1 /* This code is part of the tng binary trajectory format.
2 *
3 * Written by Magnus Lundborg
4 * Copyright (c) 2012-2017, The GROMACS development team.
5 * Check out http://www.gromacs.org for more information.
6 *
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the Revised BSD License.
10 */
11
12 /* These three definitions are required to enforce 64 bit file sizes. */
13 /* Force 64 bit variants of file access calls. */
14 #define _FILE_OFFSET_BITS 64
15 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
16 #define _LARGEFILE_SOURCE
17 /* Define for large files, on AIX-style hosts. */
18 #define _LARGE_FILES
19
20 #include "tng/tng_io.h"
21
22 #ifdef USE_STD_INTTYPES_H
23 #include <inttypes.h>
24 #endif
25
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <time.h>
30 #include <math.h>
31 #include <zlib.h>
32
33 #include "tng/md5.h"
34 #include "compression/tng_compress.h"
35 #include "tng/version.h"
36
37 #if defined( _WIN32 ) || defined( _WIN64 )
38 #ifndef fseeko
39 #define fseeko _fseeki64
40 #endif
41 #ifndef ftello
42 #ifdef __MINGW32__
43 #define ftello ftello64
44 #else
45 #define ftello _ftelli64
46 #endif
47 #endif
48 #endif
49
50 struct tng_bond {
51 /** One of the atoms of the bond */
52 int64_t from_atom_id;
53 /** The other atom of the bond */
54 int64_t to_atom_id;
55 };
56
57 struct tng_atom {
58 /** The residue containing this atom */
59 tng_residue_t residue;
60 /** A unique (per molecule) ID number of the atom */
61 int64_t id;
62 /** The atom_type (depending on the forcefield) */
63 char *atom_type;
64 /** The name of the atom */
65 char *name;
66 };
67
68 struct tng_residue {
69 /** The chain containing this residue */
70 tng_chain_t chain;
71 /** A unique (per chain) ID number of the residue */
72 int64_t id;
73 /** The name of the residue */
74 char *name;
75 /** The number of atoms in the residue */
76 int64_t n_atoms;
77 /** A list of atoms in the residue */
78 int64_t atoms_offset;
79 };
80
81 struct tng_chain {
82 /** The molecule containing this chain */
83 tng_molecule_t molecule;
84 /** A unique (per molecule) ID number of the chain */
85 int64_t id;
86 /** The name of the chain */
87 char *name;
88 /** The number of residues in the chain */
89 int64_t n_residues;
90 /** A list of residues in the chain */
91 tng_residue_t residues;
92 };
93
94 struct tng_molecule {
95 /** A unique ID number of the molecule */
96 int64_t id;
97 /** Quaternary structure of the molecule.
98 * 1 => monomeric
99 * 2 => dimeric
100 * 3 => trimeric
101 * etc */
102 int64_t quaternary_str;
103 /** The number of chains in the molecule */
104 int64_t n_chains;
105 /** The number of residues in the molecule */
106 int64_t n_residues;
107 /** The number of atoms in the molecule */
108 int64_t n_atoms;
109 /** The number of bonds in the molecule. If the bonds are not specified this
110 * value can be 0. */
111 int64_t n_bonds;
112 /** The name of the molecule */
113 char *name;
114 /** A list of chains in the molecule */
115 tng_chain_t chains;
116 /** A list of residues in the molecule */
117 tng_residue_t residues;
118 /** A list of the atoms in the molecule */
119 tng_atom_t atoms;
120 /** A list of the bonds in the molecule */
121 tng_bond_t bonds;
122 };
123
124 struct tng_gen_block {
125 /** The size of the block header in bytes */
126 int64_t header_contents_size;
127 /** The size of the block contents in bytes */
128 int64_t block_contents_size;
129 /** The ID of the block to determine its type */
130 int64_t id;
131 /** The MD5 hash of the block to verify integrity */
132 char md5_hash[TNG_MD5_HASH_LEN];
133 /** The name of the block */
134 char *name;
135 /** The library version used to write the block */
136 int64_t block_version;
137 int64_t alt_hash_type;
138 int64_t alt_hash_len;
139 char *alt_hash;
140 int64_t signature_type;
141 int64_t signature_len;
142 char *signature;
143 /** The full block header contents */
144 char *header_contents;
145 /** The full block contents */
146 char *block_contents;
147 };
148
149 struct tng_particle_mapping {
150 /** The index number of the first particle in this mapping block */
151 int64_t num_first_particle;
152 /** The number of particles list in this mapping block */
153 int64_t n_particles;
154 /** the mapping of index numbers to the real particle numbers in the
155 * trajectory. real_particle_numbers[0] is the real particle number
156 * (as it is numbered in the molecular system) of the first particle
157 * in the data blocks covered by this particle mapping block */
158 int64_t *real_particle_numbers;
159 };
160
161 struct tng_trajectory_frame_set {
162 /** The number of different particle mapping blocks present. */
163 int64_t n_mapping_blocks;
164 /** The atom mappings of this frame set */
165 struct tng_particle_mapping *mappings;
166 /** The first frame of this frame set */
167 int64_t first_frame;
168 /** The number of frames in this frame set */
169 int64_t n_frames;
170 /** The number of written frames in this frame set (used when writing one
171 * frame at a time). */
172 int64_t n_written_frames;
173 /** The number of frames not yet written to file in this frame set
174 * (used from the utility functions to finish the writing properly. */
175 int64_t n_unwritten_frames;
176
177
178 /** A list of the number of each molecule type - only used when using
179 * variable number of atoms */
180 int64_t *molecule_cnt_list;
181 /** The number of particles/atoms - only used when using variable number
182 * of atoms */
183 int64_t n_particles;
184 /** The file position of the next frame set */
185 int64_t next_frame_set_file_pos;
186 /** The file position of the previous frame set */
187 int64_t prev_frame_set_file_pos;
188 /** The file position of the frame set one long stride step ahead */
189 int64_t medium_stride_next_frame_set_file_pos;
190 /** The file position of the frame set one long stride step behind */
191 int64_t medium_stride_prev_frame_set_file_pos;
192 /** The file position of the frame set one long stride step ahead */
193 int64_t long_stride_next_frame_set_file_pos;
194 /** The file position of the frame set one long stride step behind */
195 int64_t long_stride_prev_frame_set_file_pos;
196 /** Time stamp (in seconds) of first frame in frame set */
197 double first_frame_time;
198
199 /* The data blocks in a frame set are trajectory data blocks */
200 /** The number of trajectory data blocks of particle dependent data */
201 int n_particle_data_blocks;
202 /** A list of data blocks containing particle dependent data */
203 struct tng_data *tr_particle_data;
204 /** The number of trajectory data blocks independent of particles */
205 int n_data_blocks;
206 /** A list of data blocks containing particle indepdendent data */
207 struct tng_data *tr_data;
208 };
209
210 /* FIXME: Should there be a pointer to a tng_gen_block from each data block? */
211 struct tng_data {
212 /** The block ID of the data block containing this particle data.
213 * This is used to determine the kind of data that is stored */
214 int64_t block_id;
215 /** The name of the data block. This is used to determine the kind of
216 * data that is stored */
217 char *block_name;
218 /** The type of data stored. */
219 char datatype;
220 /** A flag to indicate if this data block contains frame and/or particle dependent
221 * data */
222 char dependency;
223 /** The frame number of the first data value */
224 int64_t first_frame_with_data;
225 /** The number of frames in this frame set */
226 int64_t n_frames;
227 /** The number of values stored per frame */
228 int64_t n_values_per_frame;
229 /** The number of frames between each data point - e.g. when
230 * storing sparse data. */
231 int64_t stride_length;
232 /** ID of the CODEC used for compression 0 == no compression. */
233 int64_t codec_id;
234 /** If reading one frame at a time this is the last read frame */
235 int64_t last_retrieved_frame;
236 /** The multiplier used for getting integer values for compression */
237 double compression_multiplier;
238 /** A 1-dimensional array of values of length
239 * [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */
240 void *values;
241 /** If storing character data store it in a 3-dimensional array */
242 char ****strings;
243 };
244
245
246 struct tng_trajectory {
247 /** The path of the input trajectory file */
248 char *input_file_path;
249 /** A handle to the input file */
250 FILE *input_file;
251 /** The length of the input file */
252 int64_t input_file_len;
253 /** The path of the output trajectory file */
254 char *output_file_path;
255 /** A handle to the output file */
256 FILE *output_file;
257 /** Function to swap 32 bit values to and from the endianness of the
258 * input file */
259 tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
260 /** Function to swap 64 bit values to and from the endianness of the
261 * input file */
262 tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
263 /** Function to swap 32 bit values to and from the endianness of the
264 * input file */
265 tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
266 /** Function to swap 64 bit values to and from the endianness of the
267 * input file */
268 tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
269 /** The endianness of 32 bit values of the current computer */
270 char endianness_32;
271 /** The endianness of 64 bit values of the current computer */
272 char endianness_64;
273
274 /** The name of the program producing this trajectory */
275 char *first_program_name;
276 /** The forcefield used in the simulations */
277 char *forcefield_name;
278 /** The name of the user running the simulations */
279 char *first_user_name;
280 /** The name of the computer on which the simulations were performed */
281 char *first_computer_name;
282 /** The PGP signature of the user creating the file. */
283 char *first_pgp_signature;
284 /** The name of the program used when making last modifications to the
285 * file */
286 char *last_program_name;
287 /** The name of the user making the last modifications to the file */
288 char *last_user_name;
289 /** The name of the computer on which the last modifications were made */
290 char *last_computer_name;
291 /** The PGP signature of the user making the last modifications to the
292 * file. */
293 char *last_pgp_signature;
294 /** The time (n seconds since 1970) when the file was created */
295 int64_t time;
296 /** The exponential of the value of the distance unit used. The default
297 * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If
298 * the measurements are in Å the distance_unit_exponential = -10. */
299 int64_t distance_unit_exponential;
300
301 /** A flag indicating if the number of atoms can vary throughout the
302 * simulation, e.g. using a grand canonical ensemble */
303 char var_num_atoms_flag;
304 /** The number of frames in a frame set. It is allowed to have frame sets
305 * with fewer frames, but this will help searching for specific frames */
306 int64_t frame_set_n_frames;
307 /** The number of frame sets in a medium stride step */
308 int64_t medium_stride_length;
309 /** The number of frame sets in a long stride step */
310 int64_t long_stride_length;
311 /** The current (can change from one frame set to another) time length
312 * (in seconds) of one frame */
313 double time_per_frame;
314
315 /** The number of different kinds of molecules in the trajectory */
316 int64_t n_molecules;
317 /** A list of molecules in the trajectory */
318 tng_molecule_t molecules;
319 /** A list of the count of each molecule - if using variable number of
320 * particles this will be specified in each frame set */
321 int64_t *molecule_cnt_list;
322 /** The total number of particles/atoms. If using variable number of
323 * particles this will be specified in each frame set */
324 int64_t n_particles;
325
326 /** The pos in the src file of the first frame set */
327 int64_t first_trajectory_frame_set_input_file_pos;
328 /** The pos in the dest file of the first frame set */
329 int64_t first_trajectory_frame_set_output_file_pos;
330 /** The pos in the src file of the last frame set */
331 int64_t last_trajectory_frame_set_input_file_pos;
332 /** The pos in the dest file of the last frame set */
333 int64_t last_trajectory_frame_set_output_file_pos;
334 /** The currently active frame set */
335 struct tng_trajectory_frame_set current_trajectory_frame_set;
336 /** The pos in the src file of the current frame set */
337 int64_t current_trajectory_frame_set_input_file_pos;
338 /** The pos in the dest file of the current frame set */
339 int64_t current_trajectory_frame_set_output_file_pos;
340 /** The number of frame sets in the trajectory N.B. Not saved in file and
341 * cannot be trusted to be up-to-date */
342 int64_t n_trajectory_frame_sets;
343
344 /* These data blocks are non-trajectory data blocks */
345 /** The number of non-frame dependent particle dependent data blocks */
346 int n_particle_data_blocks;
347 /** A list of data blocks containing particle dependent data */
348 struct tng_data *non_tr_particle_data;
349
350 /** The number of frame and particle independent data blocks */
351 int n_data_blocks;
352 /** A list of frame and particle indepdendent data blocks */
353 struct tng_data *non_tr_data;
354
355 /** TNG compression algorithm for compressing positions */
356 int *compress_algo_pos;
357 /** TNG compression algorithm for compressing velocities */
358 int *compress_algo_vel;
359 /** The precision used for lossy compression */
360 double compression_precision;
361 };
362
363 #ifndef USE_WINDOWS
364 #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
365 #define USE_WINDOWS
366 #endif /* win32... */
367 #endif /* not defined USE_WINDOWS */
368
369 #ifdef USE_WINDOWS
370 #define TNG_INLINE __inline
371 #define TNG_SNPRINTF _snprintf
372 #else
373 #define TNG_INLINE inline
374 #define TNG_SNPRINTF snprintf
375 #endif
376
tng_min_size(const size_t a,const size_t b)377 static TNG_INLINE size_t tng_min_size(const size_t a, const size_t b)
378 {
379 return (a < b ? a : b);
380 }
381
tng_min_i64(const int64_t a,const int64_t b)382 static TNG_INLINE int64_t tng_min_i64(const int64_t a, const int64_t b)
383 {
384 return (a < b ? a : b);
385 }
386
tng_max_i64(const int64_t a,const int64_t b)387 static TNG_INLINE int64_t tng_max_i64(const int64_t a, const int64_t b)
388 {
389 return (a > b ? a : b);
390 }
391
392 /**
393 * @brief This function swaps the byte order of a 32 bit numerical variable
394 * to big endian.
395 * @param tng_data is a trajectory data container.
396 * @param v is a pointer to a 32 bit numerical value (float or integer).
397 * @details The function does not only work with integer, but e.g. floats need casting.
398 * If the byte order is already big endian no change is needed.
399 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
400 * byte order is not recognised.
401 */
tng_swap_byte_order_big_endian_32(const tng_trajectory_t tng_data,uint32_t * v)402 static tng_function_status tng_swap_byte_order_big_endian_32
403 (const tng_trajectory_t tng_data, uint32_t *v)
404 {
405 switch(tng_data->endianness_32)
406 {
407 case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */
408 *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
409 ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */
410 ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */
411 ((*v & 0x000000FF) << 24); /* Move last byte to first */
412
413 return(TNG_SUCCESS);
414
415 case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */
416 *v = ((*v & 0xFFFF0000) >> 16) |
417 ((*v & 0x0000FFFF) << 16);
418
419 return(TNG_SUCCESS);
420
421 case TNG_BIG_ENDIAN_32: /* Already correct */
422 return(TNG_SUCCESS);
423
424 default:
425 return(TNG_FAILURE);
426 }
427 }
428
429 /**
430 * @brief This function swaps the byte order of a 64 bit numerical variable
431 * to big endian.
432 * @param tng_data is a trajectory data container.
433 * @param v is a pointer to a 64 bit numerical value (double or integer).
434 * @details The function does not only work with integer, but e.g. floats need casting.
435 * The byte order swapping routine can convert four different byte
436 * orders to big endian.
437 * If the byte order is already big endian no change is needed.
438 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
439 * byte order is not recognised.
440 */
tng_swap_byte_order_big_endian_64(const tng_trajectory_t tng_data,uint64_t * v)441 static tng_function_status tng_swap_byte_order_big_endian_64
442 (const tng_trajectory_t tng_data, uint64_t *v)
443 {
444 switch(tng_data->endianness_64)
445 {
446 case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */
447 *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
448 ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
449 ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
450 ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
451 ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
452 ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
453 ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
454 ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */
455
456 return(TNG_SUCCESS);
457
458 case TNG_QUAD_SWAP_64: /* Byte quad swap */
459 *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) |
460 ((*v & 0x00000000FFFFFFFFLL) << 32);
461
462 return(TNG_SUCCESS);
463
464 case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */
465 *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) |
466 ((*v & 0x0000FFFF0000FFFFLL) << 16);
467
468 return(TNG_SUCCESS);
469
470 case TNG_BYTE_SWAP_64: /* Byte swap */
471 *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) |
472 ((*v & 0x00FF00FF00FF00FFLL) << 8);
473
474 return(TNG_SUCCESS);
475
476 case TNG_BIG_ENDIAN_64: /* Already correct */
477 return(TNG_SUCCESS);
478
479 default:
480 return(TNG_FAILURE);
481 }
482 }
483
484 /**
485 * @brief This function swaps the byte order of a 32 bit numerical variable
486 * to little endian.
487 * @param tng_data is a trajectory data container.
488 * @param v is a pointer to a 32 bit numerical value (float or integer).
489 * @details The function does not only work with integer, but e.g. floats need casting.
490 * If the byte order is already little endian no change is needed.
491 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
492 * byte order is not recognised.
493 */
tng_swap_byte_order_little_endian_32(const tng_trajectory_t tng_data,uint32_t * v)494 static tng_function_status tng_swap_byte_order_little_endian_32
495 (const tng_trajectory_t tng_data, uint32_t *v)
496 {
497 switch(tng_data->endianness_32)
498 {
499 case TNG_LITTLE_ENDIAN_32: /* Already correct */
500 return(TNG_SUCCESS);
501
502 case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */
503 *v = ((*v & 0xFF00FF00) >> 8) |
504 ((*v & 0x00FF00FF) << 8);
505
506 return(TNG_SUCCESS);
507
508 case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */
509 *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */
510 ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */
511 ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */
512 ((*v & 0x000000FF) << 24); /* Move last byte to first */
513
514 return(TNG_SUCCESS);
515
516 default:
517 return(TNG_FAILURE);
518 }
519 }
520
521 /**
522 * @brief This function swaps the byte order of a 64 bit numerical variable
523 * to little endian.
524 * @param tng_data is a trajectory data container.
525 * @param v is a pointer to a 64 bit numerical value (double or integer).
526 * @details The function does not only work with integer, but e.g. floats need casting.
527 * The byte order swapping routine can convert four different byte
528 * orders to little endian.
529 * If the byte order is already little endian no change is needed.
530 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current
531 * byte order is not recognised.
532 */
tng_swap_byte_order_little_endian_64(const tng_trajectory_t tng_data,uint64_t * v)533 static tng_function_status tng_swap_byte_order_little_endian_64
534 (const tng_trajectory_t tng_data, uint64_t *v)
535 {
536 switch(tng_data->endianness_64)
537 {
538 case TNG_LITTLE_ENDIAN_64: /* Already correct */
539 return(TNG_SUCCESS);
540
541 case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */
542 *v = ((*v & 0xFF000000FF000000LL) >> 24) |
543 ((*v & 0x00FF000000FF0000LL) >> 8) |
544 ((*v & 0x0000FF000000FF00LL) << 8) |
545 ((*v & 0x000000FF000000FFLL) << 24);
546
547 return(TNG_SUCCESS);
548
549 case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */
550 *v = ((*v & 0xFF00FF0000000000LL) >> 40) |
551 ((*v & 0x00FF00FF00000000LL) >> 24) |
552 ((*v & 0x00000000FF00FF00LL) << 24) |
553 ((*v & 0x0000000000FF00FFLL) << 40);
554
555 return(TNG_SUCCESS);
556
557 case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */
558 *v = ((*v & 0xFFFF000000000000LL) >> 48) |
559 ((*v & 0x0000FFFF00000000LL) >> 16) |
560 ((*v & 0x00000000FFFF0000LL) << 16) |
561 ((*v & 0x000000000000FFFFLL) << 48);
562
563 return(TNG_SUCCESS);
564
565 case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */
566 *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */
567 ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */
568 ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */
569 ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */
570 ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */
571 ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */
572 ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */
573 ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */
574
575 return(TNG_SUCCESS);
576
577 default:
578 return(TNG_FAILURE);
579 }
580 }
581
582 /**
583 * @brief Read a NULL terminated string from a file.
584 * @param tng_data is a trajectory data container
585 * @param str is a pointer to the character string that will
586 * contain the read string. *str is reallocated in the function
587 * and must be NULL or pointing at already allocated memory.
588 * @param hash_mode is an option to decide whether to use the md5 hash or not.
589 * @param md5_state is a pointer to the current md5 storage, which will be
590 * appended with str if hash_mode == TNG_USE_HASH.
591 * @param line_nr is the line number where this function was called, to be
592 * able to give more useful error messages.
593 */
tng_freadstr(const tng_trajectory_t tng_data,char ** str,const char hash_mode,md5_state_t * md5_state,const int line_nr)594 static tng_function_status tng_freadstr(const tng_trajectory_t tng_data,
595 char **str,
596 const char hash_mode,
597 md5_state_t *md5_state,
598 const int line_nr)
599 {
600 char temp[TNG_MAX_STR_LEN], *temp_alloc;
601 int c, count = 0;
602
603 do
604 {
605 c = fgetc(tng_data->input_file);
606
607 if (c == EOF)
608 {
609 /* Clear file error flag and return -1 if EOF is read.*/
610 clearerr(tng_data->input_file);
611 return TNG_FAILURE;
612 }
613 else
614 {
615 /* Cast c to char */
616 temp[count++] = (char) c;
617 }
618 } while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN));
619
620 temp_alloc = (char *)realloc(*str, count);
621 if(!temp_alloc)
622 {
623 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, line_nr);
624 free(*str);
625 *str = 0;
626 return TNG_FAILURE;
627 }
628 *str = temp_alloc;
629
630 strncpy(*str, temp, count);
631
632 if(hash_mode == TNG_USE_HASH)
633 {
634 md5_append(md5_state, (md5_byte_t *)*str, count);
635 }
636
637 return TNG_SUCCESS;
638 }
639
640 /**
641 * @brief Write a NULL terminated string to a file.
642 * @param tng_data is a trajectory data container
643 * @param str is a pointer to the character string should be written.
644 * @param hash_mode is an option to decide whether to use the md5 hash or not.
645 * @param md5_state is a pointer to the current md5 storage, which will be
646 * appended with str if hash_mode == TNG_USE_HASH.
647 * @param line_nr is the line number where this function was called, to be
648 * able to give more useful error messages.
649 */
tng_fwritestr(tng_trajectory_t tng_data,const char * str,const char hash_mode,md5_state_t * md5_state,const int line_nr)650 static TNG_INLINE tng_function_status tng_fwritestr(tng_trajectory_t tng_data,
651 const char *str,
652 const char hash_mode,
653 md5_state_t *md5_state,
654 const int line_nr)
655 {
656 size_t len;
657
658 len = tng_min_size(strlen(str) + 1, TNG_MAX_STR_LEN);
659
660 if(fwrite(str, len, 1, tng_data->output_file) != 1)
661 {
662 fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, line_nr);
663 return(TNG_CRITICAL);
664 }
665
666 if(hash_mode == TNG_USE_HASH)
667 {
668 md5_append(md5_state, (md5_byte_t *)str, len);
669 }
670
671 return(TNG_SUCCESS);
672 }
673
674 /**
675 * @brief Read a numerical value from file.
676 * The byte order will be swapped if need be.
677 * @param tng_data is a trajectory data container
678 * @param dest is a pointer to where to store the read data.
679 * @param len is the length (in bytes) of the numerical data type. Should
680 * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
681 * @param hash_mode is an option to decide whether to use the md5 hash or not.
682 * @param md5_state is a pointer to the current md5 storage, which will be
683 * appended with str if hash_mode == TNG_USE_HASH.
684 * @param line_nr is the line number where this function was called, to be
685 * able to give more useful error messages.
686 */
tng_file_input_numerical(const tng_trajectory_t tng_data,void * dest,const size_t len,const char hash_mode,md5_state_t * md5_state,const int line_nr)687 static TNG_INLINE tng_function_status tng_file_input_numerical
688 (const tng_trajectory_t tng_data,
689 void *dest,
690 const size_t len,
691 const char hash_mode,
692 md5_state_t *md5_state,
693 const int line_nr)
694 {
695 if(fread(dest, len, 1, tng_data->input_file) == 0)
696 {
697 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, line_nr);
698 return(TNG_CRITICAL);
699 }
700 if(hash_mode == TNG_USE_HASH)
701 {
702 md5_append(md5_state, (md5_byte_t *)dest, len);
703 }
704 switch(len)
705 {
706 case 8:
707 if(tng_data->input_endianness_swap_func_64 &&
708 tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)dest) != TNG_SUCCESS)
709 {
710 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
711 __FILE__, line_nr);
712 }
713 break;
714 case 4:
715 if(tng_data->input_endianness_swap_func_32 &&
716 tng_data->input_endianness_swap_func_32(tng_data, (uint32_t *)dest) != TNG_SUCCESS)
717 {
718 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
719 __FILE__, line_nr);
720 }
721 break;
722 default:
723 break;
724 }
725
726 return(TNG_SUCCESS);
727 }
728
729 /**
730 * @brief Write a numerical value to file.
731 * The byte order will be swapped if need be.
732 * @param tng_data is a trajectory data container
733 * @param src is a pointer to the data to write.
734 * @param len is the length (in bytes) of the numerical data type. Should
735 * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag.
736 * @param hash_mode is an option to decide whether to use the md5 hash or not.
737 * @param md5_state is a pointer to the current md5 storage, which will be
738 * appended with str if hash_mode == TNG_USE_HASH.
739 * @param line_nr is the line number where this function was called, to be
740 * able to give more useful error messages.
741 */
tng_file_output_numerical(const tng_trajectory_t tng_data,const void * src,const size_t len,const char hash_mode,md5_state_t * md5_state,const int line_nr)742 static TNG_INLINE tng_function_status tng_file_output_numerical
743 (const tng_trajectory_t tng_data,
744 const void *src,
745 const size_t len,
746 const char hash_mode,
747 md5_state_t *md5_state,
748 const int line_nr)
749 {
750 uint32_t temp_i32;
751 uint64_t temp_i64;
752
753 switch(len)
754 {
755 case 8:
756 temp_i64 = *((uint64_t *)src);
757 if(tng_data->output_endianness_swap_func_64 &&
758 tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS)
759 {
760 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
761 __FILE__, line_nr);
762 }
763 if(fwrite(&temp_i64, len, 1, tng_data->output_file) != 1)
764 {
765 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
766 return(TNG_CRITICAL);
767 }
768 if(hash_mode == TNG_USE_HASH)
769 {
770 md5_append(md5_state, (md5_byte_t *)&temp_i64, len);
771 }
772 break;
773 case 4:
774 temp_i32 = *((uint32_t *)src);
775 if(tng_data->output_endianness_swap_func_32 &&
776 tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS)
777 {
778 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
779 __FILE__, line_nr);
780 }
781 if(fwrite(&temp_i32, len, 1, tng_data->output_file) != 1)
782 {
783 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
784 return(TNG_CRITICAL);
785 }
786 if(hash_mode == TNG_USE_HASH)
787 {
788 md5_append(md5_state, (md5_byte_t *)&temp_i32, len);
789 }
790 break;
791 default:
792 if(fwrite(src, len, 1, tng_data->output_file) != 1)
793 {
794 fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr);
795 return(TNG_CRITICAL);
796 }
797 if(hash_mode == TNG_USE_HASH)
798 {
799 md5_append(md5_state, (md5_byte_t *)src, len);
800 }
801 break;
802 }
803
804 return(TNG_SUCCESS);
805 }
806
807 /**
808 * @brief Generate the md5 hash of a block.
809 * The hash is created based on the actual block contents.
810 * @param block is a general block container.
811 * @return TNG_SUCCESS (0) if successful.
812 */
tng_block_md5_hash_generate(const tng_gen_block_t block)813 static tng_function_status tng_block_md5_hash_generate(const tng_gen_block_t block)
814 {
815 md5_state_t md5_state;
816
817 md5_init(&md5_state);
818 md5_append(&md5_state, (md5_byte_t *)block->block_contents,
819 (int)block->block_contents_size);
820 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
821
822 return(TNG_SUCCESS);
823 }
824
825 /**
826 * @brief If there is data left in the block read that to append that to the MD5 hash.
827 * @param tng_data is a trajectory data container.
828 * @param block is the data block that is being read.
829 * @param start_pos is the file position where the block started.
830 * @param md5_state is the md5 to which the md5 of the remaining block
831 * will be appended.
832 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
833 * error has occured.
834 */
tng_md5_remaining_append(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int64_t start_pos,md5_state_t * md5_state)835 static tng_function_status tng_md5_remaining_append(const tng_trajectory_t tng_data,
836 const tng_gen_block_t block,
837 const int64_t start_pos,
838 md5_state_t *md5_state)
839 {
840 int64_t curr_file_pos;
841 char *temp_data;
842
843 curr_file_pos = ftello(tng_data->input_file);
844 if(curr_file_pos < start_pos + block->block_contents_size)
845 {
846 temp_data = (char *)malloc(start_pos + block->block_contents_size - curr_file_pos);
847 if(!temp_data)
848 {
849 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
850 __FILE__, __LINE__);
851 return(TNG_CRITICAL);
852 }
853 if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos,
854 1, tng_data->input_file) == 0)
855 {
856 fprintf(stderr, "TNG library: Cannot read remaining part of block to generate MD5 sum. %s: %d\n", __FILE__, __LINE__);
857 free(temp_data);
858 return(TNG_CRITICAL);
859 }
860 md5_append(md5_state, (md5_byte_t *)temp_data,
861 start_pos + block->block_contents_size - curr_file_pos);
862 free(temp_data);
863 }
864
865 return(TNG_SUCCESS);
866 }
867
868 /**
869 * @brief Open the input file if it is not already opened.
870 * @param tng_data is a trajectory data container.
871 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
872 * error has occured.
873 */
tng_input_file_init(const tng_trajectory_t tng_data)874 static tng_function_status tng_input_file_init(const tng_trajectory_t tng_data)
875 {
876 int64_t file_pos;
877
878 if(!tng_data->input_file)
879 {
880 if(!tng_data->input_file_path)
881 {
882 fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n",
883 __FILE__, __LINE__);
884 return(TNG_CRITICAL);
885 }
886 tng_data->input_file = fopen(tng_data->input_file_path, "rb");
887 if(!tng_data->input_file)
888 {
889 fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
890 tng_data->input_file_path, __FILE__, __LINE__);
891 return(TNG_CRITICAL);
892 }
893 }
894
895 if(!tng_data->input_file_len)
896 {
897 file_pos = ftello(tng_data->input_file);
898 fseeko(tng_data->input_file, 0, SEEK_END);
899 tng_data->input_file_len = ftello(tng_data->input_file);
900 fseeko(tng_data->input_file, file_pos, SEEK_SET);
901 }
902
903 return(TNG_SUCCESS);
904 }
905
906 /**
907 * @brief Open the output file if it is not already opened
908 * @param tng_data is a trajectory data container.
909 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
910 * error has occured.
911 */
tng_output_file_init(const tng_trajectory_t tng_data)912 static tng_function_status tng_output_file_init(const tng_trajectory_t tng_data)
913 {
914 if(!tng_data->output_file)
915 {
916 if(!tng_data->output_file_path)
917 {
918 fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n",
919 __FILE__, __LINE__);
920 return(TNG_CRITICAL);
921 }
922
923 tng_data->output_file = fopen(tng_data->output_file_path, "wb+");
924
925 if(!tng_data->output_file)
926 {
927 fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
928 tng_data->output_file_path, __FILE__, __LINE__);
929 return(TNG_CRITICAL);
930 }
931 }
932 return(TNG_SUCCESS);
933 }
934
935 /**
936 * @brief Setup a file block container.
937 * @param block_p a pointer to memory to initialise as a file block container.
938 * @details Memory is allocated during initialisation.
939 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
940 * error has occured.
941 */
tng_block_init(struct tng_gen_block ** block_p)942 static tng_function_status tng_block_init(struct tng_gen_block **block_p)
943 {
944 tng_gen_block_t block;
945
946 *block_p = (struct tng_gen_block *)malloc(sizeof(struct tng_gen_block));
947 if(!*block_p)
948 {
949 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
950 return(TNG_CRITICAL);
951 }
952
953 block = *block_p;
954
955 block->id = -1;
956 /* Reset the md5_hash */
957 memset(block->md5_hash, '\0', TNG_MD5_HASH_LEN);
958 block->name = 0;
959 block->block_version = TNG_API_VERSION;
960 block->header_contents = 0;
961 block->header_contents_size = 0;
962 block->block_contents = 0;
963 block->block_contents_size = 0;
964
965 return(TNG_SUCCESS);
966 }
967
968 /**
969 * @brief Clean up a file block container.
970 * @param block_p a pointer to the file block container to destroy.
971 * @details All allocated memory in the data structure is freed, as well as
972 * block_p itself.
973 * @return TNG_SUCCESS (0) if successful.
974 */
tng_block_destroy(struct tng_gen_block ** block_p)975 static tng_function_status tng_block_destroy(struct tng_gen_block **block_p)
976 {
977 tng_gen_block_t block = *block_p;
978
979 if(!*block_p)
980 {
981 return(TNG_SUCCESS);
982 }
983
984 /* fprintf(stderr, "TNG library: Destroying block\n"); */
985 if(block->name)
986 {
987 free(block->name);
988 block->name = 0;
989 }
990 if(block->header_contents)
991 {
992 free(block->header_contents);
993 block->header_contents = 0;
994 }
995 if(block->block_contents)
996 {
997 free(block->block_contents);
998 block->block_contents = 0;
999 }
1000
1001 free(*block_p);
1002 *block_p = 0;
1003
1004 return(TNG_SUCCESS);
1005 }
1006
1007 /**
1008 * @brief Read the header of a data block, regardless of its type
1009 * @param tng_data is a trajectory data container.
1010 * @param block is a general block container.
1011 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor
1012 * error has occured (not able to read the header size, thus skipping
1013 * the block) or TNG_CRITICAL (2) if a major error has occured.
1014 */
tng_block_header_read(const tng_trajectory_t tng_data,const tng_gen_block_t block)1015 static tng_function_status tng_block_header_read
1016 (const tng_trajectory_t tng_data, const tng_gen_block_t block)
1017 {
1018 int64_t start_pos;
1019
1020 TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer).");
1021
1022 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1023 {
1024 return(TNG_CRITICAL);
1025 }
1026
1027 start_pos = ftello(tng_data->input_file);
1028
1029 /* First read the header size to be able to read the whole header. */
1030 if(fread(&block->header_contents_size, sizeof(block->header_contents_size),
1031 1, tng_data->input_file) == 0)
1032 {
1033 fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n",
1034 __FILE__, __LINE__);
1035 return(TNG_CRITICAL);
1036 }
1037
1038 if(block->header_contents_size == 0)
1039 {
1040 block->id = -1;
1041 return(TNG_FAILURE);
1042 }
1043
1044 /* If this was the size of the general info block check the endianness */
1045 if(ftello(tng_data->input_file) < 9)
1046 {
1047 /* File is little endian */
1048 if ( *((const char*)&block->header_contents_size) != 0x00 &&
1049 *((const char*)(&block->header_contents_size) + 7) == 0x00)
1050 {
1051 /* If the architecture endianness is little endian no byte swap
1052 * will be needed. Otherwise use the functions to swap to little
1053 * endian */
1054 if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
1055 {
1056 tng_data->input_endianness_swap_func_32 = 0;
1057 }
1058 else
1059 {
1060 tng_data->input_endianness_swap_func_32 =
1061 &tng_swap_byte_order_little_endian_32;
1062 }
1063 if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
1064 {
1065 tng_data->input_endianness_swap_func_64 = 0;
1066 }
1067 else
1068 {
1069 tng_data->input_endianness_swap_func_64 =
1070 &tng_swap_byte_order_little_endian_64;
1071 }
1072 }
1073 /* File is big endian */
1074 else
1075 {
1076 /* If the architecture endianness is big endian no byte swap
1077 * will be needed. Otherwise use the functions to swap to big
1078 * endian */
1079 if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
1080 {
1081 tng_data->input_endianness_swap_func_32 = 0;
1082 }
1083 else
1084 {
1085 tng_data->input_endianness_swap_func_32 =
1086 &tng_swap_byte_order_big_endian_32;
1087 }
1088 if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
1089 {
1090 tng_data->input_endianness_swap_func_64 = 0;
1091 }
1092 else
1093 {
1094 tng_data->input_endianness_swap_func_64 =
1095 &tng_swap_byte_order_big_endian_64;
1096 }
1097 }
1098 }
1099
1100 if(tng_data->input_endianness_swap_func_64 &&
1101 tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)&block->header_contents_size) != TNG_SUCCESS)
1102 {
1103 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1104 __FILE__, __LINE__);
1105 }
1106
1107 if(tng_file_input_numerical(tng_data, &block->block_contents_size,
1108 sizeof(block->block_contents_size),
1109 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1110 {
1111 return(TNG_CRITICAL);
1112 }
1113
1114 if(tng_file_input_numerical(tng_data, &block->id,
1115 sizeof(block->id),
1116 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1117 {
1118 return(TNG_CRITICAL);
1119 }
1120
1121 if(fread(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->input_file) == 0)
1122 {
1123 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", __FILE__, __LINE__);
1124 return(TNG_CRITICAL);
1125 }
1126
1127 tng_freadstr(tng_data, &block->name, TNG_SKIP_HASH, 0, __LINE__);
1128
1129 if(tng_file_input_numerical(tng_data, &block->block_version,
1130 sizeof(block->block_version),
1131 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
1132 {
1133 return(TNG_CRITICAL);
1134 }
1135
1136 fseeko(tng_data->input_file, start_pos + block->header_contents_size, SEEK_SET);
1137
1138 return(TNG_SUCCESS);
1139 }
1140
1141 /**
1142 * @brief Write a whole block, both header and contents, regardless of it type
1143 * @param tng_data is a trajectory data container.
1144 * @param block is a general block container.
1145 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
1146 * has occurred or TNG_CRITICAL (2) if a major error has occured.
1147 */
1148 /* Disabled until it is used.*/
1149 /*
1150 // static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data,
1151 // tng_gen_block_t block)
1152 // {
1153 // if(!block->header_contents)
1154 // {
1155 // fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__);
1156 // return(TNG_FAILURE);
1157 // }
1158 // if(fwrite(block->header_contents, block->header_contents_size, 1,
1159 // tng_data->output_file) != 1)
1160 // {
1161 // fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n",
1162 // __FILE__, __LINE__);
1163 // return(TNG_CRITICAL);
1164 // }
1165 //
1166 // if(!block->block_contents)
1167 // {
1168 // fprintf(stderr, "TNG library: No block data to write. %s: %d\n",
1169 // __FILE__, __LINE__);
1170 // return(TNG_FAILURE);
1171 // }
1172 // if(fwrite(block->block_contents, block->block_contents_size, 1,
1173 // tng_data->output_file) != 1)
1174 // {
1175 // fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n",
1176 // __FILE__, __LINE__);
1177 // return(TNG_CRITICAL);
1178 // }
1179 // return(TNG_SUCCESS);
1180 // }
1181 */
1182
1183 /**
1184 * @brief Update the md5 hash of a block already written to the file
1185 * @param tng_data is a trajectory data container.
1186 * @param block is the block, of which to update the md5 hash.
1187 * @param header_start_pos is the file position where the block header starts.
1188 * @param contents_start_pos is the file position where the block contents
1189 * start.
1190 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1191 * error has occured.
1192 */
tng_md5_hash_update(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int64_t header_start_pos,const int64_t contents_start_pos)1193 static tng_function_status tng_md5_hash_update(const tng_trajectory_t tng_data,
1194 const tng_gen_block_t block,
1195 const int64_t header_start_pos,
1196 const int64_t contents_start_pos)
1197 {
1198 if(block->block_contents)
1199 {
1200 free(block->block_contents);
1201 }
1202
1203 block->block_contents = (char *)malloc(block->block_contents_size);
1204 if(!block->block_contents)
1205 {
1206 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
1207 return(TNG_CRITICAL);
1208 }
1209
1210 fseeko(tng_data->output_file, contents_start_pos, SEEK_SET);
1211 if(fread(block->block_contents, block->block_contents_size, 1,
1212 tng_data->output_file) == 0)
1213 {
1214 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
1215 return(TNG_CRITICAL);
1216 }
1217
1218 tng_block_md5_hash_generate(block);
1219
1220 fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t),
1221 SEEK_SET);
1222 fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file);
1223
1224 return(TNG_SUCCESS);
1225 }
1226
1227 /**
1228 * @brief Update the frame set pointers in the file header (general info block),
1229 * already written to disk
1230 * @param tng_data is a trajectory data container.
1231 * @param hash_mode specifies whether to update the block md5 hash when
1232 * updating the pointers.
1233 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1234 * error has occured.
1235 */
tng_header_pointers_update(const tng_trajectory_t tng_data,const char hash_mode)1236 static tng_function_status tng_header_pointers_update
1237 (const tng_trajectory_t tng_data, const char hash_mode)
1238 {
1239 tng_gen_block_t block;
1240 FILE *temp = tng_data->input_file;
1241 uint64_t output_file_pos, pos, contents_start_pos;
1242
1243 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1244 {
1245 fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1246 __FILE__, __LINE__);
1247 return(TNG_CRITICAL);
1248 }
1249
1250 tng_data->input_file = tng_data->output_file;
1251
1252 tng_block_init(&block);
1253
1254 output_file_pos = ftello(tng_data->output_file);
1255 fseeko(tng_data->output_file, 0, SEEK_SET);
1256
1257 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1258 {
1259 fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n",
1260 __FILE__, __LINE__);
1261 tng_data->input_file = temp;
1262 tng_block_destroy(&block);
1263 return(TNG_CRITICAL);
1264 }
1265
1266 contents_start_pos = ftello(tng_data->output_file);
1267
1268 fseeko(tng_data->output_file, block->block_contents_size - 5 *
1269 sizeof(int64_t), SEEK_CUR);
1270
1271 tng_data->input_file = temp;
1272
1273 pos = tng_data->first_trajectory_frame_set_output_file_pos;
1274
1275 if(tng_data->input_endianness_swap_func_64)
1276 {
1277 if(tng_data->input_endianness_swap_func_64(tng_data,
1278 &pos)
1279 != TNG_SUCCESS)
1280 {
1281 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1282 __FILE__, __LINE__);
1283 }
1284 }
1285
1286 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1287 {
1288 tng_block_destroy(&block);
1289 return(TNG_CRITICAL);
1290 }
1291
1292 pos = tng_data->last_trajectory_frame_set_output_file_pos;
1293
1294 if(tng_data->input_endianness_swap_func_64)
1295 {
1296 if(tng_data->input_endianness_swap_func_64(tng_data,
1297 &pos)
1298 != TNG_SUCCESS)
1299 {
1300 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1301 __FILE__, __LINE__);
1302 }
1303 }
1304
1305 if(fwrite(&pos,
1306 sizeof(int64_t), 1, tng_data->output_file) != 1)
1307 {
1308 tng_block_destroy(&block);
1309 return(TNG_CRITICAL);
1310 }
1311
1312 if(hash_mode == TNG_USE_HASH)
1313 {
1314 tng_md5_hash_update(tng_data, block, 0, contents_start_pos);
1315 }
1316
1317 tng_block_destroy(&block);
1318
1319 fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1320
1321 return(TNG_SUCCESS);
1322 }
1323
1324 /**
1325 * @brief Update the frame set pointers in the current frame set block, already
1326 * written to disk. It also updates the pointers of the blocks pointing to
1327 * the current frame set block.
1328 * @param tng_data is a trajectory data container.
1329 * @param hash_mode specifies whether to update the block md5 hash when
1330 * updating the pointers.
1331 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
1332 * error has occured.
1333 */
tng_frame_set_pointers_update(const tng_trajectory_t tng_data,const char hash_mode)1334 static tng_function_status tng_frame_set_pointers_update
1335 (const tng_trajectory_t tng_data, const char hash_mode)
1336 {
1337 tng_gen_block_t block;
1338 tng_trajectory_frame_set_t frame_set;
1339 FILE *temp = tng_data->input_file;
1340 uint64_t pos, output_file_pos, contents_start_pos;
1341
1342 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
1343 {
1344 fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
1345 __FILE__, __LINE__);
1346 return(TNG_CRITICAL);
1347 }
1348
1349 tng_block_init(&block);
1350 output_file_pos = ftello(tng_data->output_file);
1351
1352 tng_data->input_file = tng_data->output_file;
1353
1354 frame_set = &tng_data->current_trajectory_frame_set;
1355
1356 pos = tng_data->current_trajectory_frame_set_output_file_pos;
1357
1358 /* Update next frame set */
1359 if(frame_set->next_frame_set_file_pos > 0)
1360 {
1361 fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1362
1363 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1364 {
1365 fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1366 __FILE__, __LINE__);
1367 tng_data->input_file = temp;
1368 tng_block_destroy(&block);
1369 return(TNG_CRITICAL);
1370 }
1371
1372 contents_start_pos = ftello(tng_data->output_file);
1373
1374 fseeko(tng_data->output_file, block->block_contents_size - (5 *
1375 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1376
1377 if(tng_data->input_endianness_swap_func_64)
1378 {
1379 if(tng_data->input_endianness_swap_func_64(tng_data,
1380 &pos)
1381 != TNG_SUCCESS)
1382 {
1383 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1384 __FILE__, __LINE__);
1385 }
1386 }
1387
1388 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1389 {
1390 tng_data->input_file = temp;
1391 tng_block_destroy(&block);
1392 return(TNG_CRITICAL);
1393 }
1394
1395 if(hash_mode == TNG_USE_HASH)
1396 {
1397 tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos,
1398 contents_start_pos);
1399 }
1400 }
1401 /* Update previous frame set */
1402 if(frame_set->prev_frame_set_file_pos > 0)
1403 {
1404 fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos,
1405 SEEK_SET);
1406
1407 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1408 {
1409 fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n",
1410 __FILE__, __LINE__);
1411 tng_data->input_file = temp;
1412 tng_block_destroy(&block);
1413 return(TNG_CRITICAL);
1414 }
1415
1416 contents_start_pos = ftello(tng_data->output_file);
1417
1418 fseeko(tng_data->output_file, block->block_contents_size - (6 *
1419 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1420
1421 if(tng_data->input_endianness_swap_func_64)
1422 {
1423 if(tng_data->input_endianness_swap_func_64(tng_data,
1424 &pos)
1425 != TNG_SUCCESS)
1426 {
1427 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1428 __FILE__, __LINE__);
1429 }
1430 }
1431
1432 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1433 {
1434 tng_data->input_file = temp;
1435 tng_block_destroy(&block);
1436 return(TNG_CRITICAL);
1437 }
1438
1439 if(hash_mode == TNG_USE_HASH)
1440 {
1441 tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos,
1442 contents_start_pos);
1443 }
1444 }
1445
1446 /* Update the frame set one medium stride step after */
1447 if(frame_set->medium_stride_next_frame_set_file_pos > 0)
1448 {
1449 fseeko(tng_data->output_file,
1450 frame_set->medium_stride_next_frame_set_file_pos,
1451 SEEK_SET);
1452
1453 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1454 {
1455 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1456 __FILE__, __LINE__);
1457 tng_data->input_file = temp;
1458 tng_block_destroy(&block);
1459 return(TNG_CRITICAL);
1460 }
1461
1462 contents_start_pos = ftello(tng_data->output_file);
1463
1464 fseeko(tng_data->output_file, block->block_contents_size - (3 *
1465 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1466
1467 if(tng_data->input_endianness_swap_func_64)
1468 {
1469 if(tng_data->input_endianness_swap_func_64(tng_data,
1470 &pos)
1471 != TNG_SUCCESS)
1472 {
1473 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1474 __FILE__, __LINE__);
1475 }
1476 }
1477
1478 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1479 {
1480 tng_data->input_file = temp;
1481 tng_block_destroy(&block);
1482 return(TNG_CRITICAL);
1483 }
1484
1485 if(hash_mode == TNG_USE_HASH)
1486 {
1487 tng_md5_hash_update(tng_data, block,
1488 frame_set->medium_stride_next_frame_set_file_pos,
1489 contents_start_pos);
1490 }
1491 }
1492 /* Update the frame set one medium stride step before */
1493 if(frame_set->medium_stride_prev_frame_set_file_pos > 0)
1494 {
1495 fseeko(tng_data->output_file,
1496 frame_set->medium_stride_prev_frame_set_file_pos,
1497 SEEK_SET);
1498
1499 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1500 {
1501 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1502 __FILE__, __LINE__);
1503 tng_data->input_file = temp;
1504 tng_block_destroy(&block);
1505 return(TNG_CRITICAL);
1506 }
1507
1508 contents_start_pos = ftello(tng_data->output_file);
1509
1510 fseeko(tng_data->output_file, block->block_contents_size - (4 *
1511 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1512
1513 if(tng_data->input_endianness_swap_func_64)
1514 {
1515 if(tng_data->input_endianness_swap_func_64(tng_data,
1516 &pos)
1517 != TNG_SUCCESS)
1518 {
1519 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1520 __FILE__, __LINE__);
1521 }
1522 }
1523
1524 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1525 {
1526 tng_data->input_file = temp;
1527 tng_block_destroy(&block);
1528 return(TNG_CRITICAL);
1529 }
1530
1531 if(hash_mode == TNG_USE_HASH)
1532 {
1533 tng_md5_hash_update(tng_data, block,
1534 frame_set->medium_stride_prev_frame_set_file_pos,
1535 contents_start_pos);
1536 }
1537 }
1538
1539 /* Update the frame set one long stride step after */
1540 if(frame_set->long_stride_next_frame_set_file_pos > 0)
1541 {
1542 fseeko(tng_data->output_file,
1543 frame_set->long_stride_next_frame_set_file_pos,
1544 SEEK_SET);
1545
1546 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1547 {
1548 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1549 __FILE__, __LINE__);
1550 tng_data->input_file = temp;
1551 tng_block_destroy(&block);
1552 return(TNG_CRITICAL);
1553 }
1554
1555 contents_start_pos = ftello(tng_data->output_file);
1556
1557 fseeko(tng_data->output_file, block->block_contents_size - (1 *
1558 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1559
1560 if(tng_data->input_endianness_swap_func_64)
1561 {
1562 if(tng_data->input_endianness_swap_func_64(tng_data,
1563 &pos)
1564 != TNG_SUCCESS)
1565 {
1566 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1567 __FILE__, __LINE__);
1568 }
1569 }
1570
1571 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1572 {
1573 tng_data->input_file = temp;
1574 tng_block_destroy(&block);
1575 return(TNG_CRITICAL);
1576 }
1577
1578 if(hash_mode == TNG_USE_HASH)
1579 {
1580 tng_md5_hash_update(tng_data, block,
1581 frame_set->long_stride_next_frame_set_file_pos,
1582 contents_start_pos);
1583 }
1584 }
1585 /* Update the frame set one long stride step before */
1586 if(frame_set->long_stride_prev_frame_set_file_pos > 0)
1587 {
1588 fseeko(tng_data->output_file,
1589 frame_set->long_stride_prev_frame_set_file_pos,
1590 SEEK_SET);
1591
1592 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
1593 {
1594 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
1595 __FILE__, __LINE__);
1596 tng_data->input_file = temp;
1597 tng_block_destroy(&block);
1598 return(TNG_CRITICAL);
1599 }
1600
1601 contents_start_pos = ftello(tng_data->output_file);
1602
1603 fseeko(tng_data->output_file, block->block_contents_size - (2 *
1604 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
1605
1606 if(tng_data->input_endianness_swap_func_64)
1607 {
1608 if(tng_data->input_endianness_swap_func_64(tng_data,
1609 &pos)
1610 != TNG_SUCCESS)
1611 {
1612 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
1613 __FILE__, __LINE__);
1614 }
1615 }
1616
1617 if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1)
1618 {
1619 tng_data->input_file = temp;
1620 tng_block_destroy(&block);
1621 return(TNG_CRITICAL);
1622 }
1623
1624 if(hash_mode == TNG_USE_HASH)
1625 {
1626 tng_md5_hash_update(tng_data, block,
1627 frame_set->long_stride_prev_frame_set_file_pos,
1628 contents_start_pos);
1629 }
1630 }
1631
1632 fseeko(tng_data->output_file, output_file_pos, SEEK_SET);
1633
1634 tng_data->input_file = temp;
1635
1636 tng_block_destroy(&block);
1637
1638 return(TNG_SUCCESS);
1639 }
1640
tng_reread_frame_set_at_file_pos(const tng_trajectory_t tng_data,const int64_t pos)1641 static tng_function_status tng_reread_frame_set_at_file_pos
1642 (const tng_trajectory_t tng_data,
1643 const int64_t pos)
1644 {
1645 tng_gen_block_t block;
1646 tng_function_status stat;
1647
1648 tng_block_init(&block);
1649
1650 fseeko(tng_data->input_file, pos, SEEK_SET);
1651 if(pos > 0)
1652 {
1653 stat = tng_block_header_read(tng_data, block);
1654 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1655 {
1656 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
1657 __FILE__, __LINE__);
1658 tng_block_destroy(&block);
1659 return(TNG_FAILURE);
1660 }
1661
1662 if(tng_block_read_next(tng_data, block,
1663 TNG_SKIP_HASH) != TNG_SUCCESS)
1664 {
1665 tng_block_destroy(&block);
1666 return(TNG_CRITICAL);
1667 }
1668 }
1669
1670 tng_block_destroy(&block);
1671
1672 return(TNG_SUCCESS);
1673 }
1674
tng_file_pos_of_subsequent_trajectory_block_get(const tng_trajectory_t tng_data,int64_t * pos)1675 static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get
1676 (const tng_trajectory_t tng_data,
1677 int64_t *pos)
1678 {
1679 int64_t orig_pos, curr_frame_set_pos;
1680 tng_gen_block_t block;
1681 tng_function_status stat;
1682 tng_trajectory_frame_set_t frame_set =
1683 &tng_data->current_trajectory_frame_set;
1684
1685 orig_pos = ftello(tng_data->input_file);
1686 curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos;
1687
1688 *pos = tng_data->first_trajectory_frame_set_input_file_pos;
1689
1690 if(*pos <= 0)
1691 {
1692 return(TNG_SUCCESS);
1693 }
1694
1695 fseeko(tng_data->input_file, *pos, SEEK_SET);
1696
1697 tng_block_init(&block);
1698 /* Read block headers first to see that a frame set block is found. */
1699 stat = tng_block_header_read(tng_data, block);
1700 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1701 {
1702 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
1703 __FILE__, __LINE__);
1704 tng_block_destroy(&block);
1705 return(TNG_FAILURE);
1706 }
1707
1708 if(tng_block_read_next(tng_data, block,
1709 TNG_SKIP_HASH) != TNG_SUCCESS)
1710 {
1711 tng_block_destroy(&block);
1712 return(TNG_CRITICAL);
1713 }
1714
1715 /* Read all frame set blocks (not the blocks between them) */
1716 while(frame_set->next_frame_set_file_pos > 0)
1717 {
1718 fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET);
1719 stat = tng_block_header_read(tng_data, block);
1720 if(stat == TNG_CRITICAL)
1721 {
1722 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
1723 __FILE__, __LINE__);
1724 tng_block_destroy(&block);
1725 return(TNG_CRITICAL);
1726 }
1727 if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1728 {
1729 return(TNG_FAILURE);
1730 }
1731
1732 stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
1733 if(stat != TNG_SUCCESS)
1734 {
1735 tng_block_destroy(&block);
1736 return(stat);
1737 }
1738 /* Update *pos if this is the earliest frame set so far (after orig_pos) */
1739 if(tng_data->current_trajectory_frame_set_input_file_pos < *pos &&
1740 tng_data->current_trajectory_frame_set_input_file_pos > orig_pos)
1741 {
1742 *pos = tng_data->current_trajectory_frame_set_input_file_pos;
1743 }
1744 }
1745
1746 /* Re-read the frame set that used to be the current one */
1747 tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1748
1749 fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1750
1751 tng_block_destroy(&block);
1752
1753 return(TNG_SUCCESS);
1754 }
1755
1756 /**
1757 * @brief Migrate a whole frame set from one position in the file to another.
1758 * @param tng_data is a trajectory data container.
1759 * @param block_start_pos is the starting position in the file of the frame set.
1760 * @param block_len is the length of the whole frame set (including all data blocks etc).
1761 * @param new_pos is the new position in the file of the frame set.
1762 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1763 */
tng_frame_set_complete_migrate(const tng_trajectory_t tng_data,const int64_t block_start_pos,const int64_t block_len,const int64_t new_pos,const char hash_mode)1764 static tng_function_status tng_frame_set_complete_migrate
1765 (const tng_trajectory_t tng_data,
1766 const int64_t block_start_pos,
1767 const int64_t block_len,
1768 const int64_t new_pos,
1769 const char hash_mode)
1770 {
1771 tng_bool updated = TNG_FALSE;
1772
1773 char *contents;
1774
1775 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
1776 {
1777 return(TNG_CRITICAL);
1778 }
1779
1780 fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
1781
1782 contents = (char *)malloc(block_len);
1783 if(!contents)
1784 {
1785 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
1786 return(TNG_CRITICAL);
1787 }
1788
1789 if(fread(contents, block_len, 1, tng_data->input_file) == 0)
1790 {
1791 fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n",
1792 __FILE__, __LINE__);
1793 free(contents);
1794 return(TNG_CRITICAL);
1795 }
1796 fseeko(tng_data->output_file, new_pos, SEEK_SET);
1797
1798 if(fwrite(contents, block_len, 1, tng_data->output_file) != 1)
1799 {
1800 fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n",
1801 __FILE__, __LINE__);
1802 free(contents);
1803 return(TNG_CRITICAL);
1804 }
1805
1806 tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
1807 if(tng_data->input_file == tng_data->output_file)
1808 {
1809 tng_data->current_trajectory_frame_set_input_file_pos = new_pos;
1810 }
1811
1812 tng_frame_set_pointers_update(tng_data, hash_mode);
1813
1814 /* Update the general info block if needed */
1815 if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos)
1816 {
1817 tng_data->first_trajectory_frame_set_output_file_pos = new_pos;
1818 updated = TNG_TRUE;
1819 }
1820 if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos)
1821 {
1822 tng_data->last_trajectory_frame_set_output_file_pos = new_pos;
1823 updated = TNG_TRUE;
1824 }
1825 if(updated)
1826 {
1827 tng_header_pointers_update(tng_data, hash_mode);
1828 }
1829
1830 /* Fill the block with NULL to avoid confusion. */
1831 memset(contents, '\0', block_len);
1832 fseeko(tng_data->output_file, block_start_pos, SEEK_SET);
1833
1834 /* FIXME: casting block_len to size_t is dangerous */
1835 fwrite(contents, 1, block_len, tng_data->output_file);
1836
1837 free(contents);
1838
1839 return(TNG_SUCCESS);
1840 }
1841
tng_length_of_current_frame_set_contents_get(const tng_trajectory_t tng_data,int64_t * len)1842 static tng_function_status tng_length_of_current_frame_set_contents_get
1843 (const tng_trajectory_t tng_data,
1844 int64_t *len)
1845 {
1846 int64_t orig_pos, pos, curr_frame_set_pos;
1847 tng_gen_block_t block;
1848 tng_function_status stat;
1849
1850 orig_pos = ftello(tng_data->input_file);
1851 curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos;
1852
1853 *len = 0;
1854
1855 fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET);
1856
1857 tng_block_init(&block);
1858 /* Read block headers first to see that a frame set block is found. */
1859 stat = tng_block_header_read(tng_data, block);
1860 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
1861 {
1862 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
1863 curr_frame_set_pos, __FILE__, __LINE__);
1864 tng_block_destroy(&block);
1865 return(TNG_FAILURE);
1866 }
1867
1868 /* Read the headers of all blocks in the frame set (not the actual contents of them) */
1869 while(stat == TNG_SUCCESS)
1870 {
1871 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
1872 *len += block->header_contents_size + block->block_contents_size;
1873 pos += block->header_contents_size + block->block_contents_size;
1874 if(pos >= tng_data->input_file_len)
1875 {
1876 break;
1877 }
1878 stat = tng_block_header_read(tng_data, block);
1879 if(block->id == TNG_TRAJECTORY_FRAME_SET)
1880 {
1881 break;
1882 }
1883 }
1884
1885 /* Re-read the frame set that used to be the current one */
1886 tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos);
1887
1888 fseeko(tng_data->input_file, orig_pos, SEEK_SET);
1889
1890 tng_block_destroy(&block);
1891
1892 return(TNG_SUCCESS);
1893 }
1894
1895 /**
1896 * @brief Migrate blocks in the file to make room for new data in a block. This
1897 * is required e.g. when adding data to a block or extending strings in a
1898 * block.
1899 * @param tng_data is a trajectory data container.
1900 * @param start_pos is the position from which to start moving data, usually
1901 * the byte after the end of the block to which data was added.
1902 * @param offset is the number of bytes that were inserted.
1903 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
1904 * @details Trajectory blocks (frame sets and their related blocks) are moved
1905 * to the end of the file (if needed) in order to make room for non-trajectory
1906 * data.
1907 */
tng_migrate_data_in_file(const tng_trajectory_t tng_data,const int64_t start_pos,const int64_t offset,const char hash_mode)1908 static tng_function_status tng_migrate_data_in_file
1909 (const tng_trajectory_t tng_data,
1910 const int64_t start_pos,
1911 const int64_t offset,
1912 const char hash_mode)
1913 {
1914 int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length;
1915 tng_gen_block_t block;
1916 tng_function_status stat;
1917
1918 if(offset <= 0)
1919 {
1920 return(TNG_SUCCESS);
1921 }
1922
1923 stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos);
1924 if(stat != TNG_SUCCESS)
1925 {
1926 return(stat);
1927 }
1928
1929 tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos;
1930
1931 empty_space = traj_start_pos - (start_pos - 1);
1932
1933 if(empty_space >= offset)
1934 {
1935 return(TNG_SUCCESS);
1936 }
1937
1938 orig_file_pos = ftello(tng_data->input_file);
1939 tng_block_init(&block);
1940
1941 while(empty_space < offset)
1942 {
1943 fseeko(tng_data->input_file, traj_start_pos, SEEK_SET);
1944 stat = tng_block_header_read(tng_data, block);
1945 if(stat == TNG_CRITICAL)
1946 {
1947 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
1948 __FILE__, __LINE__);
1949 tng_block_destroy(&block);
1950 return(TNG_CRITICAL);
1951 }
1952 if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET)
1953 {
1954 tng_block_destroy(&block);
1955 return(TNG_FAILURE);
1956 }
1957 stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length);
1958 if(stat != TNG_SUCCESS)
1959 {
1960 tng_block_destroy(&block);
1961 return(stat);
1962 }
1963 stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos,
1964 frame_set_length, tng_data->input_file_len,
1965 hash_mode);
1966 if(stat != TNG_SUCCESS)
1967 {
1968 tng_block_destroy(&block);
1969 return(stat);
1970 }
1971
1972 empty_space += frame_set_length;
1973 }
1974 fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
1975 tng_block_destroy(&block);
1976
1977 return(TNG_SUCCESS);
1978 }
1979
tng_block_header_len_calculate(const tng_trajectory_t tng_data,const tng_gen_block_t block,int64_t * len)1980 static tng_function_status tng_block_header_len_calculate
1981 (const tng_trajectory_t tng_data,
1982 const tng_gen_block_t block,
1983 int64_t *len)
1984 {
1985 int name_len;
1986 (void)tng_data;
1987
1988 /* If the string is unallocated allocate memory for just string
1989 * termination */
1990 if(!block->name)
1991 {
1992 block->name = (char *)malloc(1);
1993 if(!block->name)
1994 {
1995 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
1996 __FILE__, __LINE__);
1997 return(TNG_CRITICAL);
1998 }
1999 block->name[0] = 0;
2000 }
2001
2002 name_len = tng_min_size(strlen(block->name) + 1, TNG_MAX_STR_LEN);
2003
2004 /* Calculate the size of the header to write */
2005 *len = sizeof(block->header_contents_size) +
2006 sizeof(block->block_contents_size) +
2007 sizeof(block->id) +
2008 sizeof(block->block_version) +
2009 TNG_MD5_HASH_LEN +
2010 name_len;
2011
2012 return (TNG_SUCCESS);
2013 }
2014
2015 /**
2016 * @brief Write the header of a data block, regardless of its type
2017 * @param tng_data is a trajectory data container.
2018 * @param block is a general block container.
2019 * @param hash_mode is an option to decide whether to use the md5 hash or not.
2020 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2021 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2022 * error has occured.
2023 */
tng_block_header_write(const tng_trajectory_t tng_data,const tng_gen_block_t block)2024 static tng_function_status tng_block_header_write
2025 (const tng_trajectory_t tng_data,
2026 const tng_gen_block_t block)
2027 {
2028 TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer).");
2029
2030 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2031 {
2032 fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
2033 __FILE__, __LINE__);
2034 return(TNG_CRITICAL);
2035 }
2036
2037 if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) !=
2038 TNG_SUCCESS)
2039 {
2040 fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n",
2041 __FILE__, __LINE__);
2042 return(TNG_CRITICAL);
2043 }
2044
2045 if(tng_file_output_numerical(tng_data, &block->header_contents_size,
2046 sizeof(block->header_contents_size),
2047 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2048 {
2049 return(TNG_CRITICAL);
2050 }
2051
2052 if(tng_file_output_numerical(tng_data, &block->block_contents_size,
2053 sizeof(block->block_contents_size),
2054 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2055 {
2056 return(TNG_CRITICAL);
2057 }
2058
2059 if(tng_file_output_numerical(tng_data, &block->id,
2060 sizeof(block->id),
2061 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2062 {
2063 return(TNG_CRITICAL);
2064 }
2065
2066 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2067 {
2068 fprintf(stderr, "TNG library: Could not write header data. %s: %d\n", __FILE__, __LINE__);
2069 return(TNG_CRITICAL);
2070 }
2071
2072 if(tng_fwritestr(tng_data, block->name, TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2073 {
2074 return(TNG_CRITICAL);
2075 }
2076
2077 if(tng_file_output_numerical(tng_data, &block->block_version,
2078 sizeof(block->block_version),
2079 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
2080 {
2081 return(TNG_CRITICAL);
2082 }
2083
2084 return(TNG_SUCCESS);
2085 }
2086
tng_general_info_block_len_calculate(const tng_trajectory_t tng_data,int64_t * len)2087 static tng_function_status tng_general_info_block_len_calculate
2088 (const tng_trajectory_t tng_data,
2089 int64_t *len)
2090 {
2091 size_t first_program_name_len, first_user_name_len;
2092 size_t first_computer_name_len, first_pgp_signature_len;
2093 size_t last_program_name_len, last_user_name_len;
2094 size_t last_computer_name_len, last_pgp_signature_len;
2095 size_t forcefield_name_len;
2096
2097 /* If the strings are unallocated allocate memory for just string
2098 * termination */
2099 if(!tng_data->first_program_name)
2100 {
2101 tng_data->first_program_name = (char *)malloc(1);
2102 if(!tng_data->first_program_name)
2103 {
2104 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2105 __FILE__, __LINE__);
2106 return(TNG_CRITICAL);
2107 }
2108 tng_data->first_program_name[0] = 0;
2109 }
2110 if(!tng_data->last_program_name)
2111 {
2112 tng_data->last_program_name = (char *)malloc(1);
2113 if(!tng_data->last_program_name)
2114 {
2115 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2116 __FILE__, __LINE__);
2117 return(TNG_CRITICAL);
2118 }
2119 tng_data->last_program_name[0] = 0;
2120 }
2121 if(!tng_data->first_user_name)
2122 {
2123 tng_data->first_user_name = (char *)malloc(1);
2124 if(!tng_data->first_user_name)
2125 {
2126 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2127 __FILE__, __LINE__);
2128 return(TNG_CRITICAL);
2129 }
2130 tng_data->first_user_name[0] = 0;
2131 }
2132 if(!tng_data->last_user_name)
2133 {
2134 tng_data->last_user_name = (char *)malloc(1);
2135 if(!tng_data->last_user_name)
2136 {
2137 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2138 __FILE__, __LINE__);
2139 return(TNG_CRITICAL);
2140 }
2141 tng_data->last_user_name[0] = 0;
2142 }
2143 if(!tng_data->first_computer_name)
2144 {
2145 tng_data->first_computer_name = (char *)malloc(1);
2146 if(!tng_data->first_computer_name)
2147 {
2148 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2149 __FILE__, __LINE__);
2150 return(TNG_CRITICAL);
2151 }
2152 tng_data->first_computer_name[0] = 0;
2153 }
2154 if(!tng_data->last_computer_name)
2155 {
2156 tng_data->last_computer_name = (char *)malloc(1);
2157 if(!tng_data->last_computer_name)
2158 {
2159 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2160 __FILE__, __LINE__);
2161 return(TNG_CRITICAL);
2162 }
2163 tng_data->last_computer_name[0] = 0;
2164 }
2165 if(!tng_data->first_pgp_signature)
2166 {
2167 tng_data->first_pgp_signature = (char *)malloc(1);
2168 if(!tng_data->first_pgp_signature)
2169 {
2170 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2171 __FILE__, __LINE__);
2172 return(TNG_CRITICAL);
2173 }
2174 tng_data->first_pgp_signature[0] = 0;
2175 }
2176 if(!tng_data->last_pgp_signature)
2177 {
2178 tng_data->last_pgp_signature = (char *)malloc(1);
2179 if(!tng_data->last_pgp_signature)
2180 {
2181 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2182 __FILE__, __LINE__);
2183 return(TNG_CRITICAL);
2184 }
2185 tng_data->last_pgp_signature[0] = 0;
2186 }
2187 if(!tng_data->forcefield_name)
2188 {
2189 tng_data->forcefield_name = (char *)malloc(1);
2190 if(!tng_data->forcefield_name)
2191 {
2192 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2193 __FILE__, __LINE__);
2194 return(TNG_CRITICAL);
2195 }
2196 tng_data->forcefield_name[0] = 0;
2197 }
2198
2199 first_program_name_len = tng_min_size(strlen(tng_data->first_program_name) + 1,
2200 TNG_MAX_STR_LEN);
2201 last_program_name_len = tng_min_size(strlen(tng_data->last_program_name) + 1,
2202 TNG_MAX_STR_LEN);
2203 first_user_name_len = tng_min_size(strlen(tng_data->first_user_name) + 1,
2204 TNG_MAX_STR_LEN);
2205 last_user_name_len = tng_min_size(strlen(tng_data->last_user_name) + 1,
2206 TNG_MAX_STR_LEN);
2207 first_computer_name_len = tng_min_size(strlen(tng_data->first_computer_name) + 1,
2208 TNG_MAX_STR_LEN);
2209 last_computer_name_len = tng_min_size(strlen(tng_data->last_computer_name) + 1,
2210 TNG_MAX_STR_LEN);
2211 first_pgp_signature_len = tng_min_size(strlen(tng_data->first_pgp_signature) + 1,
2212 TNG_MAX_STR_LEN);
2213 last_pgp_signature_len = tng_min_size(strlen(tng_data->last_pgp_signature) + 1,
2214 TNG_MAX_STR_LEN);
2215 forcefield_name_len = tng_min_size(strlen(tng_data->forcefield_name) + 1,
2216 TNG_MAX_STR_LEN);
2217
2218 *len = sizeof(tng_data->time) +
2219 sizeof(tng_data->var_num_atoms_flag) +
2220 sizeof(tng_data->frame_set_n_frames) +
2221 sizeof(tng_data->first_trajectory_frame_set_input_file_pos) +
2222 sizeof(tng_data->last_trajectory_frame_set_input_file_pos) +
2223 sizeof(tng_data->medium_stride_length) +
2224 sizeof(tng_data->long_stride_length) +
2225 sizeof(tng_data->distance_unit_exponential) +
2226 first_program_name_len +
2227 last_program_name_len +
2228 first_user_name_len +
2229 last_user_name_len +
2230 first_computer_name_len +
2231 last_computer_name_len +
2232 first_pgp_signature_len +
2233 last_pgp_signature_len +
2234 forcefield_name_len;
2235
2236 return(TNG_SUCCESS);
2237 }
2238
2239 /**
2240 * @brief Read a general info block. This is the first block of a TNG file.
2241 * Populate the fields in tng_data.
2242 * @param tng_data is a trajectory data container.
2243 * @param block is a general block container.
2244 * @param hash_mode is an option to decide whether to use the md5 hash or not.
2245 * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2246 * compared to the md5 hash of the read contents to ensure valid data.
2247 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2248 * error has occured.
2249 */
tng_general_info_block_read(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)2250 static tng_function_status tng_general_info_block_read
2251 (const tng_trajectory_t tng_data,
2252 const tng_gen_block_t block,
2253 const char hash_mode)
2254 {
2255 int64_t start_pos;
2256 char hash[TNG_MD5_HASH_LEN];
2257 md5_state_t md5_state;
2258
2259 TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)");
2260
2261 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2262 {
2263 return(TNG_CRITICAL);
2264 }
2265
2266 start_pos = ftello(tng_data->input_file);
2267
2268 if(hash_mode == TNG_USE_HASH)
2269 {
2270 md5_init(&md5_state);
2271 }
2272
2273 tng_freadstr(tng_data, &tng_data->first_program_name, hash_mode, &md5_state, __LINE__);
2274
2275 tng_freadstr(tng_data, &tng_data->last_program_name, hash_mode, &md5_state, __LINE__);
2276
2277 tng_freadstr(tng_data, &tng_data->first_user_name, hash_mode, &md5_state, __LINE__);
2278
2279 tng_freadstr(tng_data, &tng_data->last_user_name, hash_mode, &md5_state, __LINE__);
2280
2281 tng_freadstr(tng_data, &tng_data->first_computer_name, hash_mode, &md5_state, __LINE__);
2282
2283 tng_freadstr(tng_data, &tng_data->last_computer_name, hash_mode, &md5_state, __LINE__);
2284
2285 tng_freadstr(tng_data, &tng_data->first_pgp_signature, hash_mode, &md5_state, __LINE__);
2286
2287 tng_freadstr(tng_data, &tng_data->last_pgp_signature, hash_mode, &md5_state, __LINE__);
2288
2289 tng_freadstr(tng_data, &tng_data->forcefield_name, hash_mode, &md5_state, __LINE__);
2290
2291 if(tng_file_input_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2292 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2293 {
2294 return(TNG_CRITICAL);
2295 }
2296
2297
2298 if(tng_file_input_numerical(tng_data, &tng_data->var_num_atoms_flag,
2299 sizeof(tng_data->var_num_atoms_flag),
2300 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2301 {
2302 return(TNG_CRITICAL);
2303 }
2304
2305 if(tng_file_input_numerical(tng_data, &tng_data->frame_set_n_frames,
2306 sizeof(tng_data->frame_set_n_frames),
2307 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2308 {
2309 return(TNG_CRITICAL);
2310 }
2311
2312 if(tng_file_input_numerical(tng_data,
2313 &tng_data->first_trajectory_frame_set_input_file_pos,
2314 sizeof(tng_data->first_trajectory_frame_set_input_file_pos),
2315 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2316 {
2317 return(TNG_CRITICAL);
2318 }
2319
2320 tng_data->current_trajectory_frame_set.next_frame_set_file_pos =
2321 tng_data->first_trajectory_frame_set_input_file_pos;
2322
2323 if(tng_file_input_numerical(tng_data,
2324 &tng_data->last_trajectory_frame_set_input_file_pos,
2325 sizeof(tng_data->last_trajectory_frame_set_input_file_pos),
2326 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2327 {
2328 return(TNG_CRITICAL);
2329 }
2330
2331 if(tng_file_input_numerical(tng_data,
2332 &tng_data->medium_stride_length,
2333 sizeof(tng_data->medium_stride_length),
2334 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2335 {
2336 return(TNG_CRITICAL);
2337 }
2338
2339 if(tng_file_input_numerical(tng_data,
2340 &tng_data->long_stride_length,
2341 sizeof(tng_data->long_stride_length),
2342 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2343 {
2344 return(TNG_CRITICAL);
2345 }
2346
2347 if(block->block_version >= 3)
2348 {
2349 if(tng_file_input_numerical(tng_data,
2350 &tng_data->distance_unit_exponential,
2351 sizeof(tng_data->distance_unit_exponential),
2352 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2353 {
2354 return(TNG_CRITICAL);
2355 }
2356 }
2357
2358 if(hash_mode == TNG_USE_HASH)
2359 {
2360 /* If there is data left in the block that the current version of the library
2361 * cannot interpret still read that to generate the MD5 hash. */
2362 tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
2363
2364 md5_finish(&md5_state, (md5_byte_t *)hash);
2365 if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
2366 {
2367 if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
2368 {
2369 fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. "
2370 "%s: %d\n", __FILE__, __LINE__);
2371 }
2372 }
2373 }
2374 else
2375 {
2376 /* Seek to the end of the block */
2377 fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
2378 }
2379
2380 return(TNG_SUCCESS);
2381 }
2382
2383 /**
2384 * @brief Write a general info block. This is the first block of a TNG file.
2385 * @param tng_data is a trajectory data container.
2386 * @param hash_mode is an option to decide whether to use the md5 hash or not.
2387 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
2388 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2389 * error has occured.
2390 */
tng_general_info_block_write(const tng_trajectory_t tng_data,const char hash_mode)2391 static tng_function_status tng_general_info_block_write
2392 (const tng_trajectory_t tng_data,
2393 const char hash_mode)
2394 {
2395 int64_t header_file_pos, curr_file_pos;
2396 size_t name_len;
2397 tng_gen_block_t block;
2398 md5_state_t md5_state;
2399
2400 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
2401 {
2402 return(TNG_CRITICAL);
2403 }
2404
2405 fseeko(tng_data->output_file, 0, SEEK_SET);
2406
2407 tng_block_init(&block);
2408
2409 name_len = strlen("GENERAL INFO");
2410
2411 block->name = (char *)malloc(name_len + 1);
2412 if(!block->name)
2413 {
2414 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2415 tng_block_destroy(&block);
2416 return(TNG_CRITICAL);
2417 }
2418
2419 strcpy(block->name, "GENERAL INFO");
2420 block->id = TNG_GENERAL_INFO;
2421
2422 if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) !=
2423 TNG_SUCCESS)
2424 {
2425 fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n",
2426 __FILE__, __LINE__);
2427 tng_block_destroy(&block);
2428 return(TNG_CRITICAL);
2429 }
2430
2431 header_file_pos = 0;
2432
2433 if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
2434 {
2435 fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
2436 tng_data->output_file_path, __FILE__, __LINE__);
2437 tng_block_destroy(&block);
2438 return(TNG_CRITICAL);
2439 }
2440
2441 if(hash_mode == TNG_USE_HASH)
2442 {
2443 md5_init(&md5_state);
2444 }
2445
2446 if(tng_fwritestr(tng_data, tng_data->first_program_name,
2447 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2448 {
2449 return(TNG_CRITICAL);
2450 }
2451
2452 if(tng_fwritestr(tng_data, tng_data->last_program_name,
2453 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2454 {
2455 return(TNG_CRITICAL);
2456 }
2457
2458 if(tng_fwritestr(tng_data, tng_data->first_user_name,
2459 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2460 {
2461 return(TNG_CRITICAL);
2462 }
2463
2464 if(tng_fwritestr(tng_data, tng_data->last_user_name,
2465 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2466 {
2467 return(TNG_CRITICAL);
2468 }
2469
2470 if(tng_fwritestr(tng_data, tng_data->first_computer_name,
2471 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2472 {
2473 return(TNG_CRITICAL);
2474 }
2475
2476 if(tng_fwritestr(tng_data, tng_data->last_computer_name,
2477 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2478 {
2479 return(TNG_CRITICAL);
2480 }
2481
2482 if(tng_fwritestr(tng_data, tng_data->first_pgp_signature,
2483 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2484 {
2485 return(TNG_CRITICAL);
2486 }
2487
2488 if(tng_fwritestr(tng_data, tng_data->last_pgp_signature,
2489 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2490 {
2491 return(TNG_CRITICAL);
2492 }
2493
2494 if(tng_fwritestr(tng_data, tng_data->forcefield_name,
2495 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2496 {
2497 return(TNG_CRITICAL);
2498 }
2499
2500
2501 if(tng_file_output_numerical(tng_data, &tng_data->time, sizeof(tng_data->time),
2502 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2503 {
2504 return(TNG_CRITICAL);
2505 }
2506
2507 if(tng_file_output_numerical(tng_data, &tng_data->var_num_atoms_flag,
2508 sizeof(tng_data->var_num_atoms_flag),
2509 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2510 {
2511 return(TNG_CRITICAL);
2512 }
2513
2514 if(tng_file_output_numerical(tng_data, &tng_data->frame_set_n_frames,
2515 sizeof(tng_data->frame_set_n_frames),
2516 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2517 {
2518 return(TNG_CRITICAL);
2519 }
2520
2521 if(tng_file_output_numerical(tng_data, &tng_data->first_trajectory_frame_set_output_file_pos,
2522 sizeof(tng_data->first_trajectory_frame_set_output_file_pos),
2523 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2524 {
2525 return(TNG_CRITICAL);
2526 }
2527
2528 if(tng_file_output_numerical(tng_data, &tng_data->last_trajectory_frame_set_output_file_pos,
2529 sizeof(tng_data->last_trajectory_frame_set_output_file_pos),
2530 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2531 {
2532 return(TNG_CRITICAL);
2533 }
2534
2535 if(tng_file_output_numerical(tng_data, &tng_data->medium_stride_length,
2536 sizeof(tng_data->medium_stride_length),
2537 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2538 {
2539 return(TNG_CRITICAL);
2540 }
2541
2542 if(tng_file_output_numerical(tng_data, &tng_data->long_stride_length,
2543 sizeof(tng_data->long_stride_length),
2544 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2545 {
2546 return(TNG_CRITICAL);
2547 }
2548
2549 if(tng_file_output_numerical(tng_data, &tng_data->distance_unit_exponential,
2550 sizeof(tng_data->distance_unit_exponential),
2551 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2552 {
2553 return(TNG_CRITICAL);
2554 }
2555 if(hash_mode == TNG_USE_HASH)
2556 {
2557 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
2558 curr_file_pos = ftello(tng_data->output_file);
2559 fseeko(tng_data->output_file, header_file_pos +
2560 3 * sizeof(int64_t), SEEK_SET);
2561 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
2562 {
2563 fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
2564 __LINE__);
2565 return(TNG_CRITICAL);
2566 }
2567 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
2568 }
2569
2570 tng_block_destroy(&block);
2571
2572 return(TNG_SUCCESS);
2573 }
2574
2575 /**
2576 * @brief Read the chain data of a molecules block.
2577 * @param tng_data is a trajectory data container.
2578 * @param chain is the chain data container.
2579 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2580 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2581 * if hash_mode == TNG_USE_HASH.
2582 * @return TNG_SUCCESS(0) is successful.
2583 */
tng_chain_data_read(const tng_trajectory_t tng_data,const tng_chain_t chain,const char hash_mode,md5_state_t * md5_state)2584 static tng_function_status tng_chain_data_read(const tng_trajectory_t tng_data,
2585 const tng_chain_t chain,
2586 const char hash_mode,
2587 md5_state_t *md5_state)
2588 {
2589 if(tng_file_input_numerical(tng_data, &chain->id,
2590 sizeof(chain->id),
2591 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2592 {
2593 return(TNG_CRITICAL);
2594 }
2595
2596 tng_freadstr(tng_data, &chain->name, hash_mode, md5_state, __LINE__);
2597
2598 if(tng_file_input_numerical(tng_data, &chain->n_residues,
2599 sizeof(chain->n_residues),
2600 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2601 {
2602 return(TNG_CRITICAL);
2603 }
2604
2605 return(TNG_SUCCESS);
2606 }
2607
2608 /**
2609 * @brief Write the chain data of a molecules block.
2610 * @param tng_data is a trajectory data container.
2611 * @param chain is the chain data container.
2612 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2613 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2614 * if hash_mode == TNG_USE_HASH.
2615 * @return TNG_SUCCESS(0) is successful.
2616 */
tng_chain_data_write(const tng_trajectory_t tng_data,const tng_chain_t chain,const char hash_mode,md5_state_t * md5_state)2617 static tng_function_status tng_chain_data_write(const tng_trajectory_t tng_data,
2618 const tng_chain_t chain,
2619 const char hash_mode,
2620 md5_state_t *md5_state)
2621 {
2622 if(tng_file_output_numerical(tng_data, &chain->id,
2623 sizeof(chain->id),
2624 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2625 {
2626 return(TNG_CRITICAL);
2627 }
2628
2629 if(tng_fwritestr(tng_data, chain->name, hash_mode,
2630 md5_state, __LINE__) == TNG_CRITICAL)
2631 {
2632 return(TNG_CRITICAL);
2633 }
2634
2635 if(tng_file_output_numerical(tng_data, &chain->n_residues,
2636 sizeof(chain->n_residues),
2637 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2638 {
2639 return(TNG_CRITICAL);
2640 }
2641
2642 return(TNG_SUCCESS);
2643 }
2644
2645 /**
2646 * @brief Read the residue data of a molecules block.
2647 * @param tng_data is a trajectory data container.
2648 * @param residue is the residue data container.
2649 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2650 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2651 * if hash_mode == TNG_USE_HASH.
2652 * @return TNG_SUCCESS(0) is successful.
2653 */
tng_residue_data_read(const tng_trajectory_t tng_data,const tng_residue_t residue,const char hash_mode,md5_state_t * md5_state)2654 static tng_function_status tng_residue_data_read(const tng_trajectory_t tng_data,
2655 const tng_residue_t residue,
2656 const char hash_mode,
2657 md5_state_t *md5_state)
2658 {
2659 if(tng_file_input_numerical(tng_data, &residue->id,
2660 sizeof(residue->id),
2661 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2662 {
2663 return(TNG_CRITICAL);
2664 }
2665
2666 tng_freadstr(tng_data, &residue->name, hash_mode, md5_state, __LINE__);
2667
2668 if(tng_file_input_numerical(tng_data, &residue->n_atoms,
2669 sizeof(residue->n_atoms),
2670 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2671 {
2672 return(TNG_CRITICAL);
2673 }
2674
2675 return(TNG_SUCCESS);
2676 }
2677
2678 /**
2679 * @brief Write the residue data of a molecules block.
2680 * @param tng_data is a trajectory data container.
2681 * @param residue is the residue data container.
2682 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2683 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2684 * if hash_mode == TNG_USE_HASH.
2685 * @return TNG_SUCCESS(0) is successful.
2686 */
tng_residue_data_write(const tng_trajectory_t tng_data,const tng_residue_t residue,const char hash_mode,md5_state_t * md5_state)2687 static tng_function_status tng_residue_data_write(const tng_trajectory_t tng_data,
2688 const tng_residue_t residue,
2689 const char hash_mode,
2690 md5_state_t *md5_state)
2691 {
2692 if(tng_file_output_numerical(tng_data, &residue->id,
2693 sizeof(residue->id),
2694 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2695 {
2696 return(TNG_CRITICAL);
2697 }
2698
2699 if(tng_fwritestr(tng_data, residue->name, hash_mode,
2700 md5_state, __LINE__) == TNG_CRITICAL)
2701 {
2702 return(TNG_CRITICAL);
2703 }
2704
2705 if(tng_file_output_numerical(tng_data, &residue->n_atoms,
2706 sizeof(residue->n_atoms),
2707 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2708 {
2709 return(TNG_CRITICAL);
2710 }
2711
2712 return(TNG_SUCCESS);
2713 }
2714
2715 /**
2716 * @brief Read the atom data of a molecules block.
2717 * @param tng_data is a trajectory data container.
2718 * @param atom is the atom data container.
2719 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2720 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2721 * if hash_mode == TNG_USE_HASH.
2722 * @return TNG_SUCCESS(0) is successful.
2723 */
tng_atom_data_read(const tng_trajectory_t tng_data,const tng_atom_t atom,const char hash_mode,md5_state_t * md5_state)2724 static tng_function_status tng_atom_data_read(const tng_trajectory_t tng_data,
2725 const tng_atom_t atom,
2726 const char hash_mode,
2727 md5_state_t *md5_state)
2728 {
2729 if(tng_file_input_numerical(tng_data, &atom->id,
2730 sizeof(atom->id),
2731 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2732 {
2733 return(TNG_CRITICAL);
2734 }
2735
2736 tng_freadstr(tng_data, &atom->name, hash_mode, md5_state, __LINE__);
2737
2738 tng_freadstr(tng_data, &atom->atom_type, hash_mode, md5_state, __LINE__);
2739
2740 return(TNG_SUCCESS);
2741 }
2742
2743 /**
2744 * @brief Write the atom data of a molecules block.
2745 * @param tng_data is a trajectory data container.
2746 * @param atom is the atom data container.
2747 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
2748 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
2749 * if hash_mode == TNG_USE_HASH.
2750 * @return TNG_SUCCESS(0) is successful.
2751 */
tng_atom_data_write(const tng_trajectory_t tng_data,const tng_atom_t atom,const char hash_mode,md5_state_t * md5_state)2752 static tng_function_status tng_atom_data_write(const tng_trajectory_t tng_data,
2753 const tng_atom_t atom,
2754 const char hash_mode,
2755 md5_state_t *md5_state)
2756 {
2757 if(tng_file_output_numerical(tng_data, &atom->id,
2758 sizeof(atom->id),
2759 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
2760 {
2761 return(TNG_CRITICAL);
2762 }
2763
2764 if(tng_fwritestr(tng_data, atom->name, hash_mode,
2765 md5_state, __LINE__) == TNG_CRITICAL)
2766 {
2767 return(TNG_CRITICAL);
2768 }
2769
2770 if(tng_fwritestr(tng_data, atom->atom_type, hash_mode,
2771 md5_state, __LINE__) == TNG_CRITICAL)
2772 {
2773 return(TNG_CRITICAL);
2774 }
2775
2776 return(TNG_SUCCESS);
2777 }
2778
tng_molecules_block_len_calculate(const tng_trajectory_t tng_data,int64_t * len)2779 static tng_function_status tng_molecules_block_len_calculate
2780 (const tng_trajectory_t tng_data,
2781 int64_t *len)
2782 {
2783 int64_t i, j;
2784 tng_molecule_t molecule;
2785 tng_chain_t chain;
2786 tng_residue_t residue;
2787 tng_atom_t atom;
2788 tng_bond_t bond;
2789
2790 *len = 0;
2791
2792 for(i = 0; i < tng_data->n_molecules; i++)
2793 {
2794 molecule = &tng_data->molecules[i];
2795 if(!molecule->name)
2796 {
2797 molecule->name = (char *)malloc(1);
2798 if(!molecule->name)
2799 {
2800 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2801 __FILE__, __LINE__);
2802 return(TNG_CRITICAL);
2803 }
2804 molecule->name[0] = 0;
2805 }
2806 *len += tng_min_size(strlen(molecule->name) + 1, TNG_MAX_STR_LEN);
2807
2808 chain = molecule->chains;
2809 for(j = 0; j < molecule->n_chains; j++)
2810 {
2811 *len += sizeof(chain->id);
2812
2813 if(!chain->name)
2814 {
2815 chain->name = (char *)malloc(1);
2816 if(!chain->name)
2817 {
2818 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2819 __FILE__, __LINE__);
2820 return(TNG_CRITICAL);
2821 }
2822 chain->name[0] = 0;
2823 }
2824 *len += tng_min_size(strlen(chain->name) + 1, TNG_MAX_STR_LEN);
2825
2826 *len += sizeof(chain->n_residues);
2827
2828 chain++;
2829 }
2830
2831 residue = molecule->residues;
2832 for(j = 0; j < molecule->n_residues; j++)
2833 {
2834 *len += sizeof(residue->id);
2835
2836 if(!residue->name)
2837 {
2838 residue->name = (char *)malloc(1);
2839 if(!residue->name)
2840 {
2841 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2842 __FILE__, __LINE__);
2843 return(TNG_CRITICAL);
2844 }
2845 residue->name[0] = 0;
2846 }
2847 *len += tng_min_size(strlen(residue->name) + 1, TNG_MAX_STR_LEN);
2848
2849 *len += sizeof(residue->n_atoms);
2850
2851 residue++;
2852 }
2853
2854 atom = molecule->atoms;
2855 for(j = 0; j < molecule->n_atoms; j++)
2856 {
2857 *len += sizeof(atom->id);
2858 if(!atom->name)
2859 {
2860 atom->name = (char *)malloc(1);
2861 if(!atom->name)
2862 {
2863 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2864 __FILE__, __LINE__);
2865 return(TNG_CRITICAL);
2866 }
2867 atom->name[0] = 0;
2868 }
2869 *len += tng_min_size(strlen(atom->name) + 1, TNG_MAX_STR_LEN);
2870
2871 if(!atom->atom_type)
2872 {
2873 atom->atom_type = (char *)malloc(1);
2874 if(!atom->atom_type)
2875 {
2876 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
2877 __FILE__, __LINE__);
2878 return(TNG_CRITICAL);
2879 }
2880 atom->atom_type[0] = 0;
2881 }
2882 *len += tng_min_size(strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN);
2883
2884 atom++;
2885 }
2886
2887 for(j = 0; j < molecule->n_bonds; j++)
2888 {
2889 *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id);
2890 }
2891 }
2892 *len += sizeof(tng_data->n_molecules) +
2893 (sizeof(molecule->id) +
2894 sizeof(molecule->quaternary_str) +
2895 sizeof(molecule->n_chains) +
2896 sizeof(molecule->n_residues) +
2897 sizeof(molecule->n_atoms) +
2898 sizeof(molecule->n_bonds)) *
2899 tng_data->n_molecules;
2900
2901 if(!tng_data->var_num_atoms_flag)
2902 {
2903 *len += tng_data->n_molecules * sizeof(int64_t);
2904 }
2905
2906 return(TNG_SUCCESS);
2907 }
2908
2909 /**
2910 * @brief Read a molecules block. Contains chain, residue and atom data
2911 * @param tng_data is a trajectory data container.
2912 * @param block is a general block container.
2913 * @param hash_mode is an option to decide whether to use the md5 hash or not.
2914 * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
2915 * compared to the md5 hash of the read contents to ensure valid data.
2916 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
2917 * error has occured.
2918 */
tng_molecules_block_read(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)2919 static tng_function_status tng_molecules_block_read
2920 (const tng_trajectory_t tng_data,
2921 const tng_gen_block_t block,
2922 const char hash_mode)
2923 {
2924 int64_t start_pos, i, j, k, l;
2925 tng_molecule_t molecule;
2926 tng_chain_t chain;
2927 tng_residue_t residue;
2928 tng_atom_t atom;
2929 tng_bond_t bond;
2930 char hash[TNG_MD5_HASH_LEN];
2931 md5_state_t md5_state;
2932
2933 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
2934 {
2935 return(TNG_CRITICAL);
2936 }
2937
2938 start_pos = ftello(tng_data->input_file);
2939
2940 /* FIXME: Does not check if the size of the contents matches the expected
2941 * size or if the contents can be read. */
2942
2943 if(tng_data->molecules)
2944 {
2945 for(i=0; i<tng_data->n_molecules; i++)
2946 {
2947 tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
2948 }
2949 free(tng_data->molecules);
2950 tng_data->molecules = 0;
2951 tng_data->n_molecules = 0;
2952 }
2953
2954 if(hash_mode == TNG_USE_HASH)
2955 {
2956 md5_init(&md5_state);
2957 }
2958
2959 if(tng_file_input_numerical(tng_data, &tng_data->n_molecules,
2960 sizeof(tng_data->n_molecules),
2961 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
2962 {
2963 return(TNG_CRITICAL);
2964 }
2965
2966 if(tng_data->molecules)
2967 {
2968 free(tng_data->molecules);
2969 }
2970
2971 tng_data->n_particles = 0;
2972
2973 tng_data->molecules = (struct tng_molecule *)malloc(tng_data->n_molecules *
2974 sizeof(struct tng_molecule));
2975 if(!tng_data->molecules)
2976 {
2977 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2978 return(TNG_CRITICAL);
2979 }
2980
2981 if(!tng_data->var_num_atoms_flag)
2982 {
2983 if(tng_data->molecule_cnt_list)
2984 {
2985 free(tng_data->molecule_cnt_list);
2986 }
2987 tng_data->molecule_cnt_list = (int64_t *)malloc(sizeof(int64_t) *
2988 tng_data->n_molecules);
2989 if(!tng_data->molecule_cnt_list)
2990 {
2991 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
2992 return(TNG_CRITICAL);
2993 }
2994 }
2995
2996 /* Read each molecule from file */
2997 for(i=0; i < tng_data->n_molecules; i++)
2998 {
2999 molecule = &tng_data->molecules[i];
3000
3001 molecule->name = 0;
3002
3003 if(tng_file_input_numerical(tng_data, &molecule->id,
3004 sizeof(molecule->id),
3005 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3006 {
3007 return(TNG_CRITICAL);
3008 }
3009
3010 /* fprintf(stderr, "TNG library: Read id: %" PRId64 " offset: %d\n", molecule->id, offset);*/
3011 tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__);
3012
3013 if(tng_file_input_numerical(tng_data, &molecule->quaternary_str,
3014 sizeof(molecule->quaternary_str),
3015 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3016 {
3017 return(TNG_CRITICAL);
3018 }
3019
3020 if(!tng_data->var_num_atoms_flag)
3021 {
3022 if(tng_file_input_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3023 sizeof(int64_t),
3024 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3025 {
3026 return(TNG_CRITICAL);
3027 }
3028 }
3029
3030 if(tng_file_input_numerical(tng_data, &molecule->n_chains,
3031 sizeof(molecule->n_chains),
3032 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3033 {
3034 return(TNG_CRITICAL);
3035 }
3036
3037 if(tng_file_input_numerical(tng_data, &molecule->n_residues,
3038 sizeof(molecule->n_residues),
3039 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3040 {
3041 return(TNG_CRITICAL);
3042 }
3043
3044 if(tng_file_input_numerical(tng_data, &molecule->n_atoms,
3045 sizeof(molecule->n_atoms),
3046 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3047 {
3048 return(TNG_CRITICAL);
3049 }
3050
3051 tng_data->n_particles += molecule->n_atoms *
3052 tng_data->molecule_cnt_list[i];
3053
3054 if(molecule->n_chains > 0)
3055 {
3056 molecule->chains = (struct tng_chain *)malloc(molecule->n_chains *
3057 sizeof(struct tng_chain));
3058 if(!molecule->chains)
3059 {
3060 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3061 __FILE__, __LINE__);
3062 return(TNG_CRITICAL);
3063 }
3064
3065 chain = molecule->chains;
3066 }
3067 else
3068 {
3069 chain = 0;
3070 }
3071
3072 if(molecule->n_residues > 0)
3073 {
3074 molecule->residues = (struct tng_residue *)malloc(molecule->n_residues *
3075 sizeof(struct tng_residue));
3076 if(!molecule->residues)
3077 {
3078 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3079 __FILE__, __LINE__);
3080 if(molecule->chains)
3081 {
3082 free(molecule->chains);
3083 molecule->chains = 0;
3084 }
3085 return(TNG_CRITICAL);
3086 }
3087
3088 residue = molecule->residues;
3089 }
3090 else
3091 {
3092 residue = 0;
3093 }
3094
3095 molecule->atoms = (struct tng_atom *)malloc(molecule->n_atoms *
3096 sizeof(struct tng_atom));
3097 if(!molecule->atoms)
3098 {
3099 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3100 __FILE__, __LINE__);
3101 if(molecule->chains)
3102 {
3103 free(molecule->chains);
3104 molecule->chains = 0;
3105 }
3106 if(molecule->residues)
3107 {
3108 free(molecule->residues);
3109 molecule->residues = 0;
3110 }
3111 return(TNG_CRITICAL);
3112 }
3113
3114 atom = molecule->atoms;
3115
3116 if(molecule->n_chains > 0)
3117 {
3118 /* Read the chains of the molecule */
3119 for(j=0; j<molecule->n_chains; j++)
3120 {
3121 chain->molecule = molecule;
3122
3123 chain->name = 0;
3124
3125 tng_chain_data_read(tng_data, chain, hash_mode, &md5_state);
3126
3127 if(j==0)
3128 {
3129 chain->residues = molecule->residues;
3130 residue = chain->residues;
3131 }
3132 else
3133 {
3134 chain->residues = residue;
3135 }
3136
3137 /* Read the residues of the chain */
3138 for(k=0; k<chain->n_residues; k++)
3139 {
3140 residue->chain = chain;
3141
3142 residue->name = 0;
3143
3144 tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3145
3146 residue->atoms_offset = atom - molecule->atoms;
3147 /* Read the atoms of the residue */
3148 for(l=0; l<residue->n_atoms; l++)
3149 {
3150 atom->residue = residue;
3151
3152 atom->name = 0;
3153 atom->atom_type = 0;
3154
3155 tng_atom_data_read(tng_data,atom, hash_mode, &md5_state);
3156
3157 atom++;
3158 }
3159 residue++;
3160 }
3161 chain++;
3162 }
3163 }
3164 else
3165 {
3166 if(molecule->n_residues > 0)
3167 {
3168 for(k=0; k<molecule->n_residues; k++)
3169 {
3170 residue->chain = 0;
3171
3172 residue->name = 0;
3173
3174 tng_residue_data_read(tng_data, residue, hash_mode, &md5_state);
3175
3176 residue->atoms_offset = atom - molecule->atoms;
3177 /* Read the atoms of the residue */
3178 for(l=0; l<residue->n_atoms; l++)
3179 {
3180 atom->residue = residue;
3181
3182 tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3183
3184 atom++;
3185 }
3186 residue++;
3187 }
3188 }
3189 else
3190 {
3191 for(l=0; l<molecule->n_atoms; l++)
3192 {
3193 atom->residue = 0;
3194
3195 atom->name = 0;
3196 atom->atom_type = 0;
3197
3198 tng_atom_data_read(tng_data, atom, hash_mode, &md5_state);
3199
3200 atom++;
3201 }
3202 }
3203 }
3204
3205 if(tng_file_input_numerical(tng_data, &molecule->n_bonds,
3206 sizeof(molecule->n_bonds),
3207 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3208 {
3209 return(TNG_CRITICAL);
3210 }
3211
3212 if(molecule->n_bonds > 0)
3213 {
3214 tng_data->molecules[i].bonds = (struct tng_bond *)malloc(molecule->n_bonds *
3215 sizeof(struct tng_bond));
3216 if(!molecule->bonds)
3217 {
3218 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3219 __FILE__, __LINE__);
3220 if(molecule->chains)
3221 {
3222 free(molecule->chains);
3223 molecule->chains = 0;
3224 }
3225 if(molecule->residues)
3226 {
3227 free(molecule->residues);
3228 molecule->residues = 0;
3229 }
3230 if(molecule->atoms)
3231 {
3232 free(molecule->atoms);
3233 molecule->atoms = 0;
3234 }
3235 return(TNG_CRITICAL);
3236 }
3237
3238 bond = molecule->bonds;
3239
3240 for(j=0; j<molecule->n_bonds; j++)
3241 {
3242 if(tng_file_input_numerical(tng_data, &bond->from_atom_id,
3243 sizeof(bond->from_atom_id),
3244 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3245 {
3246 return(TNG_CRITICAL);
3247 }
3248
3249 if(tng_file_input_numerical(tng_data, &bond->to_atom_id,
3250 sizeof(bond->to_atom_id),
3251 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3252 {
3253 return(TNG_CRITICAL);
3254 }
3255
3256 bond++;
3257 }
3258 }
3259 else
3260 {
3261 molecule->bonds = 0;
3262 }
3263 }
3264
3265 if(hash_mode == TNG_USE_HASH)
3266 {
3267 /* If there is data left in the block that the current version of the library
3268 * cannot interpret still read that to generate the MD5 hash. */
3269 tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3270
3271 md5_finish(&md5_state, (md5_byte_t *)hash);
3272 if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
3273 {
3274 if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3275 {
3276 fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. "
3277 "%s: %d\n", __FILE__, __LINE__);
3278 }
3279 }
3280 }
3281
3282 else
3283 {
3284 /* Seek to the end of the block */
3285 fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3286 }
3287
3288 return(TNG_SUCCESS);
3289 }
3290
3291 /**
3292 * @brief Write a molecules block.
3293 * @param tng_data is a trajectory data container.
3294 * @param hash_mode is an option to decide whether to use the md5 hash or not.
3295 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3296 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3297 * error has occured.
3298 */
tng_molecules_block_write(const tng_trajectory_t tng_data,const char hash_mode)3299 static tng_function_status tng_molecules_block_write
3300 (const tng_trajectory_t tng_data,
3301 const char hash_mode)
3302 {
3303 int name_len;
3304 int64_t i, j, k, l, header_file_pos, curr_file_pos;
3305 tng_molecule_t molecule;
3306 tng_chain_t chain;
3307 tng_residue_t residue;
3308 tng_atom_t atom;
3309 tng_bond_t bond;
3310 tng_gen_block_t block;
3311 md5_state_t md5_state;
3312
3313 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3314 {
3315 return(TNG_CRITICAL);
3316 }
3317
3318 tng_block_init(&block);
3319
3320 name_len = (unsigned int)strlen("MOLECULES");
3321
3322 block->name = (char *)malloc(name_len + 1);
3323 if(!block->name)
3324 {
3325 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
3326 tng_block_destroy(&block);
3327 return(TNG_CRITICAL);
3328 }
3329
3330 strcpy(block->name, "MOLECULES");
3331 block->id = TNG_MOLECULES;
3332
3333 if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) !=
3334 TNG_SUCCESS)
3335 {
3336 fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n",
3337 __FILE__, __LINE__);
3338 tng_block_destroy(&block);
3339 return(TNG_CRITICAL);
3340 }
3341
3342 header_file_pos = ftello(tng_data->output_file);
3343
3344 if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3345 {
3346 fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3347 tng_data->output_file_path, __FILE__, __LINE__);
3348 tng_block_destroy(&block);
3349 return(TNG_CRITICAL);
3350 }
3351
3352 if(hash_mode == TNG_USE_HASH)
3353 {
3354 md5_init(&md5_state);
3355 }
3356
3357 if(tng_file_output_numerical(tng_data, &tng_data->n_molecules,
3358 sizeof(tng_data->n_molecules),
3359 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3360 {
3361 return(TNG_CRITICAL);
3362 }
3363
3364 for(i = 0; i < tng_data->n_molecules; i++)
3365 {
3366 molecule = &tng_data->molecules[i];
3367
3368 if(tng_file_output_numerical(tng_data, &molecule->id,
3369 sizeof(molecule->id),
3370 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3371 {
3372 return(TNG_CRITICAL);
3373 }
3374
3375 if(tng_fwritestr(tng_data, molecule->name, hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3376 {
3377 return(TNG_CRITICAL);
3378 }
3379
3380 if(tng_file_output_numerical(tng_data, &molecule->quaternary_str,
3381 sizeof(molecule->quaternary_str),
3382 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3383 {
3384 return(TNG_CRITICAL);
3385 }
3386
3387 if(!tng_data->var_num_atoms_flag)
3388 {
3389 if(tng_file_output_numerical(tng_data, &tng_data->molecule_cnt_list[i],
3390 sizeof(int64_t),
3391 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3392 {
3393 return(TNG_CRITICAL);
3394 }
3395 }
3396
3397 if(tng_file_output_numerical(tng_data, &molecule->n_chains,
3398 sizeof(molecule->n_chains),
3399 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3400 {
3401 return(TNG_CRITICAL);
3402 }
3403
3404 if(tng_file_output_numerical(tng_data, &molecule->n_residues,
3405 sizeof(molecule->n_residues),
3406 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3407 {
3408 return(TNG_CRITICAL);
3409 }
3410
3411 if(tng_file_output_numerical(tng_data, &molecule->n_atoms,
3412 sizeof(molecule->n_atoms),
3413 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3414 {
3415 return(TNG_CRITICAL);
3416 }
3417
3418 if(molecule->n_chains > 0)
3419 {
3420 chain = molecule->chains;
3421 for(j = 0; j < molecule->n_chains; j++)
3422 {
3423 tng_chain_data_write(tng_data, chain, hash_mode, &md5_state);
3424
3425 residue = chain->residues;
3426 for(k = 0; k < chain->n_residues; k++)
3427 {
3428 tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3429
3430 atom = molecule->atoms + residue->atoms_offset;
3431 for(l = 0; l < residue->n_atoms; l++)
3432 {
3433 tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3434
3435 atom++;
3436 }
3437 residue++;
3438 }
3439 chain++;
3440 }
3441 }
3442 else
3443 {
3444 if(molecule->n_residues > 0)
3445 {
3446 residue = molecule->residues;
3447 for(k = 0; k < molecule->n_residues; k++)
3448 {
3449 tng_residue_data_write(tng_data, residue, hash_mode, &md5_state);
3450
3451 atom = molecule->atoms + residue->atoms_offset;
3452 for(l = 0; l < residue->n_atoms; l++)
3453 {
3454 tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3455
3456 atom++;
3457 }
3458 residue++;
3459 }
3460 }
3461 else
3462 {
3463 atom = molecule->atoms;
3464 for(l = 0; l < molecule->n_atoms; l++)
3465 {
3466 tng_atom_data_write(tng_data, atom, hash_mode, &md5_state);
3467
3468 atom++;
3469 }
3470 }
3471 }
3472
3473 if(tng_file_output_numerical(tng_data, &molecule->n_bonds,
3474 sizeof(molecule->n_bonds),
3475 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3476 {
3477 return(TNG_CRITICAL);
3478 }
3479
3480 bond = molecule->bonds;
3481 for(j = 0; j < molecule->n_bonds; j++)
3482 {
3483 if(tng_file_output_numerical(tng_data, &bond->from_atom_id,
3484 sizeof(bond->from_atom_id),
3485 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3486 {
3487 return(TNG_CRITICAL);
3488 }
3489
3490 if(tng_file_output_numerical(tng_data, &bond->to_atom_id,
3491 sizeof(bond->to_atom_id),
3492 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3493 {
3494 return(TNG_CRITICAL);
3495 }
3496
3497 bond++;
3498 }
3499 }
3500 if(hash_mode == TNG_USE_HASH)
3501 {
3502 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3503 curr_file_pos = ftello(tng_data->output_file);
3504 fseeko(tng_data->output_file, header_file_pos +
3505 3 * sizeof(int64_t), SEEK_SET);
3506 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3507 {
3508 fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3509 __LINE__);
3510 return(TNG_CRITICAL);
3511 }
3512 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3513 }
3514
3515 tng_block_destroy(&block);
3516
3517 return(TNG_SUCCESS);
3518 }
3519
tng_frame_set_block_len_calculate(const tng_trajectory_t tng_data,int64_t * len)3520 static tng_function_status tng_frame_set_block_len_calculate
3521 (const tng_trajectory_t tng_data,
3522 int64_t *len)
3523 {
3524 *len = sizeof(int64_t) * 8;
3525 *len += sizeof(double) * 2;
3526
3527 if(tng_data->var_num_atoms_flag)
3528 {
3529 *len += sizeof(int64_t) * tng_data->n_molecules;
3530 }
3531 return(TNG_SUCCESS);
3532 }
3533
3534 /**
3535 * @brief Read a frame set block. Update tng_data->current_trajectory_frame_set
3536 * @param tng_data is a trajectory data container.
3537 * @param block is a general block container.
3538 * @param hash_mode is an option to decide whether to use the md5 hash or not.
3539 * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3540 * compared to the md5 hash of the read contents to ensure valid data.
3541 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3542 * error has occured.
3543 */
tng_frame_set_block_read(tng_trajectory_t tng_data,tng_gen_block_t block,const char hash_mode)3544 static tng_function_status tng_frame_set_block_read
3545 (tng_trajectory_t tng_data,
3546 tng_gen_block_t block,
3547 const char hash_mode)
3548 {
3549 int64_t file_pos, start_pos, i, prev_n_particles;
3550 tng_trajectory_frame_set_t frame_set =
3551 &tng_data->current_trajectory_frame_set;
3552 char hash[TNG_MD5_HASH_LEN];
3553 md5_state_t md5_state;
3554
3555 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3556 {
3557 return(TNG_CRITICAL);
3558 }
3559
3560 start_pos = ftello(tng_data->input_file);
3561
3562 /* FIXME: Does not check if the size of the contents matches the expected
3563 * size or if the contents can be read. */
3564
3565 file_pos = start_pos - block->header_contents_size;
3566
3567 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
3568
3569 tng_frame_set_particle_mapping_free(tng_data);
3570
3571 if(hash_mode == TNG_USE_HASH)
3572 {
3573 md5_init(&md5_state);
3574 }
3575 if(tng_file_input_numerical(tng_data, &frame_set->first_frame,
3576 sizeof(frame_set->first_frame),
3577 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3578 {
3579 return(TNG_CRITICAL);
3580 }
3581
3582 if(tng_file_input_numerical(tng_data, &frame_set->n_frames,
3583 sizeof(frame_set->n_frames),
3584 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3585 {
3586 return(TNG_CRITICAL);
3587 }
3588
3589 if(tng_data->var_num_atoms_flag)
3590 {
3591 prev_n_particles = frame_set->n_particles;
3592 frame_set->n_particles = 0;
3593 /* If the list of molecule counts has already been created assume that
3594 * it is of correct size. */
3595 if(!frame_set->molecule_cnt_list)
3596 {
3597 frame_set->molecule_cnt_list =
3598 (int64_t *)malloc(sizeof(int64_t) * tng_data->n_molecules);
3599
3600 if(!frame_set->molecule_cnt_list)
3601 {
3602 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3603 __FILE__, __LINE__);
3604 return(TNG_CRITICAL);
3605 }
3606 }
3607 for(i = 0; i < tng_data->n_molecules; i++)
3608 {
3609 if(tng_file_input_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3610 sizeof(int64_t),
3611 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3612 {
3613 return(TNG_CRITICAL);
3614 }
3615
3616 frame_set->n_particles += tng_data->molecules[i].n_atoms *
3617 frame_set->molecule_cnt_list[i];
3618 }
3619 if(prev_n_particles && frame_set->n_particles != prev_n_particles)
3620 {
3621 /* FIXME: Particle dependent data memory management */
3622 }
3623 }
3624
3625 if(tng_file_input_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3626 sizeof(frame_set->next_frame_set_file_pos),
3627 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3628 {
3629 return(TNG_CRITICAL);
3630 }
3631
3632 if(tng_file_input_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3633 sizeof(frame_set->prev_frame_set_file_pos),
3634 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3635 {
3636 return(TNG_CRITICAL);
3637 }
3638
3639 if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3640 sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3641 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3642 {
3643 return(TNG_CRITICAL);
3644 }
3645
3646 if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3647 sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3648 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3649 {
3650 return(TNG_CRITICAL);
3651 }
3652
3653 if(tng_file_input_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3654 sizeof(frame_set->long_stride_next_frame_set_file_pos),
3655 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3656 {
3657 return(TNG_CRITICAL);
3658 }
3659
3660 if(tng_file_input_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3661 sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3662 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3663 {
3664 return(TNG_CRITICAL);
3665 }
3666
3667 if(block->block_version >= 3)
3668 {
3669 if(tng_file_input_numerical(tng_data, &frame_set->first_frame_time,
3670 sizeof(frame_set->first_frame_time),
3671 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3672 {
3673 return(TNG_CRITICAL);
3674 }
3675
3676 if(tng_file_input_numerical(tng_data, &tng_data->time_per_frame,
3677 sizeof(tng_data->time_per_frame),
3678 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3679 {
3680 return(TNG_CRITICAL);
3681 }
3682 }
3683 else
3684 {
3685 frame_set->first_frame_time = -1;
3686 tng_data->time_per_frame = -1;
3687 }
3688
3689 if(hash_mode == TNG_USE_HASH)
3690 {
3691 /* If there is data left in the block that the current version of the library
3692 * cannot interpret still read that to generate the MD5 hash. */
3693 tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
3694
3695 md5_finish(&md5_state, (md5_byte_t *)hash);
3696 if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
3697 {
3698 if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
3699 {
3700 fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %" PRId64 "). Hashes do not match. "
3701 "%s: %d\n", frame_set->first_frame, __FILE__, __LINE__);
3702 }
3703 }
3704 }
3705 else
3706 {
3707 /* Seek to the end of the block */
3708 fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
3709 }
3710
3711 /* If the output file and the input files are the same the number of
3712 * frames in the file are the same number as has just been read.
3713 * This is updated here to later on see if there have been new frames
3714 * added and thereby the frame set needs to be rewritten. */
3715 if(tng_data->output_file == tng_data->input_file)
3716 {
3717 frame_set->n_written_frames = frame_set->n_frames;
3718 }
3719
3720 return(TNG_SUCCESS);
3721 }
3722
3723 /**
3724 * @brief Write tng_data->current_trajectory_frame_set to file
3725 * @param tng_data is a trajectory data container.
3726 * @param block is a general block container.
3727 * @param hash_mode is an option to decide whether to use the md5 hash or not.
3728 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
3729 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3730 * error has occured.
3731 */
tng_frame_set_block_write(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)3732 static tng_function_status tng_frame_set_block_write
3733 (const tng_trajectory_t tng_data,
3734 const tng_gen_block_t block,
3735 const char hash_mode)
3736 {
3737 char *temp_name;
3738 int64_t i, header_file_pos, curr_file_pos;
3739 unsigned int name_len;
3740 tng_trajectory_frame_set_t frame_set =
3741 &tng_data->current_trajectory_frame_set;
3742 md5_state_t md5_state;
3743
3744 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
3745 {
3746 return(TNG_CRITICAL);
3747 }
3748
3749 name_len = (unsigned int)strlen("TRAJECTORY FRAME SET");
3750
3751 if(!block->name || strlen(block->name) < name_len)
3752 {
3753 temp_name = (char *)realloc(block->name, name_len + 1);
3754 if(!temp_name)
3755 {
3756 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3757 __FILE__, __LINE__);
3758 free(block->name);
3759 block->name = 0;
3760 return(TNG_CRITICAL);
3761 }
3762 block->name = temp_name;
3763 }
3764 strcpy(block->name, "TRAJECTORY FRAME SET");
3765 block->id = TNG_TRAJECTORY_FRAME_SET;
3766
3767 if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) !=
3768 TNG_SUCCESS)
3769 {
3770 fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n",
3771 __FILE__, __LINE__);
3772 return(TNG_CRITICAL);
3773 }
3774
3775 header_file_pos = ftello(tng_data->output_file);
3776
3777 if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
3778 {
3779 fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
3780 tng_data->output_file_path, __FILE__, __LINE__);
3781 return(TNG_CRITICAL);
3782 }
3783
3784 if(hash_mode == TNG_USE_HASH)
3785 {
3786 md5_init(&md5_state);
3787 }
3788 if(tng_file_output_numerical(tng_data, &frame_set->first_frame,
3789 sizeof(frame_set->first_frame),
3790 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3791 {
3792 return(TNG_CRITICAL);
3793 }
3794
3795 if(tng_file_output_numerical(tng_data, &frame_set->n_frames,
3796 sizeof(frame_set->n_frames),
3797 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3798 {
3799 return(TNG_CRITICAL);
3800 }
3801
3802 if(tng_data->var_num_atoms_flag)
3803 {
3804 for(i = 0; i < tng_data->n_molecules; i++)
3805 {
3806 if(tng_file_output_numerical(tng_data, &frame_set->molecule_cnt_list[i],
3807 sizeof(int64_t),
3808 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3809 {
3810 return(TNG_CRITICAL);
3811 }
3812 }
3813 }
3814
3815 if(tng_file_output_numerical(tng_data, &frame_set->next_frame_set_file_pos,
3816 sizeof(frame_set->next_frame_set_file_pos),
3817 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3818 {
3819 return(TNG_CRITICAL);
3820 }
3821
3822 if(tng_file_output_numerical(tng_data, &frame_set->prev_frame_set_file_pos,
3823 sizeof(frame_set->prev_frame_set_file_pos),
3824 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3825 {
3826 return(TNG_CRITICAL);
3827 }
3828
3829 if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos,
3830 sizeof(frame_set->medium_stride_next_frame_set_file_pos),
3831 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3832 {
3833 return(TNG_CRITICAL);
3834 }
3835
3836 if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos,
3837 sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
3838 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3839 {
3840 return(TNG_CRITICAL);
3841 }
3842
3843 if(tng_file_output_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos,
3844 sizeof(frame_set->long_stride_next_frame_set_file_pos),
3845 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3846 {
3847 return(TNG_CRITICAL);
3848 }
3849
3850 if(tng_file_output_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos,
3851 sizeof(frame_set->long_stride_prev_frame_set_file_pos),
3852 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3853 {
3854 return(TNG_CRITICAL);
3855 }
3856
3857 if(tng_file_output_numerical(tng_data, &frame_set->first_frame_time,
3858 sizeof(frame_set->first_frame_time),
3859 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3860 {
3861 return(TNG_CRITICAL);
3862 }
3863
3864 if(tng_file_output_numerical(tng_data, &tng_data->time_per_frame,
3865 sizeof(tng_data->time_per_frame),
3866 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3867 {
3868 return(TNG_CRITICAL);
3869 }
3870 if(hash_mode == TNG_USE_HASH)
3871 {
3872 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
3873 curr_file_pos = ftello(tng_data->output_file);
3874 fseeko(tng_data->output_file, header_file_pos +
3875 3 * sizeof(int64_t), SEEK_SET);
3876 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
3877 {
3878 fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
3879 __LINE__);
3880 return(TNG_CRITICAL);
3881 }
3882 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
3883 }
3884
3885 return(TNG_SUCCESS);
3886 }
3887
tng_trajectory_mapping_block_len_calculate(const tng_trajectory_t tng_data,const int64_t n_particles,int64_t * len)3888 static tng_function_status tng_trajectory_mapping_block_len_calculate
3889 (const tng_trajectory_t tng_data,
3890 const int64_t n_particles,
3891 int64_t *len)
3892 {
3893 (void)tng_data;
3894 *len = sizeof(int64_t) * (2 + n_particles);
3895
3896 return(TNG_SUCCESS);
3897 }
3898
3899 /**
3900 * @brief Read an atom mappings block (translating between real atom indexes and how
3901 * the atom info is written in this frame set).
3902 * @param tng_data is a trajectory data container.
3903 * @param block is a general block container.
3904 * @param hash_mode is an option to decide whether to use the md5 hash or not.
3905 * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
3906 * compared to the md5 hash of the read contents to ensure valid data.
3907 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
3908 * error has occured.
3909 */
tng_trajectory_mapping_block_read(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)3910 static tng_function_status tng_trajectory_mapping_block_read
3911 (const tng_trajectory_t tng_data,
3912 const tng_gen_block_t block,
3913 const char hash_mode)
3914 {
3915 int64_t start_pos, i;
3916 tng_trajectory_frame_set_t frame_set =
3917 &tng_data->current_trajectory_frame_set;
3918 tng_particle_mapping_t mapping, mappings;
3919 char hash[TNG_MD5_HASH_LEN];
3920 md5_state_t md5_state;
3921
3922 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
3923 {
3924 return(TNG_CRITICAL);
3925 }
3926
3927 start_pos = ftello(tng_data->input_file);
3928
3929 /* FIXME: Does not check if the size of the contents matches the expected
3930 * size or if the contents can be read. */
3931
3932 frame_set->n_mapping_blocks++;
3933 mappings = (tng_particle_mapping_t)realloc(frame_set->mappings,
3934 sizeof(struct tng_particle_mapping) *
3935 frame_set->n_mapping_blocks);
3936 if(!mappings)
3937 {
3938 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3939 __FILE__, __LINE__);
3940 free(frame_set->mappings);
3941 frame_set->mappings = 0;
3942 return(TNG_CRITICAL);
3943 }
3944 frame_set->mappings = mappings;
3945 mapping = &mappings[frame_set->n_mapping_blocks - 1];
3946
3947
3948 if(hash_mode == TNG_USE_HASH)
3949 {
3950 md5_init(&md5_state);
3951 }
3952
3953 if(tng_file_input_numerical(tng_data, &mapping->num_first_particle,
3954 sizeof(mapping->num_first_particle),
3955 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3956 {
3957 return(TNG_CRITICAL);
3958 }
3959
3960 if(tng_file_input_numerical(tng_data, &mapping->n_particles,
3961 sizeof(mapping->n_particles),
3962 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3963 {
3964 return(TNG_CRITICAL);
3965 }
3966
3967 mapping->real_particle_numbers = (int64_t *)malloc(mapping->n_particles *
3968 sizeof(int64_t));
3969 if(!mapping->real_particle_numbers)
3970 {
3971 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
3972 __FILE__, __LINE__);
3973 return(TNG_CRITICAL);
3974 }
3975
3976 /* If the byte order needs to be swapped the data must be read one value at
3977 * a time and swapped */
3978 if(tng_data->input_endianness_swap_func_64)
3979 {
3980 for(i = 0; i < mapping->n_particles; i++)
3981 {
3982 if(tng_file_input_numerical(tng_data, &mapping->real_particle_numbers[i],
3983 sizeof(int64_t),
3984 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
3985 {
3986 return(TNG_CRITICAL);
3987 }
3988 }
3989 }
3990 /* Otherwise the data can be read all at once */
3991 else
3992 {
3993 if(fread(mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t),
3994 1, tng_data->input_file) == 0)
3995 {
3996 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
3997 return(TNG_CRITICAL);
3998 }
3999 if(hash_mode == TNG_USE_HASH)
4000 {
4001 md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t));
4002 }
4003 }
4004
4005 if(hash_mode == TNG_USE_HASH)
4006 {
4007 /* If there is data left in the block that the current version of the library
4008 * cannot interpret still read that to generate the MD5 hash. */
4009 tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
4010
4011 md5_finish(&md5_state, (md5_byte_t *)hash);
4012 if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
4013 {
4014 if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
4015 {
4016 fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. "
4017 "%s: %d\n", __FILE__, __LINE__);
4018 }
4019 }
4020 }
4021 else
4022 {
4023 /* Seek to the end of the block */
4024 fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
4025 }
4026
4027 return(TNG_SUCCESS);
4028 }
4029
4030 /**
4031 * @brief Write the atom mappings of the current trajectory frame set
4032 * @param tng_data is a trajectory data container.
4033 * @param block is a general block container.
4034 * @param mapping_block_nr is the index of the mapping block to write.
4035 * @param hash_mode is an option to decide whether to use the md5 hash or not.
4036 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
4037 * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error
4038 * has occurred or TNG_CRITICAL (2) if a major error has occured.
4039 */
tng_trajectory_mapping_block_write(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int mapping_block_nr,const char hash_mode)4040 static tng_function_status tng_trajectory_mapping_block_write
4041 (const tng_trajectory_t tng_data,
4042 const tng_gen_block_t block,
4043 const int mapping_block_nr,
4044 const char hash_mode)
4045 {
4046 int64_t header_file_pos, curr_file_pos;
4047 char *temp_name;
4048 int i;
4049 unsigned int name_len;
4050 md5_state_t md5_state;
4051 tng_particle_mapping_t mapping =
4052 &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr];
4053
4054 if(mapping_block_nr >=
4055 tng_data->current_trajectory_frame_set.n_mapping_blocks)
4056 {
4057 fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n",
4058 __FILE__, __LINE__);
4059 return(TNG_FAILURE);
4060 }
4061
4062 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
4063 {
4064 return(TNG_CRITICAL);
4065 }
4066
4067 name_len = (unsigned int)strlen("PARTICLE MAPPING");
4068
4069 if(!block->name || strlen(block->name) < name_len)
4070 {
4071 temp_name = (char *)realloc(block->name, name_len + 1);
4072 if(!temp_name)
4073 {
4074 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4075 __FILE__, __LINE__);
4076 free(block->name);
4077 block->name = 0;
4078 return(TNG_CRITICAL);
4079 }
4080 block->name = temp_name;
4081 }
4082 strcpy(block->name, "PARTICLE MAPPING");
4083 block->id = TNG_PARTICLE_MAPPING;
4084
4085 if(tng_trajectory_mapping_block_len_calculate(tng_data,
4086 mapping->n_particles,
4087 &block->block_contents_size) !=
4088 TNG_SUCCESS)
4089 {
4090 fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n",
4091 __FILE__, __LINE__);
4092 return(TNG_CRITICAL);
4093 }
4094
4095 header_file_pos = ftello(tng_data->output_file);
4096
4097 if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
4098 {
4099 fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
4100 tng_data->output_file_path, __FILE__, __LINE__);
4101 return(TNG_CRITICAL);
4102 }
4103
4104 if(hash_mode == TNG_USE_HASH)
4105 {
4106 md5_init(&md5_state);
4107 }
4108 if(tng_file_output_numerical(tng_data, &mapping->num_first_particle,
4109 sizeof(mapping->num_first_particle),
4110 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4111 {
4112 return(TNG_CRITICAL);
4113 }
4114
4115 if(tng_file_output_numerical(tng_data, &mapping->n_particles,
4116 sizeof(mapping->n_particles),
4117 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4118 {
4119 return(TNG_CRITICAL);
4120 }
4121
4122 if(tng_data->output_endianness_swap_func_64)
4123 {
4124 for(i = 0; i < mapping->n_particles; i++)
4125 {
4126 if(tng_file_output_numerical(tng_data, &mapping->real_particle_numbers[i],
4127 sizeof(int64_t),
4128 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
4129 {
4130 return(TNG_CRITICAL);
4131 }
4132 }
4133 }
4134 else
4135 {
4136 if(fwrite(mapping->real_particle_numbers,
4137 mapping->n_particles * sizeof(int64_t),
4138 1, tng_data->output_file) != 1)
4139 {
4140 fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, __LINE__);
4141 return(TNG_CRITICAL);
4142 }
4143 if(hash_mode == TNG_USE_HASH)
4144 {
4145 md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers,
4146 mapping->n_particles * sizeof(int64_t));
4147 }
4148 }
4149
4150 if(hash_mode == TNG_USE_HASH)
4151 {
4152 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
4153 curr_file_pos = ftello(tng_data->output_file);
4154 fseeko(tng_data->output_file, header_file_pos +
4155 3 * sizeof(int64_t), SEEK_SET);
4156 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
4157 {
4158 fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
4159 __LINE__);
4160 return(TNG_CRITICAL);
4161 }
4162 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
4163 }
4164
4165 return(TNG_SUCCESS);
4166 }
4167
4168 /**
4169 * @brief Prepare a block for storing particle data
4170 * @param tng_data is a trajectory data container.
4171 * @param block_type_flag specifies if this is a trajectory block or a
4172 * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
4173 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4174 * error has occured.
4175 */
tng_particle_data_block_create(const tng_trajectory_t tng_data,const char block_type_flag)4176 static tng_function_status tng_particle_data_block_create
4177 (const tng_trajectory_t tng_data,
4178 const char block_type_flag)
4179 {
4180 tng_trajectory_frame_set_t frame_set =
4181 &tng_data->current_trajectory_frame_set;
4182
4183 tng_data_t data;
4184
4185 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4186 {
4187 frame_set->n_particle_data_blocks++;
4188 data = (tng_data_t)realloc(frame_set->tr_particle_data,
4189 sizeof(struct tng_data) *
4190 frame_set->n_particle_data_blocks);
4191 if(!data)
4192 {
4193 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4194 __FILE__, __LINE__);
4195 free(frame_set->tr_particle_data);
4196 frame_set->tr_particle_data = 0;
4197 return(TNG_CRITICAL);
4198 }
4199 frame_set->tr_particle_data = data;
4200 }
4201 else
4202 {
4203 tng_data->n_particle_data_blocks++;
4204 data = (tng_data_t)realloc(tng_data->non_tr_particle_data,
4205 sizeof(struct tng_data) *
4206 tng_data->n_particle_data_blocks);
4207 if(!data)
4208 {
4209 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4210 __FILE__, __LINE__);
4211 free(tng_data->non_tr_particle_data);
4212 tng_data->non_tr_particle_data = 0;
4213 return(TNG_CRITICAL);
4214 }
4215 tng_data->non_tr_particle_data = data;
4216 }
4217
4218 return(TNG_SUCCESS);
4219 }
4220
tng_compress(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int64_t n_frames,const int64_t n_particles,const char type,char ** data,int64_t * new_len)4221 static tng_function_status tng_compress(const tng_trajectory_t tng_data,
4222 const tng_gen_block_t block,
4223 const int64_t n_frames,
4224 const int64_t n_particles,
4225 const char type,
4226 char **data,
4227 int64_t *new_len)
4228 {
4229 int nalgo;
4230 int compressed_len;
4231 int *alt_algo = 0;
4232 char *dest;
4233 int64_t algo_find_n_frames = -1;
4234 float f_precision;
4235 double d_precision;
4236
4237 if(block->id != TNG_TRAJ_POSITIONS &&
4238 block->id != TNG_TRAJ_VELOCITIES)
4239 {
4240 fprintf(stderr, "TNG library: Can only compress positions and velocities with the "
4241 "TNG method. %s: %d\n", __FILE__, __LINE__);
4242 return(TNG_FAILURE);
4243 }
4244 if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4245 {
4246 fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__);
4247 return(TNG_FAILURE);
4248 }
4249
4250 if(n_frames <= 0 || n_particles <= 0)
4251 {
4252 fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data "
4253 "with the TNG method. %s: %d\n", __FILE__, __LINE__);
4254 return(TNG_FAILURE);
4255 }
4256
4257 f_precision = 1/(float)tng_data->compression_precision;
4258 d_precision = 1/tng_data->compression_precision;
4259
4260 if(block->id == TNG_TRAJ_POSITIONS)
4261 {
4262 /* If there is only one frame in this frame set and there might be more
4263 * do not store the algorithm as the compression algorithm, but find
4264 * the best one without storing it */
4265 if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4266 {
4267 nalgo = tng_compress_nalgo();
4268 alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_pos);
4269
4270 /* If we have already determined the initial coding and
4271 * initial coding parameter do not determine them again. */
4272 if(tng_data->compress_algo_pos)
4273 {
4274 alt_algo[0] = tng_data->compress_algo_pos[0];
4275 alt_algo[1] = tng_data->compress_algo_pos[1];
4276 alt_algo[2] = tng_data->compress_algo_pos[2];
4277 alt_algo[3] = tng_data->compress_algo_pos[3];
4278 }
4279 else
4280 {
4281 alt_algo[0] = -1;
4282 alt_algo[1] = -1;
4283 alt_algo[2] = -1;
4284 alt_algo[3] = -1;
4285 }
4286
4287 /* If the initial coding and initial coding parameter are -1
4288 * they will be determined in tng_compress_pos/_float/. */
4289 if(type == TNG_FLOAT_DATA)
4290 {
4291 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4292 (int)n_frames,
4293 f_precision,
4294 0, alt_algo,
4295 &compressed_len);
4296
4297 }
4298 else
4299 {
4300 dest = tng_compress_pos((double *)*data, (int)n_particles,
4301 (int)n_frames,
4302 d_precision,
4303 0, alt_algo,
4304 &compressed_len);
4305 }
4306 /* If there had been no algorithm determined before keep the initial coding
4307 * and initial coding parameter so that they won't have to be determined again. */
4308 if(!tng_data->compress_algo_pos)
4309 {
4310 nalgo = tng_compress_nalgo();
4311 tng_data->compress_algo_pos = (int *)malloc(nalgo *
4312 sizeof *tng_data->compress_algo_pos);
4313 tng_data->compress_algo_pos[0] = alt_algo[0];
4314 tng_data->compress_algo_pos[1] = alt_algo[1];
4315 tng_data->compress_algo_pos[2] = -1;
4316 tng_data->compress_algo_pos[3] = -1;
4317 }
4318 }
4319 else if(!tng_data->compress_algo_pos || tng_data->compress_algo_pos[2] == -1 ||
4320 tng_data->compress_algo_pos[2] == -1)
4321 {
4322 if(n_frames > 6)
4323 {
4324 algo_find_n_frames = 5;
4325 }
4326 else
4327 {
4328 algo_find_n_frames = n_frames;
4329 }
4330
4331 /* If the algorithm parameters are -1 they will be determined during the
4332 * compression. */
4333 if(!tng_data->compress_algo_pos)
4334 {
4335 nalgo = tng_compress_nalgo();
4336 tng_data->compress_algo_pos = (int *)malloc(nalgo *
4337 sizeof *tng_data->compress_algo_pos);
4338 tng_data->compress_algo_pos[0] = -1;
4339 tng_data->compress_algo_pos[1] = -1;
4340 tng_data->compress_algo_pos[2] = -1;
4341 tng_data->compress_algo_pos[3] = -1;
4342 }
4343 if(type == TNG_FLOAT_DATA)
4344 {
4345 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4346 (int)algo_find_n_frames,
4347 f_precision,
4348 0, tng_data->
4349 compress_algo_pos,
4350 &compressed_len);
4351
4352 if(algo_find_n_frames < n_frames)
4353 {
4354 free(dest);
4355 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4356 (int)n_frames,
4357 f_precision,
4358 0, tng_data->compress_algo_pos,
4359 &compressed_len);
4360 }
4361 }
4362 else
4363 {
4364 dest = tng_compress_pos((double *)*data, (int)n_particles,
4365 (int)algo_find_n_frames,
4366 d_precision,
4367 0, tng_data->
4368 compress_algo_pos,
4369 &compressed_len);
4370
4371 if(algo_find_n_frames < n_frames)
4372 {
4373 free(dest);
4374 dest = tng_compress_pos((double *)*data, (int)n_particles,
4375 (int)n_frames,
4376 d_precision, 0,
4377 tng_data->compress_algo_pos,
4378 &compressed_len);
4379 }
4380 }
4381 }
4382 else
4383 {
4384 if(type == TNG_FLOAT_DATA)
4385 {
4386 dest = tng_compress_pos_float((float *)*data, (int)n_particles,
4387 (int)n_frames,
4388 f_precision, 0,
4389 tng_data->compress_algo_pos, &compressed_len);
4390 }
4391 else
4392 {
4393 dest = tng_compress_pos((double *)*data, (int)n_particles,
4394 (int)n_frames,
4395 d_precision, 0,
4396 tng_data->compress_algo_pos,
4397 &compressed_len);
4398 }
4399 }
4400 }
4401 else if(block->id == TNG_TRAJ_VELOCITIES)
4402 {
4403 /* If there is only one frame in this frame set and there might be more
4404 * do not store the algorithm as the compression algorithm, but find
4405 * the best one without storing it */
4406 if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
4407 {
4408 nalgo = tng_compress_nalgo();
4409 alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_vel);
4410
4411 /* If we have already determined the initial coding and
4412 * initial coding parameter do not determine them again. */
4413 if(tng_data->compress_algo_vel)
4414 {
4415 alt_algo[0] = tng_data->compress_algo_vel[0];
4416 alt_algo[1] = tng_data->compress_algo_vel[1];
4417 alt_algo[2] = tng_data->compress_algo_vel[2];
4418 alt_algo[3] = tng_data->compress_algo_vel[3];
4419 }
4420 else
4421 {
4422 alt_algo[0] = -1;
4423 alt_algo[1] = -1;
4424 alt_algo[2] = -1;
4425 alt_algo[3] = -1;
4426 }
4427
4428 /* If the initial coding and initial coding parameter are -1
4429 * they will be determined in tng_compress_pos/_float/. */
4430 if(type == TNG_FLOAT_DATA)
4431 {
4432 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4433 (int)n_frames,
4434 f_precision,
4435 0, alt_algo,
4436 &compressed_len);
4437
4438 }
4439 else
4440 {
4441 dest = tng_compress_vel((double *)*data, (int)n_particles,
4442 (int)n_frames,
4443 d_precision,
4444 0, alt_algo,
4445 &compressed_len);
4446 }
4447 /* If there had been no algorithm determined before keep the initial coding
4448 * and initial coding parameter so that they won't have to be determined again. */
4449 if(!tng_data->compress_algo_vel)
4450 {
4451 nalgo = tng_compress_nalgo();
4452 tng_data->compress_algo_vel = (int *)malloc(nalgo *
4453 sizeof *tng_data->compress_algo_vel);
4454 tng_data->compress_algo_vel[0] = alt_algo[0];
4455 tng_data->compress_algo_vel[1] = alt_algo[1];
4456 tng_data->compress_algo_vel[2] = -1;
4457 tng_data->compress_algo_vel[3] = -1;
4458 }
4459 }
4460 else if(!tng_data->compress_algo_vel || tng_data->compress_algo_vel[2] == -1 ||
4461 tng_data->compress_algo_vel[2] == -1)
4462 {
4463 if(n_frames > 6)
4464 {
4465 algo_find_n_frames = 5;
4466 }
4467 else
4468 {
4469 algo_find_n_frames = n_frames;
4470 }
4471
4472 /* If the algorithm parameters are -1 they will be determined during the
4473 * compression. */
4474 if(!tng_data->compress_algo_vel)
4475 {
4476 nalgo = tng_compress_nalgo();
4477 tng_data->compress_algo_vel = (int *)malloc(nalgo *
4478 sizeof *tng_data->compress_algo_vel);
4479 tng_data->compress_algo_vel[0] = -1;
4480 tng_data->compress_algo_vel[1] = -1;
4481 tng_data->compress_algo_vel[2] = -1;
4482 tng_data->compress_algo_vel[3] = -1;
4483 }
4484 if(type == TNG_FLOAT_DATA)
4485 {
4486 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4487 (int)algo_find_n_frames,
4488 f_precision,
4489 0, tng_data->
4490 compress_algo_vel,
4491 &compressed_len);
4492 if(algo_find_n_frames < n_frames)
4493 {
4494 free(dest);
4495 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4496 (int)n_frames,
4497 f_precision,
4498 0, tng_data->compress_algo_vel,
4499 &compressed_len);
4500 }
4501 }
4502 else
4503 {
4504 dest = tng_compress_vel((double *)*data, (int)n_particles,
4505 (int)algo_find_n_frames,
4506 d_precision,
4507 0, tng_data->
4508 compress_algo_vel,
4509 &compressed_len);
4510 if(algo_find_n_frames < n_frames)
4511 {
4512 free(dest);
4513 dest = tng_compress_vel((double *)*data, (int)n_particles,
4514 (int)n_frames,
4515 d_precision,
4516 0, tng_data->compress_algo_vel,
4517 &compressed_len);
4518 }
4519 }
4520 }
4521 else
4522 {
4523 if(type == TNG_FLOAT_DATA)
4524 {
4525 dest = tng_compress_vel_float((float *)*data, (int)n_particles,
4526 (int)n_frames,
4527 f_precision,
4528 0, tng_data->
4529 compress_algo_vel,
4530 &compressed_len);
4531 }
4532 else
4533 {
4534 dest = tng_compress_vel((double *)*data, (int)n_particles,
4535 (int)n_frames,
4536 d_precision,
4537 0, tng_data->
4538 compress_algo_vel,
4539 &compressed_len);
4540 }
4541 }
4542 }
4543 else
4544 {
4545 fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n");
4546 return(TNG_FAILURE);
4547 }
4548
4549 if(alt_algo)
4550 {
4551 free(alt_algo);
4552 }
4553
4554 free(*data);
4555
4556 *data = (char *)dest;
4557
4558 *new_len = compressed_len;
4559
4560 return(TNG_SUCCESS);
4561 }
4562
tng_uncompress(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char type,char ** data,const int64_t uncompressed_len)4563 static tng_function_status tng_uncompress(const tng_trajectory_t tng_data,
4564 const tng_gen_block_t block,
4565 const char type,
4566 char **data,
4567 const int64_t uncompressed_len)
4568 {
4569 double *d_dest = 0;
4570 float *f_dest = 0;
4571 int result;
4572 (void)tng_data;
4573
4574 TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0.");
4575
4576 if(block->id != TNG_TRAJ_POSITIONS &&
4577 block->id != TNG_TRAJ_VELOCITIES)
4578 {
4579 fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the"
4580 "TNG method.\n");
4581 return(TNG_FAILURE);
4582 }
4583 if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA)
4584 {
4585 fprintf(stderr, "TNG library: Data type not supported.\n");
4586 return(TNG_FAILURE);
4587 }
4588
4589 if(type == TNG_FLOAT_DATA)
4590 {
4591 f_dest = (float *)malloc(uncompressed_len);
4592 if(!f_dest)
4593 {
4594 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4595 __FILE__, __LINE__);
4596 return(TNG_CRITICAL);
4597 }
4598 result = tng_compress_uncompress_float(*data, f_dest);
4599
4600 free(*data);
4601
4602 *data = (char *)f_dest;
4603 }
4604 else
4605 {
4606 d_dest = (double *)malloc(uncompressed_len);
4607 if(!d_dest)
4608 {
4609 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4610 __FILE__, __LINE__);
4611 return(TNG_CRITICAL);
4612 }
4613 result = tng_compress_uncompress(*data, d_dest);
4614
4615 free(*data);
4616
4617 *data = (char *)d_dest;
4618 }
4619
4620 if(result == 1)
4621 {
4622 fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n");
4623 return(TNG_FAILURE);
4624 }
4625
4626 return(TNG_SUCCESS);
4627 }
4628
tng_gzip_compress(const tng_trajectory_t tng_data,char ** data,const int64_t len,int64_t * new_len)4629 static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
4630 char **data, const int64_t len,
4631 int64_t *new_len)
4632 {
4633 Bytef *dest;
4634 uLongf stat, max_len;
4635 (void)tng_data;
4636
4637 max_len = compressBound(len);
4638 dest = (Bytef *)malloc(max_len);
4639 if(!dest)
4640 {
4641 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4642 __FILE__, __LINE__);
4643 return(TNG_CRITICAL);
4644 }
4645
4646 stat = compress(dest, &max_len, (Bytef *)*data, len);
4647 if(stat != (unsigned long)Z_OK)
4648 {
4649 free(dest);
4650 if(stat == (unsigned long)Z_MEM_ERROR)
4651 {
4652 fprintf(stderr, "TNG library: Not enough memory. ");
4653 }
4654 else if(stat == (unsigned long)Z_BUF_ERROR)
4655 {
4656 fprintf(stderr, "TNG library: Destination buffer too small. ");
4657 }
4658 fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__);
4659 return(TNG_FAILURE);
4660 }
4661
4662 *new_len = max_len;
4663
4664 free(*data);
4665
4666 *data = (char *)dest;
4667
4668 return(TNG_SUCCESS);
4669 }
4670
tng_gzip_uncompress(const tng_trajectory_t tng_data,char ** data,const int64_t compressed_len,const int64_t uncompressed_len)4671 static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data,
4672 char **data,
4673 const int64_t compressed_len,
4674 const int64_t uncompressed_len)
4675 {
4676 Bytef *dest;
4677 unsigned long stat;
4678 (void)tng_data;
4679 uLongf new_len = uncompressed_len;
4680
4681 dest = (Bytef *)malloc(uncompressed_len);
4682 if(!dest)
4683 {
4684 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4685 __FILE__, __LINE__);
4686 return(TNG_CRITICAL);
4687 }
4688
4689 stat = uncompress(dest, &new_len, (Bytef *) *data,
4690 compressed_len);
4691
4692 if(stat != Z_OK)
4693 {
4694 free(dest);
4695 if(stat == (unsigned long)Z_MEM_ERROR)
4696 {
4697 fprintf(stderr, "TNG library: Not enough memory. ");
4698 }
4699 else if(stat == (unsigned long)Z_BUF_ERROR)
4700 {
4701 fprintf(stderr, "TNG library: Destination buffer too small. ");
4702 }
4703 else if(stat == (unsigned long)Z_DATA_ERROR)
4704 {
4705 fprintf(stderr, "TNG library: Data corrupt. ");
4706 }
4707 fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__,
4708 __LINE__);
4709 return(TNG_FAILURE);
4710 }
4711
4712 free(*data);
4713
4714 *data = (char *)dest;
4715
4716 return(TNG_SUCCESS);
4717 }
4718
4719 /**
4720 * @brief Allocate memory for storing particle data.
4721 * The allocated block will be refered to by data->values.
4722 * @param tng_data is a trajectory data container.
4723 * @param data is the data struct, which will contain the allocated memory in
4724 * data->values.
4725 * @param n_frames is the number of frames of data to store.
4726 * @param n_particles is the number of particles with data.
4727 * @param n_values_per_frame is the number of data values per particle and
4728 * frame.
4729 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
4730 * error has occured.
4731 */
tng_allocate_particle_data_mem(const tng_trajectory_t tng_data,const tng_data_t data,int64_t n_frames,const int64_t stride_length,const int64_t n_particles,const int64_t n_values_per_frame)4732 static tng_function_status tng_allocate_particle_data_mem
4733 (const tng_trajectory_t tng_data,
4734 const tng_data_t data,
4735 int64_t n_frames,
4736 const int64_t stride_length,
4737 const int64_t n_particles,
4738 const int64_t n_values_per_frame)
4739 {
4740 void ***values;
4741 int64_t i, j, k, size, frame_alloc;
4742 (void)tng_data;
4743
4744 if(n_particles == 0 || n_values_per_frame == 0)
4745 {
4746 return(TNG_FAILURE);
4747 }
4748
4749 if(data->strings && data->datatype == TNG_CHAR_DATA)
4750 {
4751 for(i = 0; i < data->n_frames; i++)
4752 {
4753 for(j = 0; j < n_particles; j++)
4754 {
4755 for(k = 0; k < data->n_values_per_frame; k++)
4756 {
4757 if(data->strings[i][j][k])
4758 {
4759 free(data->strings[i][j][k]);
4760 }
4761 }
4762 free(data->strings[i][j]);
4763 }
4764 free(data->strings[i]);
4765 }
4766 free(data->strings);
4767 }
4768 data->n_frames = n_frames;
4769 n_frames = tng_max_i64(1, n_frames);
4770 data->stride_length = tng_max_i64(1, stride_length);
4771 data->n_values_per_frame = n_values_per_frame;
4772 frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
4773
4774 if(data->datatype == TNG_CHAR_DATA)
4775 {
4776 data->strings = (char ****)malloc(sizeof(char ***) * frame_alloc);
4777 for(i = 0; i < frame_alloc; i++)
4778 {
4779 data->strings[i] = (char ***)malloc(sizeof(char **) *
4780 n_particles);
4781 if(!data->strings[i])
4782 {
4783 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4784 __FILE__, __LINE__);
4785 return(TNG_CRITICAL);
4786 }
4787 for(j = 0; j < n_particles; j++)
4788 {
4789 data->strings[i][j] = (char **)malloc(sizeof(char *) *
4790 n_values_per_frame);
4791 if(!data->strings[i][j])
4792 {
4793 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4794 __FILE__, __LINE__);
4795 return(TNG_CRITICAL);
4796 }
4797 for(k = 0; k < n_values_per_frame; k++)
4798 {
4799 data->strings[i][j][k] = 0;
4800 }
4801 }
4802 }
4803 }
4804 else
4805 {
4806 switch(data->datatype)
4807 {
4808 case TNG_INT_DATA:
4809 size = sizeof(int64_t);
4810 break;
4811 case TNG_FLOAT_DATA:
4812 size = sizeof(float);
4813 break;
4814 case TNG_DOUBLE_DATA:
4815 default:
4816 size = sizeof(double);
4817 }
4818
4819 values = (void ***)realloc(data->values,
4820 size * frame_alloc *
4821 n_particles * n_values_per_frame);
4822 if(!values)
4823 {
4824 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
4825 __FILE__, __LINE__);
4826 free(data->values);
4827 data->values = 0;
4828 return(TNG_CRITICAL);
4829 }
4830 data->values = values;
4831 }
4832 return(TNG_SUCCESS);
4833 }
4834
tng_particle_data_find(const tng_trajectory_t tng_data,const int64_t id,tng_data_t * data)4835 static tng_function_status tng_particle_data_find
4836 (const tng_trajectory_t tng_data,
4837 const int64_t id,
4838 tng_data_t *data)
4839 {
4840 int64_t block_index, i;
4841 tng_trajectory_frame_set_t frame_set = &tng_data->
4842 current_trajectory_frame_set;
4843 char block_type_flag;
4844
4845 if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4846 tng_data->current_trajectory_frame_set_output_file_pos > 0)
4847 {
4848 block_type_flag = TNG_TRAJECTORY_BLOCK;
4849 }
4850 else
4851 {
4852 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4853 }
4854
4855 block_index = -1;
4856 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4857 {
4858 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
4859 {
4860 *data = &frame_set->tr_particle_data[i];
4861 if((*data)->block_id == id)
4862 {
4863 block_index = i;
4864 break;
4865 }
4866 }
4867 }
4868 else
4869 {
4870 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
4871 {
4872 *data = &tng_data->non_tr_particle_data[i];
4873 if((*data)->block_id == id)
4874 {
4875 block_index = i;
4876 break;
4877 }
4878 }
4879 }
4880 if(block_index == -1)
4881 {
4882 return(TNG_FAILURE);
4883 }
4884 return(TNG_SUCCESS);
4885 }
4886
tng_data_find(const tng_trajectory_t tng_data,const int64_t id,tng_data_t * data)4887 static tng_function_status tng_data_find
4888 (const tng_trajectory_t tng_data,
4889 const int64_t id,
4890 tng_data_t *data)
4891 {
4892 int64_t block_index, i;
4893 tng_trajectory_frame_set_t frame_set = &tng_data->
4894 current_trajectory_frame_set;
4895 char block_type_flag;
4896
4897 if(tng_data->current_trajectory_frame_set_input_file_pos > 0 ||
4898 tng_data->current_trajectory_frame_set_output_file_pos > 0)
4899 {
4900 block_type_flag = TNG_TRAJECTORY_BLOCK;
4901 }
4902 else
4903 {
4904 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
4905 }
4906
4907 block_index = -1;
4908 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
4909 {
4910 for(i = 0; i < frame_set->n_data_blocks; i++)
4911 {
4912 *data = &frame_set->tr_data[i];
4913 if((*data)->block_id == id)
4914 {
4915 block_index = i;
4916 break;
4917 }
4918 }
4919 if(block_index == -1)
4920 {
4921 for(i = 0; i < tng_data->n_data_blocks; i++)
4922 {
4923 *data = &tng_data->non_tr_data[i];
4924 if((*data)->block_id == id)
4925 {
4926 block_index = i;
4927 break;
4928 }
4929 }
4930 }
4931 }
4932 else
4933 {
4934 for(i = 0; i < tng_data->n_data_blocks; i++)
4935 {
4936 *data = &tng_data->non_tr_data[i];
4937 if((*data)->block_id == id)
4938 {
4939 block_index = i;
4940 break;
4941 }
4942 }
4943 }
4944 if(block_index == -1)
4945 {
4946 return(TNG_FAILURE);
4947 }
4948 return(TNG_SUCCESS);
4949 }
4950
tng_data_block_len_calculate(const tng_trajectory_t tng_data,const tng_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,int64_t * data_start_pos,int64_t * len)4951 static tng_function_status tng_data_block_len_calculate
4952 (const tng_trajectory_t tng_data,
4953 const tng_data_t data,
4954 const tng_bool is_particle_data,
4955 const int64_t n_frames,
4956 const int64_t frame_step,
4957 const int64_t stride_length,
4958 const int64_t num_first_particle,
4959 const int64_t n_particles,
4960 int64_t *data_start_pos,
4961 int64_t *len)
4962 {
4963 int size;
4964 int64_t i, j, k;
4965 char ***first_dim_values, **second_dim_values;
4966 (void)tng_data;
4967
4968 if(data == 0)
4969 {
4970 return(TNG_SUCCESS);
4971 }
4972
4973 switch(data->datatype)
4974 {
4975 case TNG_CHAR_DATA:
4976 size = 1;
4977 break;
4978 case TNG_INT_DATA:
4979 size = sizeof(int64_t);
4980 break;
4981 case TNG_FLOAT_DATA:
4982 size = sizeof(float);
4983 break;
4984 case TNG_DOUBLE_DATA:
4985 default:
4986 size = sizeof(double);
4987 }
4988
4989 *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) +
4990 sizeof(data->codec_id);
4991 if(is_particle_data)
4992 {
4993 *len += sizeof(num_first_particle) + sizeof(n_particles);
4994 }
4995
4996 if(stride_length > 1)
4997 {
4998 *len += sizeof(data->first_frame_with_data) +
4999 sizeof(data->stride_length);
5000 }
5001
5002 if(data->codec_id != TNG_UNCOMPRESSED)
5003 {
5004 *len += sizeof(data->compression_multiplier);
5005 }
5006
5007 if(data->dependency & TNG_FRAME_DEPENDENT)
5008 {
5009 *len += sizeof(char);
5010 }
5011
5012 *data_start_pos = *len;
5013
5014 if(data->datatype == TNG_CHAR_DATA)
5015 {
5016 if(is_particle_data)
5017 {
5018 for(i = 0; i < n_frames; i++)
5019 {
5020 first_dim_values = data->strings[i];
5021 for(j = num_first_particle; j < num_first_particle + n_particles;
5022 j++)
5023 {
5024 second_dim_values = first_dim_values[j];
5025 for(k = 0; k < data->n_values_per_frame; k++)
5026 {
5027 *len += strlen(second_dim_values[k]) + 1;
5028 }
5029 }
5030 }
5031 }
5032 else
5033 {
5034 for(i = 0; i < n_frames; i++)
5035 {
5036 second_dim_values = data->strings[0][i];
5037 for(j = 0; j < data->n_values_per_frame; j++)
5038 {
5039 *len += strlen(second_dim_values[j]) + 1;
5040 }
5041 }
5042 }
5043 }
5044 else
5045 {
5046 *len += size * frame_step * n_particles * data->n_values_per_frame;
5047 }
5048
5049 return(TNG_SUCCESS);
5050 }
5051
5052 /* TEST: */
5053 /**
5054 * @brief Create a non-particle data block
5055 * @param tng_data is a trajectory data container.
5056 * @param block_type_flag specifies if this is a trajectory block or a
5057 * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK)
5058 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5059 * error has occured.
5060 */
tng_data_block_create(const tng_trajectory_t tng_data,const char block_type_flag)5061 static tng_function_status tng_data_block_create
5062 (const tng_trajectory_t tng_data,
5063 const char block_type_flag)
5064 {
5065 tng_trajectory_frame_set_t frame_set =
5066 &tng_data->current_trajectory_frame_set;
5067
5068 tng_data_t data;
5069
5070 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5071 {
5072 frame_set->n_data_blocks++;
5073 data = (tng_data_t)realloc(frame_set->tr_data, sizeof(struct tng_data) *
5074 frame_set->n_data_blocks);
5075 if(!data)
5076 {
5077 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5078 __FILE__, __LINE__);
5079 free(frame_set->tr_data);
5080 frame_set->tr_data = 0;
5081 return(TNG_CRITICAL);
5082 }
5083 frame_set->tr_data = data;
5084 }
5085 else
5086 {
5087 tng_data->n_data_blocks++;
5088 data = (tng_data_t)realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
5089 tng_data->n_data_blocks);
5090 if(!data)
5091 {
5092 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5093 __FILE__, __LINE__);
5094 free(tng_data->non_tr_data);
5095 tng_data->non_tr_data = 0;
5096 return(TNG_CRITICAL);
5097 }
5098 tng_data->non_tr_data = data;
5099 }
5100
5101 return(TNG_SUCCESS);
5102 }
5103
5104 /* TEST: */
5105 /**
5106 * @brief Allocate memory for storing non-particle data.
5107 * The allocated block will be refered to by data->values.
5108 * @param tng_data is a trajectory data container.
5109 * @param data is the data struct, which will contain the allocated memory in
5110 * data->values.
5111 * @param n_frames is the number of frames of data to store.
5112 * @param n_values_per_frame is the number of data values per frame.
5113 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5114 * error has occured.
5115 */
tng_allocate_data_mem(const tng_trajectory_t tng_data,const tng_data_t data,int64_t n_frames,const int64_t stride_length,const int64_t n_values_per_frame)5116 static tng_function_status tng_allocate_data_mem
5117 (const tng_trajectory_t tng_data,
5118 const tng_data_t data,
5119 int64_t n_frames,
5120 const int64_t stride_length,
5121 const int64_t n_values_per_frame)
5122 {
5123 void **values;
5124 int64_t i, j, size, frame_alloc;
5125 (void)tng_data;
5126
5127 if(n_values_per_frame == 0)
5128 {
5129 return(TNG_FAILURE);
5130 }
5131
5132 if(data->strings && data->datatype == TNG_CHAR_DATA)
5133 {
5134 for(i = 0; i < data->n_frames; i++)
5135 {
5136 for(j = 0; j < data->n_values_per_frame; j++)
5137 {
5138 if(data->strings[0][i][j])
5139 {
5140 free(data->strings[0][i][j]);
5141 data->strings[0][i][j] = 0;
5142 }
5143 }
5144 free(data->strings[0][i]);
5145 data->strings[0][i] = 0;
5146 }
5147 free(data->strings[0]);
5148 data->strings[0] = 0;
5149 free(data->strings);
5150 }
5151 data->n_frames = n_frames;
5152 data->stride_length = tng_max_i64(1, stride_length);
5153 n_frames = tng_max_i64(1, n_frames);
5154 data->n_values_per_frame = n_values_per_frame;
5155 frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5156
5157 if(data->datatype == TNG_CHAR_DATA)
5158 {
5159 data->strings = (char ****)malloc(sizeof(char ***));
5160 data->strings[0] = (char ***)malloc(sizeof(char **) * frame_alloc);
5161 for(i = 0; i < frame_alloc; i++)
5162 {
5163 data->strings[0][i] = (char **)malloc(sizeof(char *) * n_values_per_frame);
5164 if(!data->strings[0][i])
5165 {
5166 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5167 __FILE__, __LINE__);
5168 return(TNG_CRITICAL);
5169 }
5170 for(j = 0; j < n_values_per_frame; j++)
5171 {
5172 data->strings[0][i][j] = 0;
5173 }
5174 }
5175 }
5176 else
5177 {
5178 switch(data->datatype)
5179 {
5180 case TNG_INT_DATA:
5181 size = sizeof(int64_t);
5182 break;
5183 case TNG_FLOAT_DATA:
5184 size = sizeof(float);
5185 break;
5186 case TNG_DOUBLE_DATA:
5187 default:
5188 size = sizeof(double);
5189 }
5190
5191 values = (void **)realloc(data->values,
5192 size * frame_alloc *
5193 n_values_per_frame);
5194 if(!values)
5195 {
5196 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5197 __FILE__, __LINE__);
5198 free(data->values);
5199 data->values = 0;
5200 return(TNG_CRITICAL);
5201 }
5202 data->values = values;
5203 }
5204
5205 return(TNG_SUCCESS);
5206 }
5207
5208 /**
5209 * @brief Read the values of a data block
5210 * @param tng_data is a trajectory data container.
5211 * @param block is the block to store the data (should already contain
5212 * the block headers and the block contents).
5213 * @param block_data_len is the length of the data contents of the block.
5214 * @param datatype is the type of data of the data block (char, int, float or
5215 * double).
5216 * @param num_first_particle is the number of the first particle in the data
5217 * block. This should be the same as in the corresponding particle mapping
5218 * block. Only used if reading particle dependent data.
5219 * @param n_particles is the number of particles in the data block. This should
5220 * be the same as in the corresponding particle mapping block. Only used if
5221 * reading particle dependent data.
5222 * @param first_frame_with_data is the frame number of the first frame with data
5223 * in this data block.
5224 * @param stride_length is the number of frames between each data entry.
5225 * @param n_frames is the number of frames in this data block.
5226 * @param n_values is the number of values per frame stored in this data block.
5227 * @param codec_id is the ID of the codec to compress the data.
5228 * @param multiplier is the multiplication factor applied to each data value
5229 * before compression. This factor is applied since some compression algorithms
5230 * work only on integers.
5231 * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes.
5232 * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately
5233 * if hash_mode == TNG_USE_HASH.
5234 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5235 * error has occured.
5236 */
tng_data_read(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int64_t block_data_len,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,const char hash_mode,md5_state_t * md5_state)5237 static tng_function_status tng_data_read(const tng_trajectory_t tng_data,
5238 const tng_gen_block_t block,
5239 const int64_t block_data_len,
5240 const char datatype,
5241 const int64_t num_first_particle,
5242 const int64_t n_particles,
5243 const int64_t first_frame_with_data,
5244 const int64_t stride_length,
5245 int64_t n_frames,
5246 const int64_t n_values,
5247 const int64_t codec_id,
5248 const double multiplier,
5249 const char hash_mode,
5250 md5_state_t *md5_state)
5251 {
5252 int64_t i, j, k, tot_n_particles, n_frames_div, offset;
5253 int64_t full_data_len;
5254 int size, len;
5255 char ***first_dim_values, **second_dim_values;
5256 tng_data_t data;
5257 tng_trajectory_frame_set_t frame_set =
5258 &tng_data->current_trajectory_frame_set;
5259 char block_type_flag, *contents;
5260 tng_bool is_particle_data;
5261 tng_function_status stat;
5262
5263 /* fprintf(stderr, "TNG library: %s\n", block->name);*/
5264
5265 switch(datatype)
5266 {
5267 case TNG_CHAR_DATA:
5268 size = 1;
5269 break;
5270 case TNG_INT_DATA:
5271 size = sizeof(int64_t);
5272 break;
5273 case TNG_FLOAT_DATA:
5274 size = sizeof(float);
5275 break;
5276 case TNG_DOUBLE_DATA:
5277 default:
5278 size = sizeof(double);
5279 }
5280
5281 if(n_particles > 0)
5282 {
5283 is_particle_data = TNG_TRUE;
5284 }
5285 else
5286 {
5287 if(codec_id == TNG_XTC_COMPRESSION || codec_id == TNG_TNG_COMPRESSION)
5288 {
5289 fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
5290 __LINE__);
5291 return(TNG_FAILURE);
5292 }
5293 is_particle_data = TNG_FALSE;
5294 }
5295
5296 if(is_particle_data == TNG_TRUE)
5297 {
5298 stat = tng_particle_data_find(tng_data, block->id, &data);
5299 }
5300 else
5301 {
5302 stat = tng_data_find(tng_data, block->id, &data);
5303 }
5304
5305 if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
5306 {
5307 block_type_flag = TNG_TRAJECTORY_BLOCK;
5308 }
5309 else
5310 {
5311 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5312 }
5313
5314 /* If the block does not exist, create it */
5315 if(stat != TNG_SUCCESS)
5316 {
5317 if(is_particle_data == TNG_TRUE)
5318 {
5319 stat = tng_particle_data_block_create(tng_data, block_type_flag);
5320 }
5321 else
5322 {
5323 stat = tng_data_block_create(tng_data, block_type_flag);
5324 }
5325
5326 if(stat != TNG_SUCCESS)
5327 {
5328 fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n",
5329 __FILE__, __LINE__);
5330 return(TNG_CRITICAL);
5331 }
5332
5333 if(is_particle_data == TNG_TRUE)
5334 {
5335 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5336 {
5337 data = &frame_set->tr_particle_data[frame_set->
5338 n_particle_data_blocks - 1];
5339 }
5340 else
5341 {
5342 data = &tng_data->non_tr_particle_data[tng_data->
5343 n_particle_data_blocks - 1];
5344 }
5345 }
5346 else
5347 {
5348 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5349 {
5350 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
5351 }
5352 else
5353 {
5354 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
5355 }
5356 }
5357
5358 data->block_id = block->id;
5359
5360 data->block_name = (char *)malloc(strlen(block->name) + 1);
5361 if(!data->block_name)
5362 {
5363 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5364 __FILE__, __LINE__);
5365 return(TNG_CRITICAL);
5366 }
5367 strcpy(data->block_name, block->name);
5368
5369 data->datatype = datatype;
5370
5371 data->values = 0;
5372 /* FIXME: Memory leak from strings. */
5373 data->strings = 0;
5374 data->n_frames = 0;
5375 data->dependency = 0;
5376 if(is_particle_data == TNG_TRUE)
5377 {
5378 data->dependency += TNG_PARTICLE_DEPENDENT;
5379 }
5380 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5381 (n_frames > 1 ||
5382 frame_set->n_frames == n_frames ||
5383 stride_length > 1))
5384 {
5385 data->dependency += TNG_FRAME_DEPENDENT;
5386 }
5387 data->codec_id = codec_id;
5388 data->compression_multiplier = multiplier;
5389 data->last_retrieved_frame = -1;
5390 }
5391
5392 if(is_particle_data == TNG_TRUE)
5393 {
5394 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
5395 tng_data->var_num_atoms_flag)
5396 {
5397 tot_n_particles = frame_set->n_particles;
5398 }
5399 else
5400 {
5401 tot_n_particles = tng_data->n_particles;
5402 }
5403 }
5404 /* If there are no particles in this data block, still set tot_n_particles = 1
5405 * to calculate block lengths etc properly. */
5406 else
5407 {
5408 tot_n_particles = 1;
5409 }
5410
5411 n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
5412
5413 contents = (char *)malloc(block_data_len);
5414 if(!contents)
5415 {
5416 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5417 __FILE__, __LINE__);
5418 return(TNG_CRITICAL);
5419 }
5420
5421 if(fread(contents, block_data_len, 1, tng_data->input_file) == 0)
5422 {
5423 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
5424 return(TNG_CRITICAL);
5425 }
5426
5427 if(hash_mode == TNG_USE_HASH)
5428 {
5429 md5_append(md5_state, (md5_byte_t *)contents, block_data_len);
5430 }
5431
5432 if(codec_id != TNG_UNCOMPRESSED)
5433 {
5434 full_data_len = n_frames_div * size * n_values;
5435 if(is_particle_data == TNG_TRUE)
5436 {
5437 full_data_len *= n_particles;
5438 }
5439 switch(codec_id)
5440 {
5441 case TNG_XTC_COMPRESSION:
5442 fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
5443 break;
5444 case TNG_TNG_COMPRESSION:
5445 /* fprintf(stderr, "TNG library: Before TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
5446 if(tng_uncompress(tng_data, block, datatype,
5447 &contents, full_data_len) != TNG_SUCCESS)
5448 {
5449 fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n",
5450 __FILE__, __LINE__);
5451 free(contents);
5452 return(TNG_CRITICAL);
5453 }
5454 /* fprintf(stderr, "TNG library: After TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
5455 break;
5456 case TNG_GZIP_COMPRESSION:
5457 /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
5458 if(tng_gzip_uncompress(tng_data, &contents,
5459 block_data_len, full_data_len) != TNG_SUCCESS)
5460 {
5461 fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__,
5462 __LINE__);
5463 free(contents);
5464 return(TNG_CRITICAL);
5465 }
5466 /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
5467 break;
5468 }
5469 }
5470 else
5471 {
5472 full_data_len = block_data_len;
5473 }
5474
5475 /* Allocate memory */
5476 if(!data->values || data->n_frames != n_frames ||
5477 data->n_values_per_frame != n_values)
5478 {
5479 if(is_particle_data == TNG_TRUE)
5480 {
5481 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
5482 stride_length,
5483 tot_n_particles, n_values);
5484 }
5485 else
5486 {
5487 stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
5488 n_values);
5489 }
5490 if(stat != TNG_SUCCESS)
5491 {
5492 fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n",
5493 __FILE__, __LINE__);
5494 free(contents);
5495 return(TNG_CRITICAL);
5496 }
5497 }
5498
5499 data->first_frame_with_data = first_frame_with_data;
5500
5501 if(datatype == TNG_CHAR_DATA)
5502 {
5503 offset = 0;
5504 /* Strings are stores slightly differently if the data block contains particle
5505 * data (frames * particles * n_values) or not (frames * n_values). */
5506 if(is_particle_data == TNG_TRUE)
5507 {
5508 for(i = 0; i < n_frames_div; i++)
5509 {
5510 first_dim_values = data->strings[i];
5511 for(j = num_first_particle; j < num_first_particle + n_particles;
5512 j++)
5513 {
5514 second_dim_values = first_dim_values[j];
5515 for(k = 0; k < n_values; k++)
5516 {
5517 len = tng_min_size(strlen(contents+offset) + 1,
5518 TNG_MAX_STR_LEN);
5519 if(second_dim_values[k])
5520 {
5521 free(second_dim_values[k]);
5522 }
5523 second_dim_values[k] = (char *)malloc(len);
5524 if(!second_dim_values[k])
5525 {
5526 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5527 __FILE__, __LINE__);
5528 free(contents);
5529 return(TNG_CRITICAL);
5530 }
5531 strncpy(second_dim_values[k], contents+offset, len);
5532 offset += len;
5533 }
5534 }
5535 }
5536 }
5537 else
5538 {
5539 for(i = 0; i < n_frames_div; i++)
5540 {
5541 for(j = 0; j < n_values; j++)
5542 {
5543 len = tng_min_size(strlen(contents+offset) + 1,
5544 TNG_MAX_STR_LEN);
5545 if(data->strings[0][i][j])
5546 {
5547 free(data->strings[0][i][j]);
5548 }
5549 data->strings[0][i][j] = (char *)malloc(len);
5550 if(!data->strings[0][i][j])
5551 {
5552 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5553 __FILE__, __LINE__);
5554 free(contents);
5555 return(TNG_CRITICAL);
5556 }
5557 strncpy(data->strings[0][i][j], contents+offset, len);
5558 offset += len;
5559 }
5560 }
5561 }
5562 }
5563 else
5564 {
5565 if(is_particle_data)
5566 {
5567 memcpy((char *)data->values + n_frames_div * size * n_values *
5568 num_first_particle, contents, full_data_len);
5569 }
5570 else
5571 {
5572 memcpy(data->values, contents, full_data_len);
5573 }
5574 /* Endianness is handled by the TNG compression library. TNG compressed blocks are always written
5575 * as little endian by the compression library. */
5576 if(codec_id != TNG_TNG_COMPRESSION)
5577 {
5578 switch(datatype)
5579 {
5580 case TNG_FLOAT_DATA:
5581 if(tng_data->input_endianness_swap_func_32)
5582 {
5583 for(i = 0; i < full_data_len; i+=size)
5584 {
5585 if(tng_data->input_endianness_swap_func_32(tng_data,
5586 (uint32_t *)((char *)data->values + i))
5587 != TNG_SUCCESS)
5588 {
5589 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5590 __FILE__, __LINE__);
5591 }
5592 }
5593 }
5594 break;
5595 case TNG_INT_DATA:
5596 case TNG_DOUBLE_DATA:
5597 if(tng_data->input_endianness_swap_func_64)
5598 {
5599 for(i = 0; i < full_data_len; i+=size)
5600 {
5601 if(tng_data->input_endianness_swap_func_64(tng_data,
5602 (uint64_t *)((char *)data->values + i))
5603 != TNG_SUCCESS)
5604 {
5605 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
5606 __FILE__, __LINE__);
5607 }
5608 }
5609 }
5610 break;
5611 case TNG_CHAR_DATA:
5612 break;
5613 }
5614 }
5615 }
5616
5617 free(contents);
5618
5619 return(TNG_SUCCESS);
5620 }
5621
5622 /**
5623 * @brief Write a data block (particle or non-particle data)
5624 * @param tng_data is a trajectory data container.
5625 * @param block is the block to store the data (should already contain
5626 * the block headers and the block contents).
5627 * @param block_index is the index number of the data block in the frame set.
5628 * @param is_particle_data is a flag to specify if the data to write is
5629 * particle dependent or not.
5630 * @param mapping is the particle mapping that is relevant for the data block.
5631 * Only relevant if writing particle dependent data.
5632 * @param hash_mode is an option to decide whether to use the md5 hash or not.
5633 * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written.
5634 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
5635 * error has occured.
5636 */
tng_data_block_write(const tng_trajectory_t tng_data,const tng_gen_block_t block,const int64_t block_index,const tng_bool is_particle_data,const tng_particle_mapping_t mapping,const char hash_mode)5637 static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data,
5638 const tng_gen_block_t block,
5639 const int64_t block_index,
5640 const tng_bool is_particle_data,
5641 const tng_particle_mapping_t mapping,
5642 const char hash_mode)
5643 {
5644 int64_t n_particles, num_first_particle, n_frames, stride_length;
5645 int64_t full_data_len, block_data_len, frame_step, data_start_pos;
5646 int64_t i, j, k, curr_file_pos, header_file_pos;
5647 int size;
5648 size_t len;
5649 tng_function_status stat;
5650 char temp, *temp_name, ***first_dim_values, **second_dim_values, *contents;
5651 double multiplier;
5652 tng_trajectory_frame_set_t frame_set =
5653 &tng_data->current_trajectory_frame_set;
5654 tng_data_t data;
5655 char block_type_flag;
5656 md5_state_t md5_state;
5657
5658 /* If we have already started writing frame sets it is too late to write
5659 * non-trajectory data blocks */
5660 if(tng_data->current_trajectory_frame_set_output_file_pos > 0)
5661 {
5662 block_type_flag = TNG_TRAJECTORY_BLOCK;
5663 }
5664 else
5665 {
5666 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
5667 }
5668
5669 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
5670 {
5671 return(TNG_CRITICAL);
5672 }
5673
5674 if(is_particle_data == TNG_TRUE)
5675 {
5676 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5677 {
5678 data = &frame_set->tr_particle_data[block_index];
5679
5680 /* If this data block has not had any data added in this frame set
5681 * do not write it. */
5682 if(data->first_frame_with_data < frame_set->first_frame)
5683 {
5684 return(TNG_SUCCESS);
5685 }
5686
5687 stride_length = tng_max_i64(1, data->stride_length);
5688 }
5689 else
5690 {
5691 data = &tng_data->non_tr_particle_data[block_index];
5692 stride_length = 1;
5693 }
5694 }
5695 else
5696 {
5697 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5698 {
5699 data = &frame_set->tr_data[block_index];
5700
5701 /* If this data block has not had any data added in this frame set
5702 * do not write it. */
5703 if(data->first_frame_with_data < frame_set->first_frame)
5704 {
5705 return(TNG_SUCCESS);
5706 }
5707
5708 stride_length = tng_max_i64(1, data->stride_length);
5709 }
5710 else
5711 {
5712 data = &tng_data->non_tr_data[block_index];
5713 stride_length = 1;
5714 }
5715 }
5716
5717 switch(data->datatype)
5718 {
5719 case TNG_CHAR_DATA:
5720 size = 1;
5721 break;
5722 case TNG_INT_DATA:
5723 size = sizeof(int64_t);
5724 break;
5725 case TNG_FLOAT_DATA:
5726 size = sizeof(float);
5727 break;
5728 case TNG_DOUBLE_DATA:
5729 default:
5730 size = sizeof(double);
5731 }
5732
5733 len = strlen(data->block_name) + 1;
5734
5735 if(!block->name || strlen(block->name) < len)
5736 {
5737 temp_name = (char *)realloc(block->name, len);
5738 if(!temp_name)
5739 {
5740 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
5741 __FILE__, __LINE__);
5742 free(block->name);
5743 block->name = 0;
5744 return(TNG_CRITICAL);
5745 }
5746 block->name = temp_name;
5747 }
5748 strncpy(block->name, data->block_name, len);
5749 block->id = data->block_id;
5750
5751 /* If writing frame independent data data->n_frames is 0, but n_frames
5752 is used for the loop writing the data (and reserving memory) and needs
5753 to be at least 1 */
5754 n_frames = tng_max_i64(1, data->n_frames);
5755
5756 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
5757 {
5758 /* If the frame set is finished before writing the full number of frames
5759 make sure the data block is not longer than the frame set. */
5760 n_frames = tng_min_i64(n_frames, frame_set->n_frames);
5761
5762 n_frames -= (data->first_frame_with_data - frame_set->first_frame);
5763 }
5764
5765 frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1:
5766 n_frames / stride_length;
5767
5768 /* TNG compression will use compression precision to get integers from
5769 * floating point data. The compression multiplier stores that information
5770 * to be able to return the precision of the compressed data. */
5771 if(data->codec_id == TNG_TNG_COMPRESSION)
5772 {
5773 data->compression_multiplier = tng_data->compression_precision;
5774 }
5775 /* Uncompressed data blocks do not use compression multipliers at all.
5776 * GZip compression does not need it either. */
5777 else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
5778 {
5779 data->compression_multiplier = 1.0;
5780 }
5781
5782 if(data->dependency & TNG_PARTICLE_DEPENDENT)
5783 {
5784 if(mapping && mapping->n_particles != 0)
5785 {
5786 n_particles = mapping->n_particles;
5787 num_first_particle = mapping->num_first_particle;
5788 }
5789 else
5790 {
5791 num_first_particle = 0;
5792 if(tng_data->var_num_atoms_flag)
5793 {
5794 n_particles = frame_set->n_particles;
5795 }
5796 else
5797 {
5798 n_particles = tng_data->n_particles;
5799 }
5800 }
5801 }
5802 else
5803 {
5804 /* This just appeases gcc-7 -Wmaybe-uninitialized.
5805 * FIXME: It would be better to refactor so that
5806 * TNG_PARTICLE_DEPENDENT triggers two distinct code paths.
5807 */
5808 num_first_particle = -1;
5809 n_particles = -1;
5810 }
5811
5812 if(data->dependency & TNG_PARTICLE_DEPENDENT)
5813 {
5814 if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames,
5815 frame_step, stride_length, num_first_particle,
5816 n_particles, &data_start_pos,
5817 &block->block_contents_size) != TNG_SUCCESS)
5818 {
5819 fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n",
5820 __FILE__, __LINE__);
5821 return(TNG_CRITICAL);
5822 }
5823 }
5824 else
5825 {
5826 if(tng_data_block_len_calculate(tng_data, data, TNG_FALSE, n_frames,
5827 frame_step, stride_length, 0,
5828 1, &data_start_pos,
5829 &block->block_contents_size) != TNG_SUCCESS)
5830 {
5831 fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n",
5832 __FILE__, __LINE__);
5833 return(TNG_CRITICAL);
5834 }
5835 }
5836
5837 header_file_pos = ftello(tng_data->output_file);
5838
5839 if(tng_block_header_write(tng_data, block) != TNG_SUCCESS)
5840 {
5841 fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n",
5842 tng_data->output_file_path, __FILE__, __LINE__);
5843 return(TNG_CRITICAL);
5844 }
5845
5846 if(hash_mode == TNG_USE_HASH)
5847 {
5848 md5_init(&md5_state);
5849 }
5850
5851 if(tng_file_output_numerical(tng_data, &data->datatype,
5852 sizeof(data->datatype),
5853 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5854 {
5855 return(TNG_CRITICAL);
5856 }
5857
5858 if(tng_file_output_numerical(tng_data, &data->dependency,
5859 sizeof(data->dependency),
5860 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5861 {
5862 return(TNG_CRITICAL);
5863 }
5864
5865 if(data->dependency & TNG_FRAME_DEPENDENT)
5866 {
5867 if(stride_length > 1)
5868 {
5869 temp = 1;
5870 }
5871 else
5872 {
5873 temp = 0;
5874 }
5875 if(tng_file_output_numerical(tng_data, &temp,
5876 sizeof(temp),
5877 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5878 {
5879 return(TNG_CRITICAL);
5880 }
5881 }
5882
5883 if(tng_file_output_numerical(tng_data, &data->n_values_per_frame,
5884 sizeof(data->n_values_per_frame),
5885 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5886 {
5887 return(TNG_CRITICAL);
5888 }
5889
5890 if(tng_file_output_numerical(tng_data, &data->codec_id,
5891 sizeof(data->codec_id),
5892 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5893 {
5894 return(TNG_CRITICAL);
5895 }
5896
5897 if(data->codec_id != TNG_UNCOMPRESSED)
5898 {
5899 if(tng_file_output_numerical(tng_data, &data->compression_multiplier,
5900 sizeof(data->compression_multiplier),
5901 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5902 {
5903 return(TNG_CRITICAL);
5904 }
5905 }
5906
5907 if(data->n_frames > 0 && stride_length > 1)
5908 {
5909 /* FIXME: first_frame_with_data is not reliably set */
5910 if(data->first_frame_with_data == 0)
5911 {
5912 data->first_frame_with_data = frame_set->first_frame;
5913 }
5914 if(tng_file_output_numerical(tng_data, &data->first_frame_with_data,
5915 sizeof(data->first_frame_with_data),
5916 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5917 {
5918 return(TNG_CRITICAL);
5919 }
5920
5921 if(tng_file_output_numerical(tng_data, &stride_length,
5922 sizeof(stride_length),
5923 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5924 {
5925 return(TNG_CRITICAL);
5926 }
5927 }
5928
5929 if(data->dependency & TNG_PARTICLE_DEPENDENT)
5930 {
5931 if(tng_file_output_numerical(tng_data, &num_first_particle,
5932 sizeof(num_first_particle),
5933 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5934 {
5935 return(TNG_CRITICAL);
5936 }
5937
5938 if(tng_file_output_numerical(tng_data, &n_particles,
5939 sizeof(n_particles),
5940 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5941 {
5942 return(TNG_CRITICAL);
5943 }
5944 }
5945
5946 if(data->datatype == TNG_CHAR_DATA)
5947 {
5948 if(data->strings)
5949 {
5950 if(data->dependency & TNG_PARTICLE_DEPENDENT)
5951 {
5952 for(i = 0; i < frame_step; i++)
5953 {
5954 first_dim_values = data->strings[i];
5955 for(j = num_first_particle; j < num_first_particle + n_particles;
5956 j++)
5957 {
5958 second_dim_values = first_dim_values[j];
5959 for(k = 0; k < data->n_values_per_frame; k++)
5960 {
5961 if(tng_fwritestr(tng_data, second_dim_values[k],
5962 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5963 {
5964 return(TNG_CRITICAL);
5965 }
5966 }
5967 }
5968 }
5969 }
5970 else
5971 {
5972 for(i = 0; i < frame_step; i++)
5973 {
5974 for(j = 0; j < data->n_values_per_frame; j++)
5975 {
5976 if(tng_fwritestr(tng_data, data->strings[0][i][j],
5977 hash_mode, &md5_state, __LINE__) == TNG_CRITICAL)
5978 {
5979 return(TNG_CRITICAL);
5980 }
5981 }
5982 }
5983 }
5984 }
5985 }
5986 else
5987 {
5988 if(data->dependency & TNG_PARTICLE_DEPENDENT)
5989 {
5990 full_data_len = size * frame_step * n_particles * data->n_values_per_frame;
5991 }
5992 else
5993 {
5994 full_data_len = size * frame_step * data->n_values_per_frame;
5995 }
5996 contents = (char *)malloc(full_data_len);
5997 if(!contents)
5998 {
5999 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6000 __FILE__, __LINE__);
6001 return(TNG_CRITICAL);
6002 }
6003
6004 if(data->values)
6005 {
6006 memcpy(contents, data->values, full_data_len);
6007 /* If writing TNG compressed data the endianness is taken into account by the compression
6008 * routines. TNG compressed data is always written as little endian. */
6009 if(data->codec_id != TNG_TNG_COMPRESSION)
6010 {
6011 switch(data->datatype)
6012 {
6013 case TNG_FLOAT_DATA:
6014 if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION)
6015 {
6016 if(tng_data->output_endianness_swap_func_32)
6017 {
6018 for(i = 0; i < full_data_len; i+=size)
6019 {
6020 if(tng_data->output_endianness_swap_func_32(tng_data,
6021 (uint32_t *)(contents + i))
6022 != TNG_SUCCESS)
6023 {
6024 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6025 __FILE__, __LINE__);
6026 }
6027 }
6028 }
6029 }
6030 else
6031 {
6032 multiplier = data->compression_multiplier;
6033 if(fabs(multiplier - 1.0) > 0.00001 ||
6034 tng_data->output_endianness_swap_func_32)
6035 {
6036 for(i = 0; i < full_data_len; i+=size)
6037 {
6038 *(float *)(contents + i) *= (float)multiplier;
6039 if(tng_data->output_endianness_swap_func_32 &&
6040 tng_data->output_endianness_swap_func_32(tng_data,
6041 (uint32_t *)(contents + i))
6042 != TNG_SUCCESS)
6043 {
6044 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6045 __FILE__, __LINE__);
6046 }
6047 }
6048 }
6049 }
6050 break;
6051 case TNG_INT_DATA:
6052 if(tng_data->output_endianness_swap_func_64)
6053 {
6054 for(i = 0; i < full_data_len; i+=size)
6055 {
6056 if(tng_data->output_endianness_swap_func_64(tng_data,
6057 (uint64_t *)(contents + i))
6058 != TNG_SUCCESS)
6059 {
6060 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6061 __FILE__, __LINE__);
6062 }
6063 }
6064 }
6065 break;
6066 case TNG_DOUBLE_DATA:
6067 if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION)
6068 {
6069 if(tng_data->output_endianness_swap_func_64)
6070 {
6071 for(i = 0; i < full_data_len; i+=size)
6072 {
6073 if(tng_data->output_endianness_swap_func_64(tng_data,
6074 (uint64_t *)(contents + i))
6075 != TNG_SUCCESS)
6076 {
6077 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6078 __FILE__, __LINE__);
6079 }
6080 }
6081 }
6082 }
6083 else
6084 {
6085 multiplier = data->compression_multiplier;
6086 if(fabs(multiplier - 1.0) > 0.00001 ||
6087 tng_data->output_endianness_swap_func_64)
6088 {
6089 for(i = 0; i < full_data_len; i+=size)
6090 {
6091 *(double *)(contents + i) *= multiplier;
6092 if(tng_data->output_endianness_swap_func_64 &&
6093 tng_data->output_endianness_swap_func_64(tng_data,
6094 (uint64_t *)(contents + i))
6095 != TNG_SUCCESS)
6096 {
6097 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
6098 __FILE__, __LINE__);
6099 }
6100 }
6101 }
6102 }
6103 break;
6104 case TNG_CHAR_DATA:
6105 break;
6106 }
6107 }
6108 }
6109 else
6110 {
6111 memset(contents, 0, full_data_len);
6112 }
6113
6114 block_data_len = full_data_len;
6115
6116 switch(data->codec_id)
6117 {
6118 case TNG_XTC_COMPRESSION:
6119 fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
6120 data->codec_id = TNG_UNCOMPRESSED;
6121 break;
6122 case TNG_TNG_COMPRESSION:
6123 stat = tng_compress(tng_data, block, frame_step,
6124 n_particles, data->datatype,
6125 &contents, &block_data_len);
6126 if(stat != TNG_SUCCESS)
6127 {
6128 fprintf(stderr, "TNG library: Could not write TNG compressed block data. %s: %d\n",
6129 __FILE__, __LINE__);
6130 if(stat == TNG_CRITICAL)
6131 {
6132 return(TNG_CRITICAL);
6133 }
6134 /* Set the data again, but with no compression (to write only
6135 * the relevant data) */
6136 data->codec_id = TNG_UNCOMPRESSED;
6137 stat = tng_data_block_write(tng_data, block,
6138 block_index, is_particle_data, mapping,
6139 hash_mode);
6140 free(contents);
6141 return(stat);
6142 }
6143 break;
6144 case TNG_GZIP_COMPRESSION:
6145 /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
6146 stat = tng_gzip_compress(tng_data,
6147 &contents,
6148 full_data_len,
6149 &block_data_len);
6150 if(stat != TNG_SUCCESS)
6151 {
6152 fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__,
6153 __LINE__);
6154 if(stat == TNG_CRITICAL)
6155 {
6156 return(TNG_CRITICAL);
6157 }
6158 data->codec_id = TNG_UNCOMPRESSED;
6159 }
6160 /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
6161 break;
6162 }
6163 if(block_data_len != full_data_len)
6164 {
6165 block->block_contents_size -= full_data_len - block_data_len;
6166
6167 curr_file_pos = ftello(tng_data->output_file);
6168 fseeko(tng_data->output_file, header_file_pos + sizeof(block->header_contents_size), SEEK_SET);
6169
6170 if(tng_file_output_numerical(tng_data, &block->block_contents_size,
6171 sizeof(block->block_contents_size),
6172 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
6173 {
6174 return(TNG_CRITICAL);
6175 }
6176 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6177 }
6178 if(fwrite(contents, block_data_len, 1, tng_data->output_file) != 1)
6179 {
6180 fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__,
6181 __LINE__);
6182 return(TNG_CRITICAL);
6183 }
6184 if(hash_mode == TNG_USE_HASH)
6185 {
6186 md5_append(&md5_state, (md5_byte_t *)contents, block_data_len);
6187 }
6188
6189 free(contents);
6190 }
6191
6192 if(hash_mode == TNG_USE_HASH)
6193 {
6194 md5_finish(&md5_state, (md5_byte_t *)block->md5_hash);
6195 curr_file_pos = ftello(tng_data->output_file);
6196 fseeko(tng_data->output_file, header_file_pos +
6197 3 * sizeof(int64_t), SEEK_SET);
6198 if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1)
6199 {
6200 fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__,
6201 __LINE__);
6202 return(TNG_CRITICAL);
6203 }
6204 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6205 }
6206
6207 frame_set->n_written_frames += frame_set->n_unwritten_frames;
6208 frame_set->n_unwritten_frames = 0;
6209
6210 return(TNG_SUCCESS);
6211 }
6212
6213 /**
6214 * @brief Read the meta information of a data block (particle or non-particle data).
6215 * @param tng_data is a trajectory data container.
6216 * @param datatype is set to the datatype of the data block.
6217 * @param dependency is set to the dependency (particle and/or frame dependent)
6218 * @param sparse_data is set to TRUE if data is not written every frame.
6219 * @param n_values is set to the number of values per frame of the data.
6220 * @param codec_id is set to the ID of the codec used to compress the data.
6221 * @param first_frame_with_data is set to the first frame with data (only relevant if
6222 * sparse_data == TRUE).
6223 * @param stride_length is set to the writing interval of the data (1 if sparse_data
6224 * == FALSE).
6225 * @param num_first_particle is set to the number of the first particle with data written
6226 * in this block.
6227 * @param block_n_particles is set to the number of particles in this data block.
6228 * @param multiplier is set to the compression multiplier.
6229 * @param hash_mode specifies whether to check if the hash matches the contents or not.
6230 * @param md5_state is the md5 hash of the block (only used if hash_mode == TNG_USE_HASH).
6231 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6232 * error has occured.
6233 */
tng_data_block_meta_information_read(const tng_trajectory_t tng_data,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,const char hash_mode,md5_state_t * md5_state)6234 static tng_function_status tng_data_block_meta_information_read
6235 (const tng_trajectory_t tng_data,
6236 char *datatype,
6237 char *dependency,
6238 char *sparse_data,
6239 int64_t *n_values,
6240 int64_t *codec_id,
6241 int64_t *first_frame_with_data,
6242 int64_t *stride_length,
6243 int64_t *n_frames,
6244 int64_t *num_first_particle,
6245 int64_t *block_n_particles,
6246 double *multiplier,
6247 const char hash_mode,
6248 md5_state_t *md5_state)
6249 {
6250 if(tng_file_input_numerical(tng_data, datatype,
6251 sizeof(*datatype),
6252 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6253 {
6254 return(TNG_CRITICAL);
6255 }
6256
6257 if(tng_file_input_numerical(tng_data, dependency,
6258 sizeof(*dependency),
6259 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6260 {
6261 return(TNG_CRITICAL);
6262 }
6263
6264 if(*dependency & TNG_FRAME_DEPENDENT)
6265 {
6266 if(tng_file_input_numerical(tng_data, sparse_data,
6267 sizeof(*sparse_data),
6268 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6269 {
6270 return(TNG_CRITICAL);
6271 }
6272 }
6273
6274 if(tng_file_input_numerical(tng_data, n_values,
6275 sizeof(*n_values),
6276 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6277 {
6278 return(TNG_CRITICAL);
6279 }
6280
6281 if(tng_file_input_numerical(tng_data, codec_id,
6282 sizeof(*codec_id),
6283 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6284 {
6285 return(TNG_CRITICAL);
6286 }
6287
6288 if(*codec_id != TNG_UNCOMPRESSED)
6289 {
6290 if(tng_file_input_numerical(tng_data, multiplier,
6291 sizeof(*multiplier),
6292 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6293 {
6294 return(TNG_CRITICAL);
6295 }
6296 }
6297 else
6298 {
6299 *multiplier = 1;
6300 }
6301
6302 if(*dependency & TNG_FRAME_DEPENDENT)
6303 {
6304 if(*sparse_data)
6305 {
6306 if(tng_file_input_numerical(tng_data, first_frame_with_data,
6307 sizeof(*first_frame_with_data),
6308 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6309 {
6310 return(TNG_CRITICAL);
6311 }
6312
6313 if(tng_file_input_numerical(tng_data, stride_length,
6314 sizeof(*stride_length),
6315 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6316 {
6317 return(TNG_CRITICAL);
6318 }
6319
6320 *n_frames = tng_data->current_trajectory_frame_set.n_frames -
6321 (*first_frame_with_data -
6322 tng_data->current_trajectory_frame_set.first_frame);
6323 }
6324 else
6325 {
6326 *first_frame_with_data = tng_data->current_trajectory_frame_set.first_frame;
6327 *stride_length = 1;
6328 *n_frames = tng_data->current_trajectory_frame_set.n_frames;
6329 }
6330 }
6331 else
6332 {
6333 *first_frame_with_data = 0;
6334 *stride_length = 1;
6335 *n_frames = 1;
6336 }
6337
6338 if (*dependency & TNG_PARTICLE_DEPENDENT)
6339 {
6340 if(tng_file_input_numerical(tng_data, num_first_particle,
6341 sizeof(*num_first_particle),
6342 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6343 {
6344 return(TNG_CRITICAL);
6345 }
6346
6347 if(tng_file_input_numerical(tng_data, block_n_particles,
6348 sizeof(*block_n_particles),
6349 hash_mode, md5_state, __LINE__) == TNG_CRITICAL)
6350 {
6351 return(TNG_CRITICAL);
6352 }
6353 }
6354 else
6355 {
6356 *num_first_particle = -1;
6357 *block_n_particles = 0;
6358 }
6359
6360 return(TNG_SUCCESS);
6361 }
6362
6363 /**
6364 * @brief Read the contents of a data block (particle or non-particle data).
6365 * @param tng_data is a trajectory data container.
6366 * @param block is the block to store the data (should already contain
6367 * the block headers).
6368 * @param hash_mode is an option to decide whether to use the md5 hash or not.
6369 * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be
6370 * compared to the md5 hash of the read contents to ensure valid data.
6371 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6372 * error has occured.
6373 */
tng_data_block_contents_read(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)6374 static tng_function_status tng_data_block_contents_read
6375 (const tng_trajectory_t tng_data,
6376 const tng_gen_block_t block,
6377 const char hash_mode)
6378 {
6379 int64_t start_pos, n_values, codec_id, n_frames, first_frame_with_data;
6380 int64_t remaining_len, stride_length, block_n_particles, num_first_particle;
6381 double multiplier;
6382 char datatype, dependency, sparse_data;
6383 tng_function_status stat = TNG_SUCCESS;
6384 char hash[TNG_MD5_HASH_LEN];
6385 md5_state_t md5_state;
6386
6387 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
6388 {
6389 return(TNG_CRITICAL);
6390 }
6391
6392 start_pos = ftello(tng_data->input_file);
6393
6394 if(hash_mode == TNG_USE_HASH)
6395 {
6396 md5_init(&md5_state);
6397 }
6398
6399 /* FIXME: Does not check if the size of the contents matches the expected
6400 * size or if the contents can be read. */
6401
6402 if(tng_data_block_meta_information_read(tng_data,
6403 &datatype,
6404 &dependency, &sparse_data,
6405 &n_values, &codec_id,
6406 &first_frame_with_data,
6407 &stride_length, &n_frames,
6408 &num_first_particle,
6409 &block_n_particles,
6410 &multiplier,
6411 hash_mode,
6412 &md5_state) == TNG_CRITICAL)
6413 {
6414 fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n",
6415 block->name, __FILE__, __LINE__);
6416 return(TNG_CRITICAL);
6417 }
6418
6419 remaining_len = block->block_contents_size - (ftello(tng_data->input_file) - start_pos);
6420
6421 stat = tng_data_read(tng_data, block,
6422 remaining_len,
6423 datatype,
6424 num_first_particle,
6425 block_n_particles,
6426 first_frame_with_data,
6427 stride_length,
6428 n_frames, n_values,
6429 codec_id, multiplier,
6430 hash_mode,
6431 &md5_state);
6432
6433 if(hash_mode == TNG_USE_HASH)
6434 {
6435 /* If there is data left in the block that the current version of the library
6436 * cannot interpret still read that to generate the MD5 hash. */
6437 tng_md5_remaining_append(tng_data, block, start_pos, &md5_state);
6438
6439 md5_finish(&md5_state, (md5_byte_t *)hash);
6440 if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0)
6441 {
6442 if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
6443 {
6444 fprintf(stderr, "TNG library: Data block contents corrupt (%s). Hashes do not match. "
6445 "%s: %d\n", block->name, __FILE__, __LINE__);
6446 }
6447 }
6448 }
6449 else
6450 {
6451 /* Seek to the end of the block */
6452 fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET);
6453 }
6454
6455 return(stat);
6456 }
6457
6458 /*
6459 // ** Move the blocks in a frame set so that there is no unused space between
6460 // * them. This can only be done on the last frame set in the file and should
6461 // * be done e.g. if the last frame set in the file has fewer frames than
6462 // * default or after compressing data blocks in a frame set.
6463 // * @param tng_data is a trajectory data container.
6464 // * @details the current_trajectory_frame_set is the one that will be modified.
6465 // * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set
6466 // * cannot be aligned or TNG_CRITICAL (2) if a major error has occured.
6467 // * FIXME: This function is not finished!!!
6468 // *
6469 // static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data)
6470 // {
6471 // tng_gen_block_t block;
6472 // tng_trajectory_frame_set_t frame_set;
6473 // FILE *temp = tng_data->input_file;
6474 // int64_t pos, contents_start_pos, output_file_len;
6475 //
6476 // frame_set = &tng_data->current_trajectory_frame_set;
6477 //
6478 // if(frame_set->n_written_frames == frame_set->n_frames)
6479 // {
6480 // return(TNG_SUCCESS);
6481 // }
6482 //
6483 // if(tng_data->current_trajectory_frame_set_output_file_pos !=
6484 // tng_data->last_trajectory_frame_set_output_file_pos)
6485 // {
6486 // }
6487 //
6488 // if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6489 // {
6490 // fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6491 // __FILE__, __LINE__);
6492 // return(TNG_CRITICAL);
6493 // }
6494 //
6495 // tng_block_init(&block);
6496 // // output_file_pos = ftello(tng_data->output_file);
6497 //
6498 // tng_data->input_file = tng_data->output_file;
6499 //
6500 // pos = tng_data->current_trajectory_frame_set_output_file_pos;
6501 //
6502 // fseeko(tng_data->output_file, pos, SEEK_SET);
6503 // if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6504 // {
6505 // fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6506 // __FILE__, __LINE__);
6507 // tng_data->input_file = temp;
6508 // tng_block_destroy(&block);
6509 // return(TNG_CRITICAL);
6510 // }
6511 //
6512 // contents_start_pos = ftello(tng_data->output_file);
6513 //
6514 // fseeko(tng_data->output_file, 0, SEEK_END);
6515 // output_file_len = ftello(tng_data->output_file);
6516 // pos = contents_start_pos + block->block_contents_size;
6517 // fseeko(tng_data->output_file, pos,
6518 // SEEK_SET);
6519 //
6520 // while(pos < output_file_len)
6521 // {
6522 // if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6523 // {
6524 // fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
6525 // __FILE__, __LINE__);
6526 // tng_data->input_file = temp;
6527 // tng_block_destroy(&block);
6528 // return(TNG_CRITICAL);
6529 // }
6530 // pos += block->header_contents_size + block->block_contents_size;
6531 // fseeko(tng_data->output_file, pos, SEEK_SET);
6532 // }
6533 //
6534 // return(TNG_SUCCESS);
6535 // }
6536 */
6537 /**
6538 * @brief Finish writing the current frame set. Update the number of frames
6539 * and the hashes of the frame set and all its data blocks (if hash_mode
6540 * == TNG_USE_HASH).
6541 * @param tng_data is a trajectory data container.
6542 * @param hash_mode specifies whether to update the block md5 hash when
6543 * updating the pointers.
6544 * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6545 * error has occured.
6546 */
tng_frame_set_finalize(const tng_trajectory_t tng_data,const char hash_mode)6547 static tng_function_status tng_frame_set_finalize
6548 (const tng_trajectory_t tng_data,
6549 const char hash_mode)
6550 {
6551 tng_gen_block_t block;
6552 tng_trajectory_frame_set_t frame_set;
6553 FILE *temp = tng_data->input_file;
6554 int64_t pos, curr_file_pos;
6555
6556 frame_set = &tng_data->current_trajectory_frame_set;
6557
6558 if(frame_set->n_written_frames == frame_set->n_frames)
6559 {
6560 return(TNG_SUCCESS);
6561 }
6562
6563 frame_set->n_written_frames = frame_set->n_frames;
6564
6565 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
6566 {
6567 fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
6568 __FILE__, __LINE__);
6569 return(TNG_CRITICAL);
6570 }
6571
6572 tng_block_init(&block);
6573 /* output_file_pos = ftello(tng_data->output_file); */
6574
6575 tng_data->input_file = tng_data->output_file;
6576
6577 curr_file_pos = ftello(tng_data->output_file);
6578
6579 pos = tng_data->current_trajectory_frame_set_output_file_pos;
6580
6581 fseeko(tng_data->output_file, pos, SEEK_SET);
6582
6583 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
6584 {
6585 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
6586 __FILE__, __LINE__);
6587 tng_data->input_file = temp;
6588 tng_block_destroy(&block);
6589 return(TNG_CRITICAL);
6590 }
6591
6592 // contents_start_pos = ftello(tng_data->output_file);
6593
6594 fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR);
6595 if(fwrite(&frame_set->n_frames, sizeof(frame_set->n_frames),
6596 1, tng_data->output_file) != 1)
6597 {
6598 tng_data->input_file = temp;
6599 tng_block_destroy(&block);
6600 return(TNG_CRITICAL);
6601 }
6602
6603 if(hash_mode == TNG_USE_HASH)
6604 {
6605 tng_md5_hash_update(tng_data, block, pos,
6606 pos + block->header_contents_size);
6607 }
6608
6609 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
6610
6611 tng_data->input_file = temp;
6612 tng_block_destroy(&block);
6613 return(TNG_SUCCESS);
6614 }
6615
6616 /*
6617 // ** Sets the name of a file contents block
6618 // * @param tng_data is a trajectory data container.
6619 // * @param block is the block, of which to change names.
6620 // * @param new_name is the new name of the block.
6621 // * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major
6622 // * error has occured.
6623 //
6624 // static tng_function_status tng_block_name_set(tng_trajectory_t tng_data,
6625 // tng_gen_block_t block,
6626 // const char *new_name)
6627 // {
6628 // int len;
6629 //
6630 // len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6631 //
6632 // * If the currently stored string length is not enough to store the new
6633 // * string it is freed and reallocated. *
6634 // if(block->name && strlen(block->name) < len)
6635 // {
6636 // free(block->name);
6637 // block->name = 0;
6638 // }
6639 // if(!block->name)
6640 // {
6641 // block->name = (char *)malloc(len);
6642 // if(!block->name)
6643 // {
6644 // fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6645 // __FILE__, __LINE__);
6646 // return(TNG_CRITICAL);
6647 // }
6648 // }
6649 //
6650 // strncpy(block->name, new_name, len);
6651 //
6652 // return(TNG_SUCCESS);
6653 // }
6654 */
6655
tng_atom_residue_get(const tng_trajectory_t tng_data,const tng_atom_t atom,tng_residue_t * residue)6656 tng_function_status DECLSPECDLLEXPORT tng_atom_residue_get
6657 (const tng_trajectory_t tng_data,
6658 const tng_atom_t atom,
6659 tng_residue_t *residue)
6660 {
6661 (void) tng_data;
6662
6663 TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6664
6665 *residue = atom->residue;
6666
6667 return(TNG_SUCCESS);
6668 }
6669
tng_atom_name_get(const tng_trajectory_t tng_data,const tng_atom_t atom,char * name,const int max_len)6670 tng_function_status DECLSPECDLLEXPORT tng_atom_name_get
6671 (const tng_trajectory_t tng_data,
6672 const tng_atom_t atom,
6673 char *name,
6674 const int max_len)
6675 {
6676 (void) tng_data;
6677 TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6678 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
6679
6680 strncpy(name, atom->name, max_len - 1);
6681 name[max_len - 1] = 0;
6682
6683 if(strlen(atom->name) > (unsigned int)max_len - 1)
6684 {
6685 return(TNG_FAILURE);
6686 }
6687 return(TNG_SUCCESS);
6688 }
6689
tng_atom_name_set(const tng_trajectory_t tng_data,const tng_atom_t atom,const char * new_name)6690 tng_function_status DECLSPECDLLEXPORT tng_atom_name_set
6691 (const tng_trajectory_t tng_data,
6692 const tng_atom_t atom,
6693 const char *new_name)
6694 {
6695 unsigned int len;
6696 (void)tng_data;
6697
6698 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6699 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
6700
6701 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
6702
6703 /* If the currently stored string length is not enough to store the new
6704 * string it is freed and reallocated. */
6705 if(atom->name && strlen(atom->name) < len)
6706 {
6707 free(atom->name);
6708 atom->name = 0;
6709 }
6710 if(!atom->name)
6711 {
6712 atom->name = (char *)malloc(len);
6713 if(!atom->name)
6714 {
6715 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6716 __FILE__, __LINE__);
6717 return(TNG_CRITICAL);
6718 }
6719 }
6720
6721 strncpy(atom->name, new_name, len);
6722
6723 return(TNG_SUCCESS);
6724 }
6725
tng_atom_type_get(const tng_trajectory_t tng_data,const tng_atom_t atom,char * type,const int max_len)6726 tng_function_status DECLSPECDLLEXPORT tng_atom_type_get
6727 (const tng_trajectory_t tng_data,
6728 const tng_atom_t atom,
6729 char *type,
6730 const int max_len)
6731 {
6732 (void) tng_data;
6733 TNG_ASSERT(atom, "TNG library: atom must not be NULL");
6734 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer");
6735
6736 strncpy(type, atom->atom_type, max_len - 1);
6737 type[max_len - 1] = 0;
6738
6739 if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
6740 {
6741 return(TNG_FAILURE);
6742 }
6743 return(TNG_SUCCESS);
6744 }
6745
tng_atom_type_set(const tng_trajectory_t tng_data,const tng_atom_t atom,const char * new_type)6746 tng_function_status DECLSPECDLLEXPORT tng_atom_type_set
6747 (const tng_trajectory_t tng_data,
6748 const tng_atom_t atom,
6749 const char *new_type)
6750 {
6751 unsigned int len;
6752 (void)tng_data;
6753
6754 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6755 TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer.");
6756
6757 len = tng_min_size(strlen(new_type) + 1, TNG_MAX_STR_LEN);
6758
6759 /* If the currently stored string length is not enough to store the new
6760 * string it is freed and reallocated. */
6761 if(atom->atom_type && strlen(atom->atom_type) < len)
6762 {
6763 free(atom->atom_type);
6764 atom->atom_type = 0;
6765 }
6766 if(!atom->atom_type)
6767 {
6768 atom->atom_type = (char *)malloc(len);
6769 if(!atom->atom_type)
6770 {
6771 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6772 __FILE__, __LINE__);
6773 return(TNG_CRITICAL);
6774 }
6775 }
6776
6777 strncpy(atom->atom_type, new_type, len);
6778
6779 return(TNG_SUCCESS);
6780 }
6781
6782 /**
6783 * @brief Initialise an atom struct
6784 * @param atom is the atom to initialise.
6785 * @return TNG_SUCCESS (0) if successful.
6786 */
tng_atom_init(const tng_atom_t atom)6787 static tng_function_status tng_atom_init(const tng_atom_t atom)
6788 {
6789 atom->name = 0;
6790 atom->atom_type = 0;
6791
6792 return(TNG_SUCCESS);
6793 }
6794
6795 /**
6796 * @brief Free the memory in an atom struct
6797 * @param atom is the atom to destroy.
6798 * @return TNG_SUCCESS (0) if successful.
6799 */
tng_atom_destroy(const tng_atom_t atom)6800 static tng_function_status tng_atom_destroy(const tng_atom_t atom)
6801 {
6802 if(atom->name)
6803 {
6804 free(atom->name);
6805 atom->name = 0;
6806 }
6807 if(atom->atom_type)
6808 {
6809 free(atom->atom_type);
6810 atom->atom_type = 0;
6811 }
6812
6813 return(TNG_SUCCESS);
6814 }
6815
6816 /**
6817 * @brief Update chain->residue pointers (after new memory for
6818 * molecule->residues has been allocated).
6819 * @param tng_data The trajectory container containing the molecule.
6820 * @param mol The molecule that contains the chains that need to be
6821 * updated.
6822 * @returns TNG_SUCCESS (0) if successful.
6823 */
tng_molecule_chains_residue_pointers_update(const tng_trajectory_t tng_data,const tng_molecule_t mol)6824 static tng_function_status tng_molecule_chains_residue_pointers_update
6825 (const tng_trajectory_t tng_data,
6826 const tng_molecule_t mol)
6827 {
6828 tng_chain_t chain;
6829 int64_t i, res_cnt = 0;
6830 (void)tng_data;
6831
6832 for(i = 0; i < mol->n_chains; i++)
6833 {
6834 chain = &mol->chains[i];
6835 chain->residues = mol->residues + res_cnt;
6836 res_cnt += chain->n_residues;
6837 }
6838 return(TNG_SUCCESS);
6839 }
6840
6841 /**
6842 * @brief Update atoms->residue pointers (after new memory for
6843 * molecule->residues has been allocated).
6844 * @param tng_data The trajectory container containing the molecule.
6845 * @param mol The molecule that contains the chains that need to be
6846 * updated.
6847 * @returns TNG_SUCCESS (0) if successful.
6848 */
tng_molecule_atoms_residue_pointers_update(const tng_trajectory_t tng_data,const tng_molecule_t mol)6849 static tng_function_status tng_molecule_atoms_residue_pointers_update
6850 (const tng_trajectory_t tng_data,
6851 const tng_molecule_t mol)
6852 {
6853 tng_atom_t atom;
6854 tng_residue_t residue;
6855 int64_t i, j, atom_offset = 0;
6856 (void)tng_data;
6857
6858 for(i = 0; i < mol->n_residues; i++)
6859 {
6860 residue = &mol->residues[i];
6861 for(j = 0; j < residue->n_atoms; j++)
6862 {
6863 atom = &mol->atoms[j + atom_offset];
6864 atom->residue = residue;
6865 }
6866 atom_offset += residue->n_atoms;
6867 }
6868 return(TNG_SUCCESS);
6869 }
6870
tng_version_major(const tng_trajectory_t tng_data,int * version)6871 tng_function_status DECLSPECDLLEXPORT tng_version_major
6872 (const tng_trajectory_t tng_data,
6873 int *version)
6874 {
6875 (void)tng_data;
6876
6877 *version = TNG_VERSION_MAJOR;
6878
6879 return(TNG_SUCCESS);
6880 }
6881
tng_version_minor(const tng_trajectory_t tng_data,int * version)6882 tng_function_status DECLSPECDLLEXPORT tng_version_minor
6883 (const tng_trajectory_t tng_data,
6884 int *version)
6885 {
6886 (void)tng_data;
6887
6888 *version = TNG_VERSION_MINOR;
6889
6890 return(TNG_SUCCESS);
6891 }
6892
tng_version_patchlevel(const tng_trajectory_t tng_data,int * patch_level)6893 tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel
6894 (const tng_trajectory_t tng_data,
6895 int *patch_level)
6896 {
6897 (void)tng_data;
6898
6899 *patch_level = TNG_VERSION_PATCHLEVEL;
6900
6901 return(TNG_SUCCESS);
6902 }
6903
tng_version(const tng_trajectory_t tng_data,char * version,const int max_len)6904 tng_function_status DECLSPECDLLEXPORT tng_version
6905 (const tng_trajectory_t tng_data,
6906 char *version,
6907 const int max_len)
6908 {
6909 (void)tng_data;
6910 TNG_ASSERT(version, "TNG library: version must not be a NULL pointer");
6911
6912 TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION);
6913
6914 return(TNG_SUCCESS);
6915 }
6916
tng_molecule_add(const tng_trajectory_t tng_data,const char * name,tng_molecule_t * molecule)6917 tng_function_status DECLSPECDLLEXPORT tng_molecule_add
6918 (const tng_trajectory_t tng_data,
6919 const char *name,
6920 tng_molecule_t *molecule)
6921 {
6922 int64_t id;
6923
6924 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6925 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6926
6927 /* Set ID to the ID of the last molecule + 1 */
6928 if(tng_data->n_molecules)
6929 {
6930 id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
6931 }
6932 else
6933 {
6934 id = 1;
6935 }
6936
6937 return(tng_molecule_w_id_add(tng_data, name, id, molecule));
6938 }
6939
tng_molecule_w_id_add(const tng_trajectory_t tng_data,const char * name,const int64_t id,tng_molecule_t * molecule)6940 tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add
6941 (const tng_trajectory_t tng_data,
6942 const char *name,
6943 const int64_t id,
6944 tng_molecule_t *molecule)
6945 {
6946 tng_molecule_t new_molecules;
6947 int64_t *new_molecule_cnt_list;
6948 tng_function_status stat = TNG_SUCCESS;
6949
6950 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
6951 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
6952
6953 new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
6954 sizeof(struct tng_molecule) *
6955 (tng_data->n_molecules + 1));
6956
6957 if(!new_molecules)
6958 {
6959 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6960 __FILE__, __LINE__);
6961 free(tng_data->molecules);
6962 tng_data->molecules = 0;
6963 return(TNG_CRITICAL);
6964 }
6965
6966 new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
6967 sizeof(int64_t) *
6968 (tng_data->n_molecules + 1));
6969
6970 if(!new_molecule_cnt_list)
6971 {
6972 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
6973 __FILE__, __LINE__);
6974 free(tng_data->molecule_cnt_list);
6975 tng_data->molecule_cnt_list = 0;
6976 free(new_molecules);
6977 return(TNG_CRITICAL);
6978 }
6979
6980 tng_data->molecules = new_molecules;
6981 tng_data->molecule_cnt_list = new_molecule_cnt_list;
6982
6983 *molecule = &new_molecules[tng_data->n_molecules];
6984
6985 tng_molecule_init(tng_data, *molecule);
6986 tng_molecule_name_set(tng_data, *molecule, name);
6987
6988 /* FIXME: Should this be a function argument instead? */
6989 tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
6990
6991 (*molecule)->id = id;
6992
6993 tng_data->n_molecules++;
6994
6995 return(stat);
6996 }
6997
tng_molecule_existing_add(const tng_trajectory_t tng_data,tng_molecule_t * molecule_p)6998 tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add
6999 (const tng_trajectory_t tng_data,
7000 tng_molecule_t *molecule_p)
7001 {
7002 int64_t *new_molecule_cnt_list, id;
7003 tng_molecule_t new_molecules, molecule;
7004
7005 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7006
7007 /* Set ID to the ID of the last molecule + 1 */
7008 if(tng_data->n_molecules)
7009 {
7010 id = tng_data->molecules[tng_data->n_molecules-1].id + 1;
7011 }
7012 else
7013 {
7014 id = 1;
7015 }
7016
7017 new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
7018 sizeof(struct tng_molecule) *
7019 (tng_data->n_molecules + 1));
7020
7021 if(!new_molecules)
7022 {
7023 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7024 __FILE__, __LINE__);
7025 free(tng_data->molecules);
7026 tng_data->molecules = 0;
7027 return(TNG_CRITICAL);
7028 }
7029
7030 new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
7031 sizeof(int64_t) *
7032 (tng_data->n_molecules + 1));
7033
7034 if(!new_molecule_cnt_list)
7035 {
7036 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7037 __FILE__, __LINE__);
7038 free(tng_data->molecule_cnt_list);
7039 tng_data->molecule_cnt_list = 0;
7040 free(new_molecules);
7041 return(TNG_CRITICAL);
7042 }
7043
7044 molecule = *molecule_p;
7045
7046 tng_data->molecules = new_molecules;
7047 tng_data->molecule_cnt_list = new_molecule_cnt_list;
7048
7049 new_molecules[tng_data->n_molecules] = *molecule;
7050
7051 tng_data->molecule_cnt_list[tng_data->n_molecules] = 0;
7052
7053 free(*molecule_p);
7054
7055 molecule = &new_molecules[tng_data->n_molecules];
7056
7057 *molecule_p = molecule;
7058
7059 molecule->id = id;
7060
7061 tng_data->n_molecules++;
7062
7063 return(TNG_SUCCESS);
7064 }
7065
tng_molecule_name_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,char * name,const int max_len)7066 tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data,
7067 const tng_molecule_t molecule,
7068 char *name,
7069 const int max_len)
7070 {
7071 (void) tng_data;
7072 TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7073 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7074
7075 strncpy(name, molecule->name, max_len - 1);
7076 name[max_len - 1] = 0;
7077
7078 if(strlen(molecule->name) > (unsigned int)max_len - 1)
7079 {
7080 return(TNG_FAILURE);
7081 }
7082 return(TNG_SUCCESS);
7083 }
7084
tng_molecule_name_set(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const char * new_name)7085 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set
7086 (const tng_trajectory_t tng_data,
7087 const tng_molecule_t molecule,
7088 const char *new_name)
7089 {
7090 unsigned int len;
7091 (void)tng_data;
7092
7093 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7094 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7095
7096 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7097
7098 /* If the currently stored string length is not enough to store the new
7099 * string it is freed and reallocated. */
7100 if(molecule->name && strlen(molecule->name) < len)
7101 {
7102 free(molecule->name);
7103 molecule->name = 0;
7104 }
7105 if(!molecule->name)
7106 {
7107 molecule->name = (char *)malloc(len);
7108 if(!molecule->name)
7109 {
7110 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7111 __FILE__, __LINE__);
7112 return(TNG_CRITICAL);
7113 }
7114 }
7115
7116 strncpy(molecule->name, new_name, len);
7117
7118 return(TNG_SUCCESS);
7119 }
7120
tng_molecule_cnt_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,int64_t * cnt)7121 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get
7122 (const tng_trajectory_t tng_data,
7123 const tng_molecule_t molecule,
7124 int64_t *cnt)
7125 {
7126 int64_t i, index = -1;
7127
7128 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7129 TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer.");
7130
7131 for(i = 0; i < tng_data->n_molecules; i++)
7132 {
7133 if(&tng_data->molecules[i] == molecule)
7134 {
7135 index = i;
7136 break;
7137 }
7138 }
7139 if(index == -1)
7140 {
7141 return(TNG_FAILURE);
7142 }
7143 *cnt = tng_data->molecule_cnt_list[index];
7144
7145 return(TNG_SUCCESS);
7146 }
7147
tng_molecule_cnt_set(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const int64_t cnt)7148 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set
7149 (const tng_trajectory_t tng_data,
7150 const tng_molecule_t molecule,
7151 const int64_t cnt)
7152 {
7153 int64_t i, old_cnt, index = -1;
7154
7155 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7156
7157 for(i = 0; i < tng_data->n_molecules; i++)
7158 {
7159 if(&tng_data->molecules[i] == molecule)
7160 {
7161 index = i;
7162 break;
7163 }
7164 }
7165 if(index == -1)
7166 {
7167 fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n",
7168 __FILE__, __LINE__);
7169 return(TNG_FAILURE);
7170 }
7171 if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
7172 {
7173 old_cnt = tng_data->molecule_cnt_list[index];
7174 tng_data->molecule_cnt_list[index] = cnt;
7175
7176 tng_data->n_particles += (cnt-old_cnt) *
7177 tng_data->molecules[index].n_atoms;
7178 }
7179 else
7180 {
7181 old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index];
7182 tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt;
7183
7184 tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) *
7185 tng_data->molecules[index].n_atoms;
7186 }
7187
7188 return(TNG_SUCCESS);
7189 }
7190
tng_molecule_find(const tng_trajectory_t tng_data,const char * name,const int64_t nr,tng_molecule_t * molecule)7191 tng_function_status DECLSPECDLLEXPORT tng_molecule_find
7192 (const tng_trajectory_t tng_data,
7193 const char *name,
7194 const int64_t nr,
7195 tng_molecule_t *molecule)
7196 {
7197 int64_t i, n_molecules;
7198
7199 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7200 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7201 TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7202
7203 n_molecules = tng_data->n_molecules;
7204
7205 for(i = n_molecules - 1; i >= 0; i--)
7206 {
7207 *molecule = &tng_data->molecules[i];
7208 if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0)
7209 {
7210 if(nr == -1 || nr == (*molecule)->id)
7211 {
7212 return(TNG_SUCCESS);
7213 }
7214 }
7215 }
7216
7217 *molecule = 0;
7218
7219 return(TNG_FAILURE);
7220 }
7221
tng_molecule_of_index_get(const tng_trajectory_t tng_data,const int64_t index,tng_molecule_t * molecule)7222 tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get
7223 (const tng_trajectory_t tng_data,
7224 const int64_t index,
7225 tng_molecule_t *molecule)
7226 {
7227 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7228 TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7229
7230 if(index >= tng_data->n_molecules)
7231 {
7232 *molecule = 0;
7233 return(TNG_FAILURE);
7234 }
7235 *molecule = &tng_data->molecules[index];
7236 return(TNG_SUCCESS);
7237 }
7238
tng_molecule_system_copy(const tng_trajectory_t tng_data_src,const tng_trajectory_t tng_data_dest)7239 tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src,
7240 const tng_trajectory_t tng_data_dest)
7241 {
7242 tng_molecule_t molecule, molecule_temp;
7243 tng_chain_t chain, chain_temp;
7244 tng_residue_t residue, residue_temp;
7245 tng_atom_t atom, atom_temp;
7246 tng_bond_t bond_temp;
7247 tng_function_status stat;
7248 int64_t i, j, k, l, *list_temp;
7249
7250 TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup.");
7251 TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup.");
7252
7253 for(i = 0; i < tng_data_dest->n_molecules; i++)
7254 {
7255 molecule = &tng_data_dest->molecules[i];
7256 tng_molecule_destroy(tng_data_dest, molecule);
7257 }
7258
7259 tng_data_dest->n_molecules = 0;
7260 tng_data_dest->n_particles = 0;
7261
7262 molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules,
7263 sizeof(struct tng_molecule) * tng_data_src->n_molecules);
7264 if(!molecule_temp)
7265 {
7266 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7267 __FILE__, __LINE__);
7268 free(tng_data_dest->molecules);
7269 tng_data_dest->molecules = 0;
7270 return(TNG_CRITICAL);
7271 }
7272 list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list,
7273 sizeof(int64_t) * tng_data_src->n_molecules);
7274 if(!list_temp)
7275 {
7276 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7277 __FILE__, __LINE__);
7278 free(tng_data_dest->molecule_cnt_list);
7279 tng_data_dest->molecule_cnt_list = 0;
7280 free(molecule_temp);
7281 return(TNG_CRITICAL);
7282 }
7283
7284 tng_data_dest->molecules = molecule_temp;
7285 tng_data_dest->molecule_cnt_list = list_temp;
7286
7287 for(i = 0; i < tng_data_src->n_molecules; i++)
7288 {
7289 molecule = &tng_data_src->molecules[i];
7290 stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id,
7291 &molecule_temp);
7292 if(stat != TNG_SUCCESS)
7293 {
7294 fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n",
7295 __FILE__, __LINE__);
7296 return(stat);
7297 }
7298 molecule_temp->quaternary_str = molecule->quaternary_str;
7299 for(j = 0; j < molecule->n_chains; j++)
7300 {
7301 chain = &molecule->chains[j];
7302 stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp,
7303 chain->name, chain->id,
7304 &chain_temp);
7305 if(stat != TNG_SUCCESS)
7306 {
7307 fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n",
7308 __FILE__, __LINE__);
7309 return(stat);
7310 }
7311 for(k = 0; k < chain->n_residues; k++)
7312 {
7313 residue = &chain->residues[k];
7314 stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp,
7315 residue->name, residue->id,
7316 &residue_temp);
7317 if(stat != TNG_SUCCESS)
7318 {
7319 fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n",
7320 __FILE__, __LINE__);
7321 return(stat);
7322 }
7323 for(l = 0; l < residue->n_atoms; l++)
7324 {
7325 atom = &molecule->atoms[residue->atoms_offset + l];
7326 stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp,
7327 atom->name, atom->atom_type,
7328 atom->id, &atom_temp);
7329 if(stat != TNG_SUCCESS)
7330 {
7331 fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n",
7332 __FILE__, __LINE__);
7333 return(stat);
7334 }
7335 }
7336 }
7337 }
7338 molecule_temp->n_bonds = molecule->n_bonds;
7339 if(molecule->n_bonds > 0)
7340 {
7341 bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
7342 molecule->n_bonds);
7343 if(!bond_temp)
7344 {
7345 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7346 __FILE__, __LINE__);
7347 free(molecule_temp->bonds);
7348 molecule_temp->n_bonds = 0;
7349 return(TNG_CRITICAL);
7350 }
7351 molecule_temp->bonds = bond_temp;
7352 for(j = 0; j < molecule->n_bonds; j++)
7353 {
7354 molecule_temp->bonds[j] = molecule->bonds[j];
7355 }
7356 }
7357 stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp,
7358 tng_data_src->molecule_cnt_list[i]);
7359 if(stat != TNG_SUCCESS)
7360 {
7361 fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n",
7362 __FILE__, __LINE__);
7363 return(stat);
7364 }
7365 }
7366 return(TNG_SUCCESS);
7367 }
7368
tng_molecule_num_chains_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,int64_t * n)7369 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get
7370 (const tng_trajectory_t tng_data,
7371 const tng_molecule_t molecule,
7372 int64_t *n)
7373 {
7374 (void) tng_data;
7375 TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7376 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7377
7378 *n = molecule->n_chains;
7379
7380 return(TNG_SUCCESS);
7381 }
7382
tng_molecule_chain_of_index_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const int64_t index,tng_chain_t * chain)7383 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get
7384 (const tng_trajectory_t tng_data,
7385 const tng_molecule_t molecule,
7386 const int64_t index,
7387 tng_chain_t *chain)
7388 {
7389 (void) tng_data;
7390 TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7391 TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7392
7393 if(index >= molecule->n_chains)
7394 {
7395 *chain = 0;
7396 return(TNG_FAILURE);
7397 }
7398 *chain = &molecule->chains[index];
7399 return(TNG_SUCCESS);
7400 }
7401
tng_molecule_num_residues_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,int64_t * n)7402 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get
7403 (const tng_trajectory_t tng_data,
7404 const tng_molecule_t molecule,
7405 int64_t *n)
7406 {
7407 (void) tng_data;
7408 TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7409 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7410
7411 *n = molecule->n_residues;
7412
7413 return(TNG_SUCCESS);
7414 }
7415
tng_molecule_residue_of_index_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const int64_t index,tng_residue_t * residue)7416 tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get
7417 (const tng_trajectory_t tng_data,
7418 const tng_molecule_t molecule,
7419 const int64_t index,
7420 tng_residue_t *residue)
7421 {
7422 (void) tng_data;
7423 TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7424 TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7425
7426 if(index >= molecule->n_residues)
7427 {
7428 *residue = 0;
7429 return(TNG_FAILURE);
7430 }
7431 *residue = &molecule->residues[index];
7432 return(TNG_SUCCESS);
7433 }
7434
tng_molecule_num_atoms_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,int64_t * n)7435 tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get
7436 (const tng_trajectory_t tng_data,
7437 const tng_molecule_t molecule,
7438 int64_t *n)
7439 {
7440 (void) tng_data;
7441 TNG_ASSERT(molecule, "TNG library: molecule must not be NULL");
7442 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7443
7444 *n = molecule->n_atoms;
7445
7446 return(TNG_SUCCESS);
7447 }
7448
tng_molecule_atom_of_index_get(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const int64_t index,tng_atom_t * atom)7449 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get
7450 (const tng_trajectory_t tng_data,
7451 const tng_molecule_t molecule,
7452 const int64_t index,
7453 tng_atom_t *atom)
7454 {
7455 (void) tng_data;
7456 TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer.");
7457 TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7458
7459 if(index >= molecule->n_atoms)
7460 {
7461 *atom = 0;
7462 return(TNG_FAILURE);
7463 }
7464 *atom = &molecule->atoms[index];
7465 return(TNG_SUCCESS);
7466 }
7467
tng_molecule_chain_find(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const char * name,const int64_t nr,tng_chain_t * chain)7468 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find
7469 (const tng_trajectory_t tng_data,
7470 const tng_molecule_t molecule,
7471 const char *name,
7472 const int64_t nr,
7473 tng_chain_t *chain)
7474 {
7475 int64_t i, n_chains;
7476 (void)tng_data;
7477
7478 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7479 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7480
7481 n_chains = molecule->n_chains;
7482
7483 for(i = n_chains - 1; i >= 0; i--)
7484 {
7485 *chain = &molecule->chains[i];
7486 if(name[0] == 0 || strcmp(name, (*chain)->name) == 0)
7487 {
7488 if(nr == -1 || nr == (*chain)->id)
7489 {
7490 return(TNG_SUCCESS);
7491 }
7492 }
7493 }
7494
7495 *chain = 0;
7496
7497 return(TNG_FAILURE);
7498 }
7499
tng_molecule_chain_add(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const char * name,tng_chain_t * chain)7500 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add
7501 (const tng_trajectory_t tng_data,
7502 const tng_molecule_t molecule,
7503 const char *name,
7504 tng_chain_t *chain)
7505 {
7506 int64_t id;
7507
7508 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7509 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7510
7511 /* Set ID to the ID of the last chain + 1 */
7512 if(molecule->n_chains)
7513 {
7514 id = molecule->chains[molecule->n_chains-1].id + 1;
7515 }
7516 else
7517 {
7518 id = 1;
7519 }
7520
7521 return(tng_molecule_chain_w_id_add(tng_data, molecule, name,
7522 id, chain));
7523 }
7524
tng_molecule_chain_w_id_add(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const char * name,const int64_t id,tng_chain_t * chain)7525 tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add
7526 (const tng_trajectory_t tng_data,
7527 const tng_molecule_t molecule,
7528 const char *name,
7529 const int64_t id,
7530 tng_chain_t *chain)
7531 {
7532 tng_chain_t new_chains;
7533 tng_function_status stat = TNG_SUCCESS;
7534
7535 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7536 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7537
7538 new_chains = (tng_chain_t)realloc(molecule->chains,
7539 sizeof(struct tng_chain) *
7540 (molecule->n_chains + 1));
7541
7542 if(!new_chains)
7543 {
7544 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7545 __FILE__, __LINE__);
7546 free(molecule->chains);
7547 molecule->chains = 0;
7548 return(TNG_CRITICAL);
7549 }
7550
7551 molecule->chains = new_chains;
7552
7553 *chain = &new_chains[molecule->n_chains];
7554 (*chain)->name = 0;
7555
7556 tng_chain_name_set(tng_data, *chain, name);
7557
7558 (*chain)->molecule = molecule;
7559 (*chain)->n_residues = 0;
7560
7561 molecule->n_chains++;
7562
7563 (*chain)->id = id;
7564
7565 return(stat);
7566 }
7567
tng_molecule_bond_add(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const int64_t from_atom_id,const int64_t to_atom_id,tng_bond_t * bond)7568 tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add
7569 (const tng_trajectory_t tng_data,
7570 const tng_molecule_t molecule,
7571 const int64_t from_atom_id,
7572 const int64_t to_atom_id,
7573 tng_bond_t *bond)
7574 {
7575 tng_bond_t new_bonds;
7576 (void)tng_data;
7577
7578 new_bonds = (tng_bond_t)realloc(molecule->bonds,
7579 sizeof(struct tng_bond) *
7580 (molecule->n_bonds + 1));
7581
7582 if(!new_bonds)
7583 {
7584 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7585 __FILE__, __LINE__);
7586 *bond = 0;
7587 free(molecule->bonds);
7588 molecule->bonds = 0;
7589 return(TNG_CRITICAL);
7590 }
7591
7592 molecule->bonds = new_bonds;
7593
7594 *bond = &new_bonds[molecule->n_bonds];
7595
7596 (*bond)->from_atom_id = from_atom_id;
7597 (*bond)->to_atom_id = to_atom_id;
7598
7599 molecule->n_bonds++;
7600
7601 return(TNG_SUCCESS);
7602 }
7603
tng_molecule_atom_find(const tng_trajectory_t tng_data,const tng_molecule_t molecule,const char * name,const int64_t id,tng_atom_t * atom)7604 tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find
7605 (const tng_trajectory_t tng_data,
7606 const tng_molecule_t molecule,
7607 const char *name,
7608 const int64_t id,
7609 tng_atom_t *atom)
7610 {
7611 int64_t i, n_atoms;
7612 (void)tng_data;
7613
7614 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7615
7616 n_atoms = molecule->n_atoms;
7617
7618 for(i = n_atoms - 1; i >= 0; i--)
7619 {
7620 *atom = &molecule->atoms[i];
7621 if(name[0] == 0 || strcmp(name, (*atom)->name) == 0)
7622 {
7623 if(id == -1 || id == (*atom)->id)
7624 {
7625 return(TNG_SUCCESS);
7626 }
7627 }
7628 }
7629
7630 *atom = 0;
7631
7632 return(TNG_FAILURE);
7633 }
7634
tng_chain_name_get(const tng_trajectory_t tng_data,const tng_chain_t chain,char * name,const int max_len)7635 tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data,
7636 const tng_chain_t chain,
7637 char *name,
7638 const int max_len)
7639 {
7640 (void) tng_data;
7641 TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7642 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7643
7644 strncpy(name, chain->name, max_len - 1);
7645 name[max_len - 1] = 0;
7646
7647 if(strlen(chain->name) > (unsigned int)max_len - 1)
7648 {
7649 return(TNG_FAILURE);
7650 }
7651 return(TNG_SUCCESS);
7652 }
7653
tng_chain_name_set(const tng_trajectory_t tng_data,const tng_chain_t chain,const char * new_name)7654 tng_function_status DECLSPECDLLEXPORT tng_chain_name_set
7655 (const tng_trajectory_t tng_data,
7656 const tng_chain_t chain,
7657 const char *new_name)
7658 {
7659 unsigned int len;
7660 (void)tng_data;
7661
7662 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer.");
7663
7664 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7665
7666 /* If the currently stored string length is not enough to store the new
7667 * string it is freed and reallocated. */
7668 if(chain->name && strlen(chain->name) < len)
7669 {
7670 free(chain->name);
7671 chain->name = 0;
7672 }
7673 if(!chain->name)
7674 {
7675 chain->name = (char *)malloc(len);
7676 if(!chain->name)
7677 {
7678 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7679 __FILE__, __LINE__);
7680 return(TNG_CRITICAL);
7681 }
7682 }
7683
7684 strncpy(chain->name, new_name, len);
7685
7686 return(TNG_SUCCESS);
7687 }
7688
tng_chain_num_residues_get(const tng_trajectory_t tng_data,const tng_chain_t chain,int64_t * n)7689 tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get
7690 (const tng_trajectory_t tng_data,
7691 const tng_chain_t chain,
7692 int64_t *n)
7693 {
7694 (void) tng_data;
7695 TNG_ASSERT(chain, "TNG library: chain must not be NULL");
7696 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7697
7698 *n = chain->n_residues;
7699
7700 return(TNG_SUCCESS);
7701 }
7702
tng_chain_residue_of_index_get(const tng_trajectory_t tng_data,const tng_chain_t chain,const int64_t index,tng_residue_t * residue)7703 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get
7704 (const tng_trajectory_t tng_data,
7705 const tng_chain_t chain,
7706 const int64_t index,
7707 tng_residue_t *residue)
7708 {
7709 (void) tng_data;
7710 TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer.");
7711 TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7712
7713 if(index >= chain->n_residues)
7714 {
7715 *residue = 0;
7716 return(TNG_FAILURE);
7717 }
7718 *residue = &chain->residues[index];
7719 return(TNG_SUCCESS);
7720 }
7721
tng_chain_residue_find(const tng_trajectory_t tng_data,const tng_chain_t chain,const char * name,const int64_t id,tng_residue_t * residue)7722 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find
7723 (const tng_trajectory_t tng_data,
7724 const tng_chain_t chain,
7725 const char *name,
7726 const int64_t id,
7727 tng_residue_t *residue)
7728 {
7729 int64_t i, n_residues;
7730 (void)tng_data;
7731
7732 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7733
7734 n_residues = chain->n_residues;
7735
7736 for(i = n_residues - 1; i >= 0; i--)
7737 {
7738 *residue = &chain->residues[i];
7739 if(name[0] == 0 || strcmp(name, (*residue)->name) == 0)
7740 {
7741 if(id == -1 || id == (*residue)->id)
7742 {
7743 return(TNG_SUCCESS);
7744 }
7745 }
7746 }
7747
7748 *residue = 0;
7749
7750 return(TNG_FAILURE);
7751 }
7752
tng_chain_residue_add(const tng_trajectory_t tng_data,const tng_chain_t chain,const char * name,tng_residue_t * residue)7753 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add
7754 (const tng_trajectory_t tng_data,
7755 const tng_chain_t chain,
7756 const char *name,
7757 tng_residue_t *residue)
7758 {
7759 int64_t id;
7760
7761 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7762 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7763
7764 /* Set ID to the ID of the last residue + 1 */
7765 if(chain->n_residues)
7766 {
7767 id = chain->residues[chain->n_residues-1].id + 1;
7768 }
7769 else
7770 {
7771 id = 0;
7772 }
7773
7774 return(tng_chain_residue_w_id_add(tng_data, chain, name,
7775 id, residue));
7776 }
7777
tng_chain_residue_w_id_add(const tng_trajectory_t tng_data,const tng_chain_t chain,const char * name,const int64_t id,tng_residue_t * residue)7778 tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add
7779 (const tng_trajectory_t tng_data,
7780 const tng_chain_t chain,
7781 const char *name,
7782 const int64_t id,
7783 tng_residue_t *residue)
7784 {
7785 int64_t curr_index;
7786 tng_residue_t new_residues, temp_residue, last_residue;
7787 tng_molecule_t molecule = chain->molecule;
7788 tng_function_status stat = TNG_SUCCESS;
7789
7790 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7791 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
7792
7793 if(chain->n_residues)
7794 {
7795 curr_index = chain->residues - molecule->residues;
7796 }
7797 else
7798 {
7799 curr_index = -1;
7800 }
7801
7802 new_residues = (tng_residue_t)realloc(molecule->residues,
7803 sizeof(struct tng_residue) *
7804 (molecule->n_residues + 1));
7805
7806 if(!new_residues)
7807 {
7808 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7809 __FILE__, __LINE__);
7810 free(molecule->residues);
7811 molecule->residues = 0;
7812 return(TNG_CRITICAL);
7813 }
7814
7815 molecule->residues = new_residues;
7816
7817 if(curr_index != -1)
7818 {
7819 chain->residues = new_residues + curr_index;
7820 if(molecule->n_residues)
7821 {
7822 last_residue = &new_residues[molecule->n_residues - 1];
7823
7824 temp_residue = chain->residues + (chain->n_residues - 1);
7825 /* Make space in list of residues to add the new residues together with the other
7826 * residues of this chain */
7827 if(temp_residue != last_residue)
7828 {
7829 ++temp_residue;
7830 memmove(temp_residue + 1, temp_residue,
7831 last_residue - temp_residue);
7832 }
7833 }
7834 }
7835 else
7836 {
7837 curr_index = molecule->n_residues;
7838 }
7839
7840 *residue = &molecule->residues[curr_index + chain->n_residues];
7841
7842 tng_molecule_chains_residue_pointers_update(tng_data, molecule);
7843 tng_molecule_atoms_residue_pointers_update(tng_data, molecule);
7844
7845 (*residue)->name = 0;
7846 tng_residue_name_set(tng_data, *residue, name);
7847
7848 (*residue)->chain = chain;
7849 (*residue)->n_atoms = 0;
7850 (*residue)->atoms_offset = 0;
7851
7852 chain->n_residues++;
7853 molecule->n_residues++;
7854
7855 (*residue)->id = id;
7856
7857 return(stat);
7858 }
7859
tng_residue_name_get(const tng_trajectory_t tng_data,const tng_residue_t residue,char * name,const int max_len)7860 tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data,
7861 const tng_residue_t residue,
7862 char *name,
7863 const int max_len)
7864 {
7865 (void) tng_data;
7866 TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7867 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
7868
7869 strncpy(name, residue->name, max_len - 1);
7870 name[max_len - 1] = 0;
7871
7872 if(strlen(residue->name) > (unsigned int)max_len - 1)
7873 {
7874 return(TNG_FAILURE);
7875 }
7876 return(TNG_SUCCESS);
7877 }
7878
tng_residue_name_set(const tng_trajectory_t tng_data,const tng_residue_t residue,const char * new_name)7879 tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_t tng_data,
7880 const tng_residue_t residue,
7881 const char *new_name)
7882 {
7883 unsigned int len;
7884 (void)tng_data;
7885
7886 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7887 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
7888
7889 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
7890
7891 /* If the currently stored string length is not enough to store the new
7892 * string it is freed and reallocated. */
7893 if(residue->name && strlen(residue->name) < len)
7894 {
7895 free(residue->name);
7896 residue->name = 0;
7897 }
7898 if(!residue->name)
7899 {
7900 residue->name = (char *)malloc(len);
7901 if(!residue->name)
7902 {
7903 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
7904 __FILE__, __LINE__);
7905 return(TNG_CRITICAL);
7906 }
7907 }
7908
7909 strncpy(residue->name, new_name, len);
7910
7911 return(TNG_SUCCESS);
7912 }
7913
tng_residue_num_atoms_get(const tng_trajectory_t tng_data,const tng_residue_t residue,int64_t * n)7914 tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get
7915 (const tng_trajectory_t tng_data,
7916 const tng_residue_t residue,
7917 int64_t *n)
7918 {
7919 (void) tng_data;
7920 TNG_ASSERT(residue, "TNG library: residue must not be NULL");
7921 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
7922
7923 *n = residue->n_atoms;
7924
7925 return(TNG_SUCCESS);
7926 }
7927
tng_residue_atom_of_index_get(const tng_trajectory_t tng_data,const tng_residue_t residue,const int64_t index,tng_atom_t * atom)7928 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get
7929 (const tng_trajectory_t tng_data,
7930 const tng_residue_t residue,
7931 const int64_t index,
7932 tng_atom_t *atom)
7933 {
7934 tng_chain_t chain;
7935 tng_molecule_t molecule;
7936
7937 (void) tng_data;
7938 TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer.");
7939 TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer.");
7940
7941 if(index >= residue->n_atoms)
7942 {
7943 *atom = 0;
7944 return(TNG_FAILURE);
7945 }
7946 chain = residue->chain;
7947 molecule = chain->molecule;
7948
7949 if(index + residue->atoms_offset >= molecule->n_atoms)
7950 {
7951 *atom = 0;
7952 return(TNG_FAILURE);
7953 }
7954
7955 *atom = &molecule->atoms[residue->atoms_offset + index];
7956 return(TNG_SUCCESS);
7957 }
7958
tng_residue_atom_add(const tng_trajectory_t tng_data,const tng_residue_t residue,const char * atom_name,const char * atom_type,tng_atom_t * atom)7959 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add
7960 (const tng_trajectory_t tng_data,
7961 const tng_residue_t residue,
7962 const char *atom_name,
7963 const char *atom_type,
7964 tng_atom_t *atom)
7965 {
7966 int64_t id;
7967
7968 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7969 TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
7970 TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
7971
7972 /* Set ID to the ID of the last atom + 1 */
7973 if(residue->chain->molecule->n_atoms)
7974 {
7975 id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1;
7976 }
7977 else
7978 {
7979 id = 0;
7980 }
7981
7982 return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type,
7983 id, atom));
7984 }
7985
tng_residue_atom_w_id_add(const tng_trajectory_t tng_data,const tng_residue_t residue,const char * atom_name,const char * atom_type,const int64_t id,tng_atom_t * atom)7986 tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add
7987 (const tng_trajectory_t tng_data,
7988 const tng_residue_t residue,
7989 const char *atom_name,
7990 const char *atom_type,
7991 const int64_t id,
7992 tng_atom_t *atom)
7993 {
7994 tng_atom_t new_atoms;
7995 tng_molecule_t molecule = residue->chain->molecule;
7996 tng_function_status stat = TNG_SUCCESS;
7997
7998 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
7999 TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer.");
8000 TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer.");
8001
8002 if(!residue->n_atoms)
8003 {
8004 residue->atoms_offset = molecule->n_atoms;
8005 }
8006
8007 new_atoms = (tng_atom_t)realloc(molecule->atoms,
8008 sizeof(struct tng_atom) *
8009 (molecule->n_atoms + 1));
8010
8011 if(!new_atoms)
8012 {
8013 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8014 __FILE__, __LINE__);
8015 free(molecule->atoms);
8016 molecule->atoms = 0;
8017 return(TNG_CRITICAL);
8018 }
8019
8020 molecule->atoms = new_atoms;
8021
8022 *atom = &new_atoms[molecule->n_atoms];
8023
8024 tng_atom_init(*atom);
8025 tng_atom_name_set(tng_data, *atom, atom_name);
8026 tng_atom_type_set(tng_data, *atom, atom_type);
8027
8028 (*atom)->residue = residue;
8029
8030 residue->n_atoms++;
8031 molecule->n_atoms++;
8032
8033 (*atom)->id = id;
8034
8035 return(stat);
8036 }
8037
tng_molecule_alloc(const tng_trajectory_t tng_data,tng_molecule_t * molecule_p)8038 tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
8039 tng_molecule_t *molecule_p)
8040 {
8041 *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule));
8042 if(!*molecule_p)
8043 {
8044 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8045 __FILE__, __LINE__);
8046 return(TNG_CRITICAL);
8047 }
8048
8049 tng_molecule_init(tng_data, *molecule_p);
8050
8051 return(TNG_SUCCESS);
8052 }
8053
tng_molecule_free(const tng_trajectory_t tng_data,tng_molecule_t * molecule_p)8054 tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data,
8055 tng_molecule_t *molecule_p)
8056 {
8057 if(!*molecule_p)
8058 {
8059 return(TNG_SUCCESS);
8060 }
8061
8062 tng_molecule_destroy(tng_data, *molecule_p);
8063
8064 free(*molecule_p);
8065 *molecule_p = 0;
8066
8067 return(TNG_SUCCESS);
8068 }
8069
tng_molecule_init(const tng_trajectory_t tng_data,const tng_molecule_t molecule)8070 tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data,
8071 const tng_molecule_t molecule)
8072 {
8073 (void)tng_data;
8074 molecule->quaternary_str = 1;
8075 molecule->name = 0;
8076 molecule->n_chains = 0;
8077 molecule->chains = 0;
8078 molecule->n_residues = 0;
8079 molecule->residues = 0;
8080 molecule->n_atoms = 0;
8081 molecule->atoms = 0;
8082 molecule->n_bonds = 0;
8083 molecule->bonds = 0;
8084
8085 return(TNG_SUCCESS);
8086 }
8087
tng_molecule_destroy(const tng_trajectory_t tng_data,const tng_molecule_t molecule)8088 tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data,
8089 const tng_molecule_t molecule)
8090 {
8091 int64_t i;
8092 (void)tng_data;
8093
8094 if(molecule->name)
8095 {
8096 free(molecule->name);
8097 molecule->name = 0;
8098 }
8099
8100 if(molecule->chains)
8101 {
8102 for(i = 0; i < molecule->n_chains; i++)
8103 {
8104 if(molecule->chains[i].name)
8105 {
8106 free(molecule->chains[i].name);
8107 molecule->chains[i].name = 0;
8108 }
8109 }
8110 free(molecule->chains);
8111 molecule->chains = 0;
8112 }
8113 molecule->n_chains = 0;
8114
8115 if(molecule->residues)
8116 {
8117 for(i = 0; i < molecule->n_residues; i++)
8118 {
8119 if(molecule->residues[i].name)
8120 {
8121 free(molecule->residues[i].name);
8122 molecule->residues[i].name = 0;
8123 }
8124 }
8125 free(molecule->residues);
8126 molecule->residues = 0;
8127 }
8128 molecule->n_residues = 0;
8129
8130 if(molecule->atoms)
8131 {
8132 for(i = 0; i < molecule->n_atoms; i++)
8133 {
8134 tng_atom_destroy(&molecule->atoms[i]);
8135 }
8136 free(molecule->atoms);
8137 molecule->atoms = 0;
8138 }
8139 molecule->n_atoms = 0;
8140
8141 if(molecule->bonds)
8142 {
8143 free(molecule->bonds);
8144 molecule->bonds = 0;
8145 }
8146 molecule->n_bonds = 0;
8147
8148 return(TNG_SUCCESS);
8149 }
8150
tng_molecule_name_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,char * name,const int max_len)8151 tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get
8152 (const tng_trajectory_t tng_data,
8153 const int64_t nr,
8154 char *name,
8155 const int max_len)
8156 {
8157 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8158 tng_molecule_t mol;
8159 tng_bool found = TNG_FALSE;
8160
8161 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8162 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8163
8164 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8165
8166 if(!molecule_cnt_list)
8167 {
8168 return(TNG_FAILURE);
8169 }
8170
8171 for(i = 0; i < tng_data->n_molecules; i++)
8172 {
8173 mol = &tng_data->molecules[i];
8174 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8175 {
8176 cnt += mol->n_atoms * molecule_cnt_list[i];
8177 continue;
8178 }
8179 found = TNG_TRUE;
8180 break;
8181 }
8182 if(!found)
8183 {
8184 return(TNG_FAILURE);
8185 }
8186
8187 strncpy(name, mol->name, max_len - 1);
8188 name[max_len - 1] = 0;
8189
8190 if(strlen(mol->name) > (unsigned int)max_len - 1)
8191 {
8192 return(TNG_FAILURE);
8193 }
8194 return(TNG_SUCCESS);
8195 }
8196
tng_molecule_id_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,int64_t * id)8197 tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get
8198 (const tng_trajectory_t tng_data,
8199 const int64_t nr,
8200 int64_t *id)
8201 {
8202 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8203 tng_molecule_t mol;
8204 tng_bool found = TNG_FALSE;
8205
8206 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8207 TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8208
8209 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8210
8211 if(!molecule_cnt_list)
8212 {
8213 return(TNG_FAILURE);
8214 }
8215
8216 for(i = 0; i < tng_data->n_molecules; i++)
8217 {
8218 mol = &tng_data->molecules[i];
8219 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8220 {
8221 cnt += mol->n_atoms * molecule_cnt_list[i];
8222 continue;
8223 }
8224 found = TNG_TRUE;
8225 break;
8226 }
8227 if(!found)
8228 {
8229 return(TNG_FAILURE);
8230 }
8231
8232 *id = mol->id;
8233
8234 return(TNG_SUCCESS);
8235 }
8236
tng_molsystem_bonds_get(const tng_trajectory_t tng_data,int64_t * n_bonds,int64_t ** from_atoms,int64_t ** to_atoms)8237 tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get
8238 (const tng_trajectory_t tng_data,
8239 int64_t *n_bonds,
8240 int64_t **from_atoms,
8241 int64_t **to_atoms)
8242 {
8243 int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k;
8244 int64_t from_atom, to_atom, *molecule_cnt_list = 0;
8245 tng_molecule_t mol;
8246 tng_bond_t bond;
8247
8248 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8249 TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer.");
8250 TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer.");
8251 TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer.");
8252
8253 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8254
8255 if(!molecule_cnt_list)
8256 {
8257 return(TNG_FAILURE);
8258 }
8259
8260 *n_bonds = 0;
8261 /* First count the total number of bonds to allocate memory */
8262 for(i = 0; i < tng_data->n_molecules; i++)
8263 {
8264 mol = &tng_data->molecules[i];
8265 mol_cnt = molecule_cnt_list[i];
8266 *n_bonds += mol_cnt * mol->n_bonds;
8267 }
8268 if(*n_bonds == 0)
8269 {
8270 return(TNG_SUCCESS);
8271 }
8272
8273 *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8274 if(!*from_atoms)
8275 {
8276 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8277 __FILE__, __LINE__);
8278 return(TNG_CRITICAL);
8279 }
8280 *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
8281 if(!*to_atoms)
8282 {
8283 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8284 __FILE__, __LINE__);
8285 free(*from_atoms);
8286 *from_atoms = 0;
8287 return(TNG_CRITICAL);
8288 }
8289
8290 cnt = 0;
8291 for(i = 0; i < tng_data->n_molecules; i++)
8292 {
8293 mol = &tng_data->molecules[i];
8294 mol_cnt = molecule_cnt_list[i];
8295 for(j = 0; j < mol_cnt; j++)
8296 {
8297 for(k = 0; k < mol->n_bonds; k++)
8298 {
8299 bond = &mol->bonds[k];
8300 from_atom = atom_cnt + bond->from_atom_id;
8301 to_atom = atom_cnt + bond->to_atom_id;
8302 (*from_atoms)[cnt] = from_atom;
8303 (*to_atoms)[cnt++] = to_atom;
8304 }
8305 atom_cnt += mol->n_atoms;
8306 }
8307 }
8308
8309 return(TNG_SUCCESS);
8310 }
8311
tng_chain_name_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,char * name,const int max_len)8312 tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get
8313 (const tng_trajectory_t tng_data,
8314 const int64_t nr,
8315 char *name,
8316 const int max_len)
8317 {
8318 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8319 tng_molecule_t mol;
8320 tng_atom_t atom;
8321 tng_bool found = TNG_FALSE;
8322
8323 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8324 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8325
8326 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8327
8328 if(!molecule_cnt_list)
8329 {
8330 return(TNG_FAILURE);
8331 }
8332
8333 for(i = 0; i < tng_data->n_molecules; i++)
8334 {
8335 mol = &tng_data->molecules[i];
8336 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8337 {
8338 cnt += mol->n_atoms * molecule_cnt_list[i];
8339 continue;
8340 }
8341 atom = &mol->atoms[nr % mol->n_atoms];
8342 found = TNG_TRUE;
8343 break;
8344 }
8345 if(!found)
8346 {
8347 return(TNG_FAILURE);
8348 }
8349 if(!atom->residue || !atom->residue->chain)
8350 {
8351 return(TNG_FAILURE);
8352 }
8353
8354 strncpy(name, atom->residue->chain->name, max_len - 1);
8355 name[max_len - 1] = 0;
8356
8357 if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1)
8358 {
8359 return(TNG_FAILURE);
8360 }
8361 return(TNG_SUCCESS);
8362 }
8363
tng_residue_name_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,char * name,const int max_len)8364 tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get
8365 (const tng_trajectory_t tng_data,
8366 const int64_t nr,
8367 char *name,
8368 const int max_len)
8369 {
8370 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8371 tng_molecule_t mol;
8372 tng_atom_t atom;
8373 tng_bool found = TNG_FALSE;
8374
8375 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8376 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8377
8378 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8379
8380 if(!molecule_cnt_list)
8381 {
8382 return(TNG_FAILURE);
8383 }
8384
8385 for(i = 0; i < tng_data->n_molecules; i++)
8386 {
8387 mol = &tng_data->molecules[i];
8388 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8389 {
8390 cnt += mol->n_atoms * molecule_cnt_list[i];
8391 continue;
8392 }
8393 atom = &mol->atoms[nr % mol->n_atoms];
8394 found = TNG_TRUE;
8395 break;
8396 }
8397 if(!found)
8398 {
8399 return(TNG_FAILURE);
8400 }
8401 if(!atom->residue)
8402 {
8403 return(TNG_FAILURE);
8404 }
8405
8406 strncpy(name, atom->residue->name, max_len - 1);
8407 name[max_len - 1] = 0;
8408
8409 if(strlen(atom->residue->name) > (unsigned int)max_len - 1)
8410 {
8411 return(TNG_FAILURE);
8412 }
8413 return(TNG_SUCCESS);
8414 }
8415
tng_residue_id_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,int64_t * id)8416 tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get
8417 (const tng_trajectory_t tng_data,
8418 const int64_t nr,
8419 int64_t *id)
8420 {
8421 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8422 tng_molecule_t mol;
8423 tng_atom_t atom;
8424 tng_bool found = TNG_FALSE;
8425
8426 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8427 TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8428
8429 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8430
8431 if(!molecule_cnt_list)
8432 {
8433 return(TNG_FAILURE);
8434 }
8435
8436 for(i = 0; i < tng_data->n_molecules; i++)
8437 {
8438 mol = &tng_data->molecules[i];
8439 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8440 {
8441 cnt += mol->n_atoms * molecule_cnt_list[i];
8442 continue;
8443 }
8444 atom = &mol->atoms[nr % mol->n_atoms];
8445 found = TNG_TRUE;
8446 break;
8447 }
8448 if(!found)
8449 {
8450 return(TNG_FAILURE);
8451 }
8452 if(!atom->residue)
8453 {
8454 return(TNG_FAILURE);
8455 }
8456
8457 *id = atom->residue->id;
8458
8459 return(TNG_SUCCESS);
8460 }
8461
tng_global_residue_id_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,int64_t * id)8462 tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get
8463 (const tng_trajectory_t tng_data,
8464 const int64_t nr,
8465 int64_t *id)
8466 {
8467 int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0;
8468 tng_molecule_t mol;
8469 tng_atom_t atom;
8470 tng_bool found = TNG_FALSE;
8471
8472 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8473 TNG_ASSERT(id, "TNG library: id must not be a NULL pointer.");
8474
8475 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8476
8477 if(!molecule_cnt_list)
8478 {
8479 return(TNG_FAILURE);
8480 }
8481
8482 for(i = 0; i < tng_data->n_molecules; i++)
8483 {
8484 mol = &tng_data->molecules[i];
8485 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8486 {
8487 cnt += mol->n_atoms * molecule_cnt_list[i];
8488 offset += mol->n_residues * molecule_cnt_list[i];
8489 continue;
8490 }
8491 atom = &mol->atoms[nr % mol->n_atoms];
8492 found = TNG_TRUE;
8493 break;
8494 }
8495 if(!found)
8496 {
8497 return(TNG_FAILURE);
8498 }
8499 if(!atom->residue)
8500 {
8501 return(TNG_FAILURE);
8502 }
8503
8504 offset += mol->n_residues * ((nr - cnt) / mol->n_atoms);
8505
8506 *id = atom->residue->id + offset;
8507
8508 return(TNG_SUCCESS);
8509 }
8510
tng_atom_name_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,char * name,const int max_len)8511 tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get
8512 (const tng_trajectory_t tng_data,
8513 const int64_t nr,
8514 char *name,
8515 const int max_len)
8516 {
8517 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8518 tng_molecule_t mol;
8519 tng_atom_t atom;
8520 tng_bool found = TNG_FALSE;
8521
8522 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8523 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
8524
8525 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8526
8527 if(!molecule_cnt_list)
8528 {
8529 return(TNG_FAILURE);
8530 }
8531
8532 for(i = 0; i < tng_data->n_molecules; i++)
8533 {
8534 mol = &tng_data->molecules[i];
8535 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8536 {
8537 cnt += mol->n_atoms * molecule_cnt_list[i];
8538 continue;
8539 }
8540 atom = &mol->atoms[nr % mol->n_atoms];
8541 found = TNG_TRUE;
8542 break;
8543 }
8544 if(!found)
8545 {
8546 return(TNG_FAILURE);
8547 }
8548
8549 strncpy(name, atom->name, max_len - 1);
8550 name[max_len - 1] = 0;
8551
8552 if(strlen(atom->name) > (unsigned int)max_len - 1)
8553 {
8554 return(TNG_FAILURE);
8555 }
8556 return(TNG_SUCCESS);
8557 }
8558
tng_atom_type_of_particle_nr_get(const tng_trajectory_t tng_data,const int64_t nr,char * type,const int max_len)8559 tng_function_status tng_atom_type_of_particle_nr_get
8560 (const tng_trajectory_t tng_data,
8561 const int64_t nr,
8562 char *type,
8563 const int max_len)
8564 {
8565 int64_t cnt = 0, i, *molecule_cnt_list = 0;
8566 tng_molecule_t mol;
8567 tng_atom_t atom;
8568 tng_bool found = TNG_FALSE;
8569
8570 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8571 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
8572
8573 tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list);
8574
8575 if(!molecule_cnt_list)
8576 {
8577 return(TNG_FAILURE);
8578 }
8579
8580 for(i = 0; i < tng_data->n_molecules; i++)
8581 {
8582 mol = &tng_data->molecules[i];
8583 if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr)
8584 {
8585 cnt += mol->n_atoms * molecule_cnt_list[i];
8586 continue;
8587 }
8588 atom = &mol->atoms[nr % mol->n_atoms];
8589 found = TNG_TRUE;
8590 break;
8591 }
8592 if(!found)
8593 {
8594 return(TNG_FAILURE);
8595 }
8596
8597 strncpy(type, atom->atom_type, max_len - 1);
8598 type[max_len - 1] = 0;
8599
8600 if(strlen(atom->atom_type) > (unsigned int)max_len - 1)
8601 {
8602 return(TNG_FAILURE);
8603 }
8604 return(TNG_SUCCESS);
8605 }
8606
tng_particle_mapping_add(const tng_trajectory_t tng_data,const int64_t num_first_particle,const int64_t n_particles,const int64_t * mapping_table)8607 tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add
8608 (const tng_trajectory_t tng_data,
8609 const int64_t num_first_particle,
8610 const int64_t n_particles,
8611 const int64_t *mapping_table)
8612 {
8613 int64_t i;
8614 tng_particle_mapping_t mapping;
8615 tng_trajectory_frame_set_t frame_set;
8616
8617 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8618
8619 frame_set = &tng_data->current_trajectory_frame_set;
8620
8621 /* Sanity check of the particle ranges. Split into multiple if
8622 * statements for improved readability */
8623 for(i = 0; i < frame_set->n_mapping_blocks; i++)
8624 {
8625 mapping = &frame_set->mappings[i];
8626 if(num_first_particle >= mapping->num_first_particle &&
8627 num_first_particle < mapping->num_first_particle +
8628 mapping->n_particles)
8629 {
8630 fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8631 return(TNG_FAILURE);
8632 }
8633 if(num_first_particle + n_particles >=
8634 mapping->num_first_particle &&
8635 num_first_particle + n_particles <
8636 mapping->num_first_particle + mapping->n_particles)
8637 {
8638 fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8639 return(TNG_FAILURE);
8640 }
8641 if(mapping->num_first_particle >= num_first_particle &&
8642 mapping->num_first_particle < num_first_particle +
8643 n_particles)
8644 {
8645 fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8646 return(TNG_FAILURE);
8647 }
8648 if(mapping->num_first_particle + mapping->n_particles >
8649 num_first_particle &&
8650 mapping->num_first_particle + mapping->n_particles <
8651 num_first_particle + n_particles)
8652 {
8653 fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__);
8654 return(TNG_FAILURE);
8655 }
8656 }
8657
8658 frame_set->n_mapping_blocks++;
8659
8660 mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
8661 frame_set->n_mapping_blocks);
8662
8663 if(!mapping)
8664 {
8665 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8666 __FILE__, __LINE__);
8667 free(frame_set->mappings);
8668 frame_set->mappings = 0;
8669 return(TNG_CRITICAL);
8670 }
8671 frame_set->mappings = mapping;
8672
8673 frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
8674 frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
8675
8676 frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles);
8677 if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
8678 {
8679 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8680 __FILE__, __LINE__);
8681 return(TNG_CRITICAL);
8682 }
8683
8684 for(i=0; i<n_particles; i++)
8685 {
8686 frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i];
8687 }
8688
8689 return(TNG_SUCCESS);
8690 }
8691
tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data)8692 tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data)
8693 {
8694 tng_trajectory_frame_set_t frame_set;
8695 tng_particle_mapping_t mapping;
8696 int64_t i;
8697
8698 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
8699
8700 frame_set = &tng_data->current_trajectory_frame_set;
8701
8702 if(frame_set->n_mapping_blocks && frame_set->mappings)
8703 {
8704 for(i = 0; i < frame_set->n_mapping_blocks; i++)
8705 {
8706 mapping = &frame_set->mappings[i];
8707 if(mapping->real_particle_numbers)
8708 {
8709 free(mapping->real_particle_numbers);
8710 mapping->real_particle_numbers = 0;
8711 }
8712 }
8713 free(frame_set->mappings);
8714 frame_set->mappings = 0;
8715 frame_set->n_mapping_blocks = 0;
8716 }
8717
8718 return(TNG_SUCCESS);
8719 }
8720
tng_trajectory_init(tng_trajectory_t * tng_data_p)8721 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p)
8722 {
8723 time_t seconds;
8724 tng_trajectory_frame_set_t frame_set;
8725 tng_trajectory_t tng_data;
8726
8727 *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
8728 if(!*tng_data_p)
8729 {
8730 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
8731 __FILE__, __LINE__);
8732 return(TNG_CRITICAL);
8733 }
8734
8735 tng_data = *tng_data_p;
8736
8737 frame_set = &tng_data->current_trajectory_frame_set;
8738
8739 tng_data->input_file_path = 0;
8740 tng_data->input_file = 0;
8741 tng_data->input_file_len = 0;
8742 tng_data->output_file_path = 0;
8743 tng_data->output_file = 0;
8744
8745 tng_data->first_program_name = 0;
8746 tng_data->first_user_name = 0;
8747 tng_data->first_computer_name = 0;
8748 tng_data->first_pgp_signature = 0;
8749 tng_data->last_program_name = 0;
8750 tng_data->last_user_name = 0;
8751 tng_data->last_computer_name = 0;
8752 tng_data->last_pgp_signature = 0;
8753 tng_data->forcefield_name = 0;
8754
8755 seconds = time(0);
8756 if ( seconds == -1)
8757 {
8758 fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__);
8759 }
8760 else
8761 {
8762 tng_data->time = seconds;
8763 }
8764
8765 tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS;
8766 tng_data->first_trajectory_frame_set_input_file_pos = -1;
8767 tng_data->last_trajectory_frame_set_input_file_pos = -1;
8768 tng_data->current_trajectory_frame_set_input_file_pos = -1;
8769 tng_data->first_trajectory_frame_set_output_file_pos = -1;
8770 tng_data->last_trajectory_frame_set_output_file_pos = -1;
8771 tng_data->current_trajectory_frame_set_output_file_pos = -1;
8772 tng_data->frame_set_n_frames = 100;
8773 tng_data->n_trajectory_frame_sets = 0;
8774 tng_data->medium_stride_length = 100;
8775 tng_data->long_stride_length = 10000;
8776
8777 tng_data->time_per_frame = -1;
8778
8779 tng_data->n_particle_data_blocks = 0;
8780 tng_data->n_data_blocks = 0;
8781
8782 tng_data->non_tr_particle_data = 0;
8783 tng_data->non_tr_data = 0;
8784
8785 tng_data->compress_algo_pos = 0;
8786 tng_data->compress_algo_vel = 0;
8787 tng_data->compression_precision = 1000;
8788 tng_data->distance_unit_exponential = -9;
8789
8790 frame_set->first_frame = -1;
8791 frame_set->n_mapping_blocks = 0;
8792 frame_set->mappings = 0;
8793 frame_set->molecule_cnt_list = 0;
8794
8795 frame_set->n_particle_data_blocks = 0;
8796 frame_set->n_data_blocks = 0;
8797
8798 frame_set->tr_particle_data = 0;
8799 frame_set->tr_data = 0;
8800
8801 frame_set->n_written_frames = 0;
8802 frame_set->n_unwritten_frames = 0;
8803
8804 frame_set->next_frame_set_file_pos = -1;
8805 frame_set->prev_frame_set_file_pos = -1;
8806 frame_set->medium_stride_next_frame_set_file_pos = -1;
8807 frame_set->medium_stride_prev_frame_set_file_pos = -1;
8808 frame_set->long_stride_next_frame_set_file_pos = -1;
8809 frame_set->long_stride_prev_frame_set_file_pos = -1;
8810
8811 frame_set->first_frame_time = -1;
8812
8813 tng_data->n_molecules = 0;
8814 tng_data->molecules = 0;
8815 tng_data->molecule_cnt_list = 0;
8816 tng_data->n_particles = 0;
8817
8818 {
8819 /* Check the endianness of the computer */
8820 static int32_t endianness_32 = 0x01234567;
8821 /* 0x01234567 */
8822 if ( *(const unsigned char*)&endianness_32 == 0x01 )
8823 {
8824 tng_data->endianness_32 = TNG_BIG_ENDIAN_32;
8825 }
8826
8827 /* 0x67452301 */
8828 else if( *(const unsigned char*)&endianness_32 == 0x67 )
8829 {
8830 tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32;
8831
8832 }
8833
8834 /* 0x45670123 */
8835 else if ( *(const unsigned char*)&endianness_32 == 0x45 )
8836 {
8837 tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32;
8838 }
8839 }
8840 {
8841 static int64_t endianness_64 = 0x0123456789ABCDEFLL;
8842 /* 0x0123456789ABCDEF */
8843 if ( *(const unsigned char*)&endianness_64 == 0x01 )
8844 {
8845 tng_data->endianness_64 = TNG_BIG_ENDIAN_64;
8846 }
8847
8848 /* 0xEFCDAB8967452301 */
8849 else if ( *(const unsigned char*)&endianness_64 == 0xEF )
8850 {
8851 tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64;
8852 }
8853
8854 /* 0x89ABCDEF01234567 */
8855 else if ( *(const unsigned char*)&endianness_64 == 0x89 )
8856 {
8857 tng_data->endianness_64 = TNG_QUAD_SWAP_64;
8858 }
8859
8860 /* 0x45670123CDEF89AB */
8861 else if ( *(const unsigned char*)&endianness_64 == 0x45 )
8862 {
8863 tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64;
8864 }
8865
8866 /* 0x23016745AB89EFCD */
8867 else if ( *(const unsigned char*)&endianness_64 == 0x23 )
8868 {
8869 tng_data->endianness_64 = TNG_BYTE_SWAP_64;
8870 }
8871 }
8872
8873 /* By default do not swap the byte order, i.e. keep the byte order of the
8874 * architecture. The input file endianness will be set when reading the
8875 * header. The output endianness can be changed - before the file is
8876 * written. */
8877 tng_data->input_endianness_swap_func_32 = 0;
8878 tng_data->input_endianness_swap_func_64 = 0;
8879 tng_data->output_endianness_swap_func_32 = 0;
8880 tng_data->output_endianness_swap_func_64 = 0;
8881
8882 tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1;
8883 tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
8884 tng_data->current_trajectory_frame_set.n_frames = 0;
8885
8886 return(TNG_SUCCESS);
8887 }
8888
tng_trajectory_destroy(tng_trajectory_t * tng_data_p)8889 tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p)
8890 {
8891 int64_t i, j, k, l;
8892 int64_t n_particles, n_values_per_frame;
8893 tng_trajectory_t tng_data = *tng_data_p;
8894 tng_trajectory_frame_set_t frame_set;
8895
8896 if(!*tng_data_p)
8897 {
8898 return(TNG_SUCCESS);
8899 }
8900
8901 frame_set = &tng_data->current_trajectory_frame_set;
8902
8903 if(tng_data->input_file)
8904 {
8905 if(tng_data->output_file == tng_data->input_file)
8906 {
8907 tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8908 tng_data->output_file = 0;
8909 }
8910 fclose(tng_data->input_file);
8911 tng_data->input_file = 0;
8912 }
8913
8914 if(tng_data->input_file_path)
8915 {
8916 free(tng_data->input_file_path);
8917 tng_data->input_file_path = 0;
8918 }
8919
8920 if(tng_data->output_file)
8921 {
8922 /* FIXME: Do not always write the hash */
8923 tng_frame_set_finalize(tng_data, TNG_USE_HASH);
8924 fclose(tng_data->output_file);
8925 tng_data->output_file = 0;
8926 }
8927
8928 if(tng_data->output_file_path)
8929 {
8930 free(tng_data->output_file_path);
8931 tng_data->output_file_path = 0;
8932 }
8933
8934 if(tng_data->first_program_name)
8935 {
8936 free(tng_data->first_program_name);
8937 tng_data->first_program_name = 0;
8938 }
8939
8940 if(tng_data->last_program_name)
8941 {
8942 free(tng_data->last_program_name);
8943 tng_data->last_program_name = 0;
8944 }
8945
8946 if(tng_data->first_user_name)
8947 {
8948 free(tng_data->first_user_name);
8949 tng_data->first_user_name = 0;
8950 }
8951
8952 if(tng_data->last_user_name)
8953 {
8954 free(tng_data->last_user_name);
8955 tng_data->last_user_name = 0;
8956 }
8957
8958 if(tng_data->first_computer_name)
8959 {
8960 free(tng_data->first_computer_name);
8961 tng_data->first_computer_name = 0;
8962 }
8963
8964 if(tng_data->last_computer_name)
8965 {
8966 free(tng_data->last_computer_name);
8967 tng_data->last_computer_name = 0;
8968 }
8969
8970 if(tng_data->first_pgp_signature)
8971 {
8972 free(tng_data->first_pgp_signature);
8973 tng_data->first_pgp_signature = 0;
8974 }
8975
8976 if(tng_data->last_pgp_signature)
8977 {
8978 free(tng_data->last_pgp_signature);
8979 tng_data->last_pgp_signature = 0;
8980 }
8981
8982 if(tng_data->forcefield_name)
8983 {
8984 free(tng_data->forcefield_name);
8985 tng_data->forcefield_name = 0;
8986 }
8987
8988 tng_frame_set_particle_mapping_free(tng_data);
8989
8990 if(frame_set->molecule_cnt_list)
8991 {
8992 free(frame_set->molecule_cnt_list);
8993 frame_set->molecule_cnt_list = 0;
8994 }
8995
8996 if(tng_data->var_num_atoms_flag)
8997 {
8998 n_particles = frame_set->n_particles;
8999 }
9000 else
9001 {
9002 n_particles = tng_data->n_particles;
9003 }
9004
9005 if(tng_data->non_tr_particle_data)
9006 {
9007 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
9008 {
9009 if(tng_data->non_tr_particle_data[i].values)
9010 {
9011 free(tng_data->non_tr_particle_data[i].values);
9012 tng_data->non_tr_particle_data[i].values = 0;
9013 }
9014
9015 if(tng_data->non_tr_particle_data[i].strings)
9016 {
9017 n_values_per_frame = tng_data->non_tr_particle_data[i].
9018 n_values_per_frame;
9019 if(tng_data->non_tr_particle_data[i].strings[0])
9020 {
9021 for(j = 0; j < n_particles; j++)
9022 {
9023 if(tng_data->non_tr_particle_data[i].strings[0][j])
9024 {
9025 for(k = 0; k < n_values_per_frame; k++)
9026 {
9027 if(tng_data->non_tr_particle_data[i].
9028 strings[0][j][k])
9029 {
9030 free(tng_data->non_tr_particle_data[i].
9031 strings[0][j][k]);
9032 tng_data->non_tr_particle_data[i].
9033 strings[0][j][k] = 0;
9034 }
9035 }
9036 free(tng_data->non_tr_particle_data[i].
9037 strings[0][j]);
9038 tng_data->non_tr_particle_data[i].strings[0][j] = 0;
9039 }
9040 }
9041 free(tng_data->non_tr_particle_data[i].strings[0]);
9042 tng_data->non_tr_particle_data[i].strings[0] = 0;
9043 }
9044 free(tng_data->non_tr_particle_data[i].strings);
9045 tng_data->non_tr_particle_data[i].strings = 0;
9046 }
9047
9048 if(tng_data->non_tr_particle_data[i].block_name)
9049 {
9050 free(tng_data->non_tr_particle_data[i].block_name);
9051 tng_data->non_tr_particle_data[i].block_name = 0;
9052 }
9053 }
9054 free(tng_data->non_tr_particle_data);
9055 tng_data->non_tr_particle_data = 0;
9056 }
9057
9058 if(tng_data->non_tr_data)
9059 {
9060 for(i = 0; i < tng_data->n_data_blocks; i++)
9061 {
9062 if(tng_data->non_tr_data[i].values)
9063 {
9064 free(tng_data->non_tr_data[i].values);
9065 tng_data->non_tr_data[i].values = 0;
9066 }
9067
9068 if(tng_data->non_tr_data[i].strings)
9069 {
9070 n_values_per_frame = tng_data->non_tr_data[i].
9071 n_values_per_frame;
9072 if(tng_data->non_tr_data[i].strings[0][0])
9073 {
9074 for(j = 0; j < n_values_per_frame; j++)
9075 {
9076 if(tng_data->non_tr_data[i].strings[0][0][j])
9077 {
9078 free(tng_data->non_tr_data[i].strings[0][0][j]);
9079 tng_data->non_tr_data[i].strings[0][0][j] = 0;
9080 }
9081 }
9082 free(tng_data->non_tr_data[i].strings[0][0]);
9083 tng_data->non_tr_data[i].strings[0][0] = 0;
9084 }
9085 free(tng_data->non_tr_data[i].strings[0]);
9086 tng_data->non_tr_data[i].strings[0] = 0;
9087 free(tng_data->non_tr_data[i].strings);
9088 tng_data->non_tr_data[i].strings = 0;
9089 }
9090
9091 if(tng_data->non_tr_data[i].block_name)
9092 {
9093 free(tng_data->non_tr_data[i].block_name);
9094 tng_data->non_tr_data[i].block_name = 0;
9095 }
9096 }
9097 free(tng_data->non_tr_data);
9098 tng_data->non_tr_data = 0;
9099 }
9100
9101 tng_data->n_particle_data_blocks = 0;
9102 tng_data->n_data_blocks = 0;
9103
9104 if(tng_data->compress_algo_pos)
9105 {
9106 free(tng_data->compress_algo_pos);
9107 tng_data->compress_algo_pos = 0;
9108 }
9109 if(tng_data->compress_algo_vel)
9110 {
9111 free(tng_data->compress_algo_vel);
9112 tng_data->compress_algo_vel = 0;
9113 }
9114
9115 if(frame_set->tr_particle_data)
9116 {
9117 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
9118 {
9119 if(frame_set->tr_particle_data[i].values)
9120 {
9121 free(frame_set->tr_particle_data[i].values);
9122 frame_set->tr_particle_data[i].values = 0;
9123 }
9124
9125 if(frame_set->tr_particle_data[i].strings)
9126 {
9127 n_values_per_frame = frame_set->tr_particle_data[i].
9128 n_values_per_frame;
9129 for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++)
9130 {
9131 if(frame_set->tr_particle_data[i].strings[j])
9132 {
9133 for(k = 0; k < n_particles; k++)
9134 {
9135 if(frame_set->tr_particle_data[i].
9136 strings[j][k])
9137 {
9138 for(l = 0; l < n_values_per_frame; l++)
9139 {
9140 if(frame_set->tr_particle_data[i].
9141 strings[j][k][l])
9142 {
9143 free(frame_set->tr_particle_data[i].
9144 strings[j][k][l]);
9145 frame_set->tr_particle_data[i].
9146 strings[j][k][l] = 0;
9147 }
9148 }
9149 free(frame_set->tr_particle_data[i].
9150 strings[j][k]);
9151 frame_set->tr_particle_data[i].
9152 strings[j][k] = 0;
9153 }
9154 }
9155 free(frame_set->tr_particle_data[i].strings[j]);
9156 frame_set->tr_particle_data[i].strings[j] = 0;
9157 }
9158 }
9159 free(frame_set->tr_particle_data[i].strings);
9160 frame_set->tr_particle_data[i].strings = 0;
9161 }
9162
9163 if(frame_set->tr_particle_data[i].block_name)
9164 {
9165 free(frame_set->tr_particle_data[i].block_name);
9166 frame_set->tr_particle_data[i].block_name = 0;
9167 }
9168 }
9169 free(frame_set->tr_particle_data);
9170 frame_set->tr_particle_data = 0;
9171 }
9172
9173 if(frame_set->tr_data)
9174 {
9175 for(i = 0; i < frame_set->n_data_blocks; i++)
9176 {
9177 if(frame_set->tr_data[i].values)
9178 {
9179 free(frame_set->tr_data[i].values);
9180 frame_set->tr_data[i].values = 0;
9181 }
9182
9183 if(frame_set->tr_data[i].strings)
9184 {
9185 n_values_per_frame = frame_set->tr_data[i].
9186 n_values_per_frame;
9187 for(j = 0; j < frame_set->tr_data[i].n_frames; j++)
9188 {
9189 if(frame_set->tr_data[i].strings[j])
9190 {
9191 for(k = 0; k < n_values_per_frame; k++)
9192 {
9193 if(frame_set->tr_data[i].strings[j][k])
9194 {
9195 free(frame_set->tr_data[i].strings[j][k]);
9196 frame_set->tr_data[i].strings[j][k] = 0;
9197 }
9198 }
9199 free(frame_set->tr_data[i].strings[j]);
9200 frame_set->tr_data[i].strings[j] = 0;
9201 }
9202 }
9203 free(frame_set->tr_data[i].strings);
9204 frame_set->tr_data[i].strings = 0;
9205 }
9206
9207 if(frame_set->tr_data[i].block_name)
9208 {
9209 free(frame_set->tr_data[i].block_name);
9210 frame_set->tr_data[i].block_name = 0;
9211 }
9212 }
9213 free(frame_set->tr_data);
9214 frame_set->tr_data = 0;
9215 }
9216
9217 frame_set->n_particle_data_blocks = 0;
9218 frame_set->n_data_blocks = 0;
9219
9220 if(tng_data->molecules)
9221 {
9222 for(i = 0; i < tng_data->n_molecules; i++)
9223 {
9224 tng_molecule_destroy(tng_data, &tng_data->molecules[i]);
9225 }
9226 free(tng_data->molecules);
9227 tng_data->molecules = 0;
9228 tng_data->n_molecules = 0;
9229 }
9230 if(tng_data->molecule_cnt_list)
9231 {
9232 free(tng_data->molecule_cnt_list);
9233 tng_data->molecule_cnt_list = 0;
9234 }
9235
9236 free(*tng_data_p);
9237 *tng_data_p = 0;
9238
9239 return(TNG_SUCCESS);
9240 }
9241
tng_trajectory_init_from_src(const tng_trajectory_t src,tng_trajectory_t * dest_p)9242 tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src
9243 (const tng_trajectory_t src,
9244 tng_trajectory_t *dest_p)
9245 {
9246 tng_trajectory_frame_set_t frame_set;
9247 tng_trajectory_t dest;
9248
9249 TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
9250
9251 *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
9252 if(!*dest_p)
9253 {
9254 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9255 __FILE__, __LINE__);
9256 return(TNG_CRITICAL);
9257 }
9258
9259 dest = *dest_p;
9260
9261 frame_set = &dest->current_trajectory_frame_set;
9262
9263 if(src->input_file_path)
9264 {
9265 dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1);
9266 if(!dest->input_file_path)
9267 {
9268 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9269 __FILE__, __LINE__);
9270 return(TNG_CRITICAL);
9271 }
9272 strcpy(dest->input_file_path, src->input_file_path);
9273 dest->input_file_len = src->input_file_len;
9274 }
9275 else
9276 {
9277 dest->input_file_path = 0;
9278 }
9279 dest->input_file = 0;
9280 if(src->output_file_path)
9281 {
9282 dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1);
9283 if(!dest->output_file_path)
9284 {
9285 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9286 __FILE__, __LINE__);
9287 return(TNG_CRITICAL);
9288 }
9289 strcpy(dest->output_file_path, src->output_file_path);
9290 }
9291 else
9292 {
9293 dest->output_file_path = 0;
9294 }
9295 dest->output_file = 0;
9296
9297 dest->first_program_name = 0;
9298 dest->first_user_name = 0;
9299 dest->first_computer_name = 0;
9300 dest->first_pgp_signature = 0;
9301 dest->last_program_name = 0;
9302 dest->last_user_name = 0;
9303 dest->last_computer_name = 0;
9304 dest->last_pgp_signature = 0;
9305 dest->forcefield_name = 0;
9306
9307 dest->var_num_atoms_flag = src->var_num_atoms_flag;
9308 dest->first_trajectory_frame_set_input_file_pos =
9309 src->first_trajectory_frame_set_input_file_pos;
9310 dest->last_trajectory_frame_set_input_file_pos =
9311 src->last_trajectory_frame_set_input_file_pos;
9312 dest->current_trajectory_frame_set_input_file_pos =
9313 src->current_trajectory_frame_set_input_file_pos;
9314 dest->first_trajectory_frame_set_output_file_pos =
9315 src->first_trajectory_frame_set_output_file_pos;
9316 dest->last_trajectory_frame_set_output_file_pos =
9317 src->last_trajectory_frame_set_output_file_pos;
9318 dest->current_trajectory_frame_set_output_file_pos =
9319 src->current_trajectory_frame_set_output_file_pos;
9320 dest->frame_set_n_frames = src->frame_set_n_frames;
9321 dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets;
9322 dest->medium_stride_length = src->medium_stride_length;
9323 dest->long_stride_length = src->long_stride_length;
9324
9325 dest->time_per_frame = src->time_per_frame;
9326
9327 /* Currently the non trajectory data blocks are not copied since it
9328 * can lead to problems when freeing memory in a parallel block. */
9329 dest->n_particle_data_blocks = 0;
9330 dest->n_data_blocks = 0;
9331 dest->non_tr_particle_data = 0;
9332 dest->non_tr_data = 0;
9333
9334 dest->compress_algo_pos = 0;
9335 dest->compress_algo_vel = 0;
9336 dest->distance_unit_exponential = -9;
9337 dest->compression_precision = 1000;
9338
9339 frame_set->n_mapping_blocks = 0;
9340 frame_set->mappings = 0;
9341 frame_set->molecule_cnt_list = 0;
9342
9343 frame_set->n_particle_data_blocks = 0;
9344 frame_set->n_data_blocks = 0;
9345
9346 frame_set->tr_particle_data = 0;
9347 frame_set->tr_data = 0;
9348
9349 frame_set->n_written_frames = 0;
9350 frame_set->n_unwritten_frames = 0;
9351
9352 frame_set->next_frame_set_file_pos = -1;
9353 frame_set->prev_frame_set_file_pos = -1;
9354 frame_set->medium_stride_next_frame_set_file_pos = -1;
9355 frame_set->medium_stride_prev_frame_set_file_pos = -1;
9356 frame_set->long_stride_next_frame_set_file_pos = -1;
9357 frame_set->long_stride_prev_frame_set_file_pos = -1;
9358 frame_set->first_frame = -1;
9359
9360 dest->n_molecules = 0;
9361 dest->molecules = 0;
9362 dest->molecule_cnt_list = 0;
9363 dest->n_particles = src->n_particles;
9364
9365 dest->endianness_32 = src->endianness_32;
9366 dest->endianness_64 = src->endianness_64;
9367 dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32;
9368 dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64;
9369 dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32;
9370 dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64;
9371
9372 dest->current_trajectory_frame_set.next_frame_set_file_pos = -1;
9373 dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1;
9374 dest->current_trajectory_frame_set.n_frames = 0;
9375
9376 return(TNG_SUCCESS);
9377 }
9378
tng_input_file_get(const tng_trajectory_t tng_data,char * file_name,const int max_len)9379 tng_function_status DECLSPECDLLEXPORT tng_input_file_get
9380 (const tng_trajectory_t tng_data,
9381 char *file_name,
9382 const int max_len)
9383 {
9384 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9385 TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9386
9387 strncpy(file_name, tng_data->input_file_path, max_len - 1);
9388 file_name[max_len - 1] = 0;
9389
9390 if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1)
9391 {
9392 return(TNG_FAILURE);
9393 }
9394 return(TNG_SUCCESS);
9395 }
9396
tng_input_file_set(const tng_trajectory_t tng_data,const char * file_name)9397 tng_function_status DECLSPECDLLEXPORT tng_input_file_set
9398 (const tng_trajectory_t tng_data,
9399 const char *file_name)
9400 {
9401 unsigned int len;
9402 char *temp;
9403
9404 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9405 TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9406
9407
9408 if(tng_data->input_file_path && strcmp(tng_data->input_file_path,
9409 file_name) == 0)
9410 {
9411 return(TNG_SUCCESS);
9412 }
9413
9414 if(tng_data->input_file)
9415 {
9416 fclose(tng_data->input_file);
9417 }
9418
9419 len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9420 temp = (char *)realloc(tng_data->input_file_path, len);
9421 if(!temp)
9422 {
9423 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9424 __FILE__, __LINE__);
9425 free(tng_data->input_file_path);
9426 tng_data->input_file_path = 0;
9427 return(TNG_CRITICAL);
9428 }
9429 tng_data->input_file_path = temp;
9430
9431 strncpy(tng_data->input_file_path, file_name, len);
9432
9433 return(tng_input_file_init(tng_data));
9434 }
9435
tng_output_file_get(const tng_trajectory_t tng_data,char * file_name,const int max_len)9436 tng_function_status tng_output_file_get
9437 (const tng_trajectory_t tng_data,
9438 char *file_name,
9439 const int max_len)
9440 {
9441 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9442 TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9443
9444 strncpy(file_name, tng_data->output_file_path, max_len - 1);
9445 file_name[max_len - 1] = 0;
9446
9447 if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1)
9448 {
9449 return(TNG_FAILURE);
9450 }
9451 return(TNG_SUCCESS);
9452 }
9453
tng_output_file_set(const tng_trajectory_t tng_data,const char * file_name)9454 tng_function_status DECLSPECDLLEXPORT tng_output_file_set
9455 (const tng_trajectory_t tng_data,
9456 const char *file_name)
9457 {
9458 int len;
9459 char *temp;
9460
9461 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9462 TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9463
9464 if(tng_data->output_file_path &&
9465 strcmp(tng_data->output_file_path, file_name) == 0)
9466 {
9467 return(TNG_SUCCESS);
9468 }
9469
9470 if(tng_data->output_file)
9471 {
9472 fclose(tng_data->output_file);
9473 }
9474
9475 len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9476 temp = (char *)realloc(tng_data->output_file_path, len);
9477 if(!temp)
9478 {
9479 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9480 __FILE__, __LINE__);
9481 free(tng_data->output_file_path);
9482 tng_data->output_file_path = 0;
9483 return(TNG_CRITICAL);
9484 }
9485 tng_data->output_file_path = temp;
9486
9487 strncpy(tng_data->output_file_path, file_name, len);
9488
9489 return(tng_output_file_init(tng_data));
9490 }
9491
tng_output_append_file_set(const tng_trajectory_t tng_data,const char * file_name)9492 tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set
9493 (const tng_trajectory_t tng_data,
9494 const char *file_name)
9495 {
9496 int len;
9497 char *temp;
9498
9499 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9500 TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer");
9501
9502 if(tng_data->output_file_path &&
9503 strcmp(tng_data->output_file_path, file_name) == 0)
9504 {
9505 return(TNG_SUCCESS);
9506 }
9507
9508 if(tng_data->output_file)
9509 {
9510 fclose(tng_data->output_file);
9511 }
9512
9513 len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
9514 temp = (char *)realloc(tng_data->output_file_path, len);
9515 if(!temp)
9516 {
9517 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9518 __FILE__, __LINE__);
9519 free(tng_data->output_file_path);
9520 tng_data->output_file_path = 0;
9521 return(TNG_CRITICAL);
9522 }
9523 tng_data->output_file_path = temp;
9524
9525 strncpy(tng_data->output_file_path, file_name, len);
9526
9527 tng_data->output_file = fopen(tng_data->output_file_path, "rb+");
9528 if(!tng_data->output_file)
9529 {
9530 fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n",
9531 tng_data->output_file_path, __FILE__, __LINE__);
9532 return(TNG_CRITICAL);
9533 }
9534 tng_data->input_file = tng_data->output_file;
9535
9536 return(TNG_SUCCESS);
9537 }
9538
tng_output_file_endianness_get(const tng_trajectory_t tng_data,tng_file_endianness * endianness)9539 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get
9540 (const tng_trajectory_t tng_data, tng_file_endianness *endianness)
9541 {
9542 tng_endianness_32 end_32;
9543 tng_endianness_64 end_64;
9544
9545 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9546 TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer");
9547
9548 if(tng_data->output_endianness_swap_func_32)
9549 {
9550 /* If other endianness variants are added they must be added here as well */
9551 if(tng_data->output_endianness_swap_func_32 ==
9552 &tng_swap_byte_order_big_endian_32)
9553 {
9554 end_32 = TNG_BIG_ENDIAN_32;
9555 }
9556 else if(tng_data->output_endianness_swap_func_32 ==
9557 &tng_swap_byte_order_little_endian_32)
9558 {
9559 end_32 = TNG_LITTLE_ENDIAN_32;
9560 }
9561 else
9562 {
9563 return(TNG_FAILURE);
9564 }
9565 }
9566 else
9567 {
9568 end_32 = (tng_endianness_32)tng_data->endianness_32;
9569 }
9570
9571 if(tng_data->output_endianness_swap_func_64)
9572 {
9573 /* If other endianness variants are added they must be added here as well */
9574 if(tng_data->output_endianness_swap_func_64 ==
9575 &tng_swap_byte_order_big_endian_64)
9576 {
9577 end_64 = TNG_BIG_ENDIAN_64;
9578 }
9579 else if(tng_data->output_endianness_swap_func_64 ==
9580 &tng_swap_byte_order_little_endian_64)
9581 {
9582 end_64 = TNG_LITTLE_ENDIAN_64;
9583 }
9584 else
9585 {
9586 return(TNG_FAILURE);
9587 }
9588 }
9589 else
9590 {
9591 end_64 = (tng_endianness_64)tng_data->endianness_64;
9592 }
9593
9594 if((int)end_32 != (int)end_64)
9595 {
9596 return(TNG_FAILURE);
9597 }
9598
9599 if(end_32 == TNG_LITTLE_ENDIAN_32)
9600 {
9601 *endianness = TNG_LITTLE_ENDIAN;
9602 }
9603
9604 else if(end_32 == TNG_BIG_ENDIAN_32)
9605 {
9606 *endianness = TNG_BIG_ENDIAN;
9607 }
9608 else
9609 {
9610 return(TNG_FAILURE);
9611 }
9612
9613 return(TNG_SUCCESS);
9614 }
9615
tng_output_file_endianness_set(const tng_trajectory_t tng_data,const tng_file_endianness endianness)9616 tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set
9617 (const tng_trajectory_t tng_data,
9618 const tng_file_endianness endianness)
9619 {
9620 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9621
9622 /* Tne endianness cannot be changed if the data has already been written
9623 * to the output file. */
9624 if(ftello(tng_data->output_file) > 0)
9625 {
9626 return(TNG_FAILURE);
9627 }
9628
9629 if(endianness == TNG_BIG_ENDIAN)
9630 {
9631 if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32)
9632 {
9633 tng_data->output_endianness_swap_func_32 = 0;
9634 }
9635 else
9636 {
9637 tng_data->output_endianness_swap_func_32 =
9638 &tng_swap_byte_order_big_endian_32;
9639 }
9640 if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64)
9641 {
9642 tng_data->output_endianness_swap_func_64 = 0;
9643 }
9644 else
9645 {
9646 tng_data->output_endianness_swap_func_64 =
9647 &tng_swap_byte_order_big_endian_64;
9648 }
9649 return(TNG_SUCCESS);
9650 }
9651 else if(endianness == TNG_LITTLE_ENDIAN)
9652 {
9653 if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32)
9654 {
9655 tng_data->output_endianness_swap_func_32 = 0;
9656 }
9657 else
9658 {
9659 tng_data->output_endianness_swap_func_32 =
9660 &tng_swap_byte_order_little_endian_32;
9661 }
9662 if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64)
9663 {
9664 tng_data->output_endianness_swap_func_64 = 0;
9665 }
9666 else
9667 {
9668 tng_data->output_endianness_swap_func_64 =
9669 &tng_swap_byte_order_little_endian_64;
9670 }
9671 return(TNG_SUCCESS);
9672 }
9673
9674 /* If the specified endianness is neither big nor little endian return a
9675 * failure. */
9676 return(TNG_FAILURE);
9677 }
9678
tng_first_program_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9679 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get
9680 (const tng_trajectory_t tng_data,
9681 char *name,
9682 const int max_len)
9683 {
9684 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9685 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9686
9687 strncpy(name, tng_data->first_program_name, max_len - 1);
9688 name[max_len - 1] = 0;
9689
9690 if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1)
9691 {
9692 return(TNG_FAILURE);
9693 }
9694 return(TNG_SUCCESS);
9695 }
9696
tng_first_program_name_set(const tng_trajectory_t tng_data,const char * new_name)9697 tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set
9698 (const tng_trajectory_t tng_data,
9699 const char *new_name)
9700 {
9701 unsigned int len;
9702
9703 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9704 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9705
9706 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9707
9708 if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len)
9709 {
9710 free(tng_data->first_program_name);
9711 tng_data->first_program_name = 0;
9712 }
9713 if(!tng_data->first_program_name)
9714 {
9715 tng_data->first_program_name = (char *)malloc(len);
9716 if(!tng_data->first_program_name)
9717 {
9718 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9719 __FILE__, __LINE__);
9720 return(TNG_CRITICAL);
9721 }
9722 }
9723
9724 strncpy(tng_data->first_program_name, new_name, len);
9725
9726 return(TNG_SUCCESS);
9727 }
9728
tng_last_program_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9729 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get
9730 (const tng_trajectory_t tng_data,
9731 char *name, const int max_len)
9732 {
9733 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9734 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9735
9736 strncpy(name, tng_data->last_program_name, max_len - 1);
9737 name[max_len - 1] = 0;
9738
9739 if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1)
9740 {
9741 return(TNG_FAILURE);
9742 }
9743 return(TNG_SUCCESS);
9744 }
9745
tng_last_program_name_set(const tng_trajectory_t tng_data,const char * new_name)9746 tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set
9747 (const tng_trajectory_t tng_data,
9748 const char *new_name)
9749 {
9750 unsigned int len;
9751
9752 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9753 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9754
9755 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9756
9757 if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len)
9758 {
9759 free(tng_data->last_program_name);
9760 tng_data->last_program_name = 0;
9761 }
9762 if(!tng_data->last_program_name)
9763 {
9764 tng_data->last_program_name = (char *)malloc(len);
9765 if(!tng_data->last_program_name)
9766 {
9767 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9768 __FILE__, __LINE__);
9769 return(TNG_CRITICAL);
9770 }
9771 }
9772
9773 strncpy(tng_data->last_program_name, new_name, len);
9774
9775 return(TNG_SUCCESS);
9776 }
9777
tng_first_user_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9778 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get
9779 (const tng_trajectory_t tng_data,
9780 char *name, const int max_len)
9781 {
9782 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9783 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9784
9785 strncpy(name, tng_data->first_user_name, max_len - 1);
9786 name[max_len - 1] = 0;
9787
9788 if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1)
9789 {
9790 return(TNG_FAILURE);
9791 }
9792 return(TNG_SUCCESS);
9793 }
9794
tng_first_user_name_set(const tng_trajectory_t tng_data,const char * new_name)9795 tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set
9796 (const tng_trajectory_t tng_data,
9797 const char *new_name)
9798 {
9799 unsigned int len;
9800
9801 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9802 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9803
9804 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9805
9806 /* If the currently stored string length is not enough to store the new
9807 * string it is freed and reallocated. */
9808 if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len)
9809 {
9810 free(tng_data->first_user_name);
9811 tng_data->first_user_name = 0;
9812 }
9813 if(!tng_data->first_user_name)
9814 {
9815 tng_data->first_user_name = (char *)malloc(len);
9816 if(!tng_data->first_user_name)
9817 {
9818 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9819 __FILE__, __LINE__);
9820 return(TNG_CRITICAL);
9821 }
9822 }
9823
9824 strncpy(tng_data->first_user_name, new_name, len);
9825
9826 return(TNG_SUCCESS);
9827 }
9828
tng_last_user_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9829 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get
9830 (const tng_trajectory_t tng_data,
9831 char *name, const int max_len)
9832 {
9833 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9834 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9835
9836 strncpy(name, tng_data->last_user_name, max_len - 1);
9837 name[max_len - 1] = 0;
9838
9839 if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1)
9840 {
9841 return(TNG_FAILURE);
9842 }
9843 return(TNG_SUCCESS);
9844 }
9845
tng_last_user_name_set(const tng_trajectory_t tng_data,const char * new_name)9846 tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set
9847 (const tng_trajectory_t tng_data,
9848 const char *new_name)
9849 {
9850 unsigned int len;
9851
9852 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9853 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9854
9855 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9856
9857 /* If the currently stored string length is not enough to store the new
9858 * string it is freed and reallocated. */
9859 if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len)
9860 {
9861 free(tng_data->last_user_name);
9862 tng_data->last_user_name = 0;
9863 }
9864 if(!tng_data->last_user_name)
9865 {
9866 tng_data->last_user_name = (char *)malloc(len);
9867 if(!tng_data->last_user_name)
9868 {
9869 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9870 __FILE__, __LINE__);
9871 return(TNG_CRITICAL);
9872 }
9873 }
9874
9875 strncpy(tng_data->last_user_name, new_name, len);
9876
9877 return(TNG_SUCCESS);
9878 }
9879
tng_first_computer_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9880 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get
9881 (const tng_trajectory_t tng_data,
9882 char *name, const int max_len)
9883 {
9884 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9885 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9886
9887 strncpy(name, tng_data->first_computer_name, max_len - 1);
9888 name[max_len - 1] = 0;
9889
9890 if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1)
9891 {
9892 return(TNG_FAILURE);
9893 }
9894 return(TNG_SUCCESS);
9895 }
9896
tng_first_computer_name_set(const tng_trajectory_t tng_data,const char * new_name)9897 tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set
9898 (const tng_trajectory_t tng_data,
9899 const char *new_name)
9900 {
9901 unsigned int len;
9902
9903 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9904 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9905
9906 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9907
9908 /* If the currently stored string length is not enough to store the new
9909 * string it is freed and reallocated. */
9910 if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len)
9911 {
9912 free(tng_data->first_computer_name);
9913 tng_data->first_computer_name = 0;
9914 }
9915 if(!tng_data->first_computer_name)
9916 {
9917 tng_data->first_computer_name = (char *)malloc(len);
9918 if(!tng_data->first_computer_name)
9919 {
9920 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9921 __FILE__, __LINE__);
9922 return(TNG_CRITICAL);
9923 }
9924 }
9925
9926 strncpy(tng_data->first_computer_name, new_name, len);
9927
9928 return(TNG_SUCCESS);
9929 }
9930
tng_last_computer_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)9931 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get
9932 (const tng_trajectory_t tng_data,
9933 char *name, const int max_len)
9934 {
9935 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9936 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
9937
9938 strncpy(name, tng_data->last_computer_name, max_len - 1);
9939 name[max_len - 1] = 0;
9940
9941 if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1)
9942 {
9943 return(TNG_FAILURE);
9944 }
9945 return(TNG_SUCCESS);
9946 }
9947
tng_last_computer_name_set(const tng_trajectory_t tng_data,const char * new_name)9948 tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set
9949 (const tng_trajectory_t tng_data,
9950 const char *new_name)
9951 {
9952 unsigned int len;
9953
9954 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9955 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
9956
9957 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
9958
9959 /* If the currently stored string length is not enough to store the new
9960 * string it is freed and reallocated. */
9961 if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) <
9962 len)
9963 {
9964 free(tng_data->last_computer_name);
9965 tng_data->last_computer_name = 0;
9966 }
9967 if(!tng_data->last_computer_name)
9968 {
9969 tng_data->last_computer_name = (char *)malloc(len);
9970 if(!tng_data->last_computer_name)
9971 {
9972 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
9973 __FILE__, __LINE__);
9974 return(TNG_CRITICAL);
9975 }
9976 }
9977
9978 strncpy(tng_data->last_computer_name, new_name, len);
9979
9980 return(TNG_SUCCESS);
9981 }
9982
tng_first_signature_get(const tng_trajectory_t tng_data,char * signature,const int max_len)9983 tng_function_status DECLSPECDLLEXPORT tng_first_signature_get
9984 (const tng_trajectory_t tng_data,
9985 char *signature, const int max_len)
9986 {
9987 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
9988 TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
9989
9990 strncpy(signature, tng_data->first_pgp_signature, max_len - 1);
9991 signature[max_len - 1] = 0;
9992
9993 if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1)
9994 {
9995 return(TNG_FAILURE);
9996 }
9997 return(TNG_SUCCESS);
9998 }
9999
tng_first_signature_set(const tng_trajectory_t tng_data,const char * signature)10000 tng_function_status DECLSPECDLLEXPORT tng_first_signature_set
10001 (const tng_trajectory_t tng_data,
10002 const char *signature)
10003 {
10004 unsigned int len;
10005
10006 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10007 TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10008
10009 len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10010
10011 /* If the currently stored string length is not enough to store the new
10012 * string it is freed and reallocated. */
10013 if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) <
10014 len)
10015 {
10016 free(tng_data->first_pgp_signature);
10017 tng_data->first_pgp_signature = 0;
10018 }
10019 if(!tng_data->first_pgp_signature)
10020 {
10021 tng_data->first_pgp_signature = (char *)malloc(len);
10022 if(!tng_data->first_pgp_signature)
10023 {
10024 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10025 __FILE__, __LINE__);
10026 return(TNG_CRITICAL);
10027 }
10028 }
10029
10030 strncpy(tng_data->first_pgp_signature, signature, len);
10031
10032 return(TNG_SUCCESS);
10033 }
10034
tng_last_signature_get(const tng_trajectory_t tng_data,char * signature,const int max_len)10035 tng_function_status DECLSPECDLLEXPORT tng_last_signature_get
10036 (const tng_trajectory_t tng_data,
10037 char *signature, const int max_len)
10038 {
10039 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10040 TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10041
10042 strncpy(signature, tng_data->last_pgp_signature, max_len - 1);
10043 signature[max_len - 1] = 0;
10044
10045 if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1)
10046 {
10047 return(TNG_FAILURE);
10048 }
10049 return(TNG_SUCCESS);
10050 }
10051
tng_last_signature_set(const tng_trajectory_t tng_data,const char * signature)10052 tng_function_status DECLSPECDLLEXPORT tng_last_signature_set
10053 (const tng_trajectory_t tng_data,
10054 const char *signature)
10055 {
10056 unsigned int len;
10057
10058 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10059 TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer");
10060
10061 len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN);
10062
10063 /* If the currently stored string length is not enough to store the new
10064 * string it is freed and reallocated. */
10065 if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) <
10066 len)
10067 {
10068 free(tng_data->last_pgp_signature);
10069 tng_data->last_pgp_signature = 0;
10070 }
10071 if(!tng_data->last_pgp_signature)
10072 {
10073 tng_data->last_pgp_signature = (char *)malloc(len);
10074 if(!tng_data->last_pgp_signature)
10075 {
10076 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10077 __FILE__, __LINE__);
10078 return(TNG_CRITICAL);
10079 }
10080 }
10081
10082 strncpy(tng_data->last_pgp_signature, signature, len);
10083
10084 return(TNG_SUCCESS);
10085 }
10086
tng_forcefield_name_get(const tng_trajectory_t tng_data,char * name,const int max_len)10087 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get
10088 (const tng_trajectory_t tng_data,
10089 char *name, const int max_len)
10090 {
10091 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10092 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
10093
10094 strncpy(name, tng_data->forcefield_name, max_len - 1);
10095 name[max_len - 1] = 0;
10096
10097 if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1)
10098 {
10099 return(TNG_FAILURE);
10100 }
10101 return(TNG_SUCCESS);
10102 }
10103
tng_forcefield_name_set(const tng_trajectory_t tng_data,const char * new_name)10104 tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set
10105 (const tng_trajectory_t tng_data,
10106 const char *new_name)
10107 {
10108 unsigned int len;
10109
10110 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10111 TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer");
10112
10113 len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN);
10114
10115 /* If the currently stored string length is not enough to store the new
10116 * string it is freed and reallocated. */
10117 if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len)
10118 {
10119 free(tng_data->forcefield_name);
10120 tng_data->forcefield_name = 0;
10121 }
10122 if(!tng_data->forcefield_name)
10123 {
10124 tng_data->forcefield_name = (char *)malloc(len);
10125 if(!tng_data->forcefield_name)
10126 {
10127 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
10128 __FILE__, __LINE__);
10129 return(TNG_CRITICAL);
10130 }
10131 }
10132
10133 strncpy(tng_data->forcefield_name, new_name, len);
10134
10135 return(TNG_SUCCESS);
10136 }
10137
tng_medium_stride_length_get(const tng_trajectory_t tng_data,int64_t * len)10138 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get
10139 (const tng_trajectory_t tng_data,
10140 int64_t *len)
10141 {
10142 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10143 TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10144
10145 *len = tng_data->medium_stride_length;
10146
10147 return(TNG_SUCCESS);
10148 }
10149
tng_medium_stride_length_set(const tng_trajectory_t tng_data,const int64_t len)10150 tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set
10151 (const tng_trajectory_t tng_data,
10152 const int64_t len)
10153 {
10154 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10155
10156 if(len >= tng_data->long_stride_length)
10157 {
10158 return(TNG_FAILURE);
10159 }
10160 tng_data->medium_stride_length = len;
10161
10162 return(TNG_SUCCESS);
10163 }
10164
tng_long_stride_length_get(const tng_trajectory_t tng_data,int64_t * len)10165 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get
10166 (const tng_trajectory_t tng_data,
10167 int64_t *len)
10168 {
10169 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10170 TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10171
10172 *len = tng_data->long_stride_length;
10173
10174 return(TNG_SUCCESS);
10175 }
10176
tng_long_stride_length_set(const tng_trajectory_t tng_data,const int64_t len)10177 tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set
10178 (const tng_trajectory_t tng_data,
10179 const int64_t len)
10180 {
10181 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10182
10183 if(len <= tng_data->medium_stride_length)
10184 {
10185 return(TNG_FAILURE);
10186 }
10187 tng_data->long_stride_length = len;
10188
10189 return(TNG_SUCCESS);
10190 }
10191
tng_time_per_frame_get(const tng_trajectory_t tng_data,double * time)10192 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get
10193 (const tng_trajectory_t tng_data,
10194 double *time)
10195 {
10196 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10197 TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
10198
10199 *time = tng_data->time_per_frame;
10200
10201 return(TNG_SUCCESS);
10202 }
10203
tng_time_per_frame_set(const tng_trajectory_t tng_data,const double time)10204 tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set
10205 (const tng_trajectory_t tng_data,
10206 const double time)
10207 {
10208 tng_trajectory_frame_set_t frame_set;
10209
10210 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10211 TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0.");
10212
10213 if(fabs(time - tng_data->time_per_frame) < 0.00001)
10214 {
10215 return(TNG_SUCCESS);
10216 }
10217
10218 frame_set = &tng_data->current_trajectory_frame_set;
10219
10220 /* If the current frame set is not finished write it to disk before
10221 changing time per frame. */
10222 if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0)
10223 {
10224 frame_set->n_frames = frame_set->n_unwritten_frames;
10225 tng_frame_set_write(tng_data, TNG_USE_HASH);
10226 }
10227 tng_data->time_per_frame = time;
10228
10229 return(TNG_SUCCESS);
10230 }
10231
tng_input_file_len_get(const tng_trajectory_t tng_data,int64_t * len)10232 tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get
10233 (const tng_trajectory_t tng_data,
10234 int64_t *len)
10235 {
10236 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10237 TNG_ASSERT(len, "TNG library: len must not be a NULL pointer");
10238
10239 *len = tng_data->input_file_len;
10240
10241 return(TNG_SUCCESS);
10242 }
10243
tng_num_frames_get(const tng_trajectory_t tng_data,int64_t * n)10244 tng_function_status DECLSPECDLLEXPORT tng_num_frames_get
10245 (const tng_trajectory_t tng_data,
10246 int64_t *n)
10247 {
10248 tng_gen_block_t block;
10249 tng_function_status stat;
10250 int64_t file_pos, last_file_pos, first_frame, n_frames;
10251
10252 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10253 TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
10254 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10255
10256 file_pos = ftello(tng_data->input_file);
10257 last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10258
10259 if(last_file_pos <= 0)
10260 {
10261 return(TNG_FAILURE);
10262 }
10263
10264 tng_block_init(&block);
10265 fseeko(tng_data->input_file,
10266 last_file_pos,
10267 SEEK_SET);
10268 /* Read block headers first to see that a frame set block is found. */
10269 stat = tng_block_header_read(tng_data, block);
10270 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10271 {
10272 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos,
10273 __FILE__, __LINE__);
10274 tng_block_destroy(&block);
10275 return(TNG_FAILURE);
10276 }
10277 tng_block_destroy(&block);
10278
10279 if(tng_file_input_numerical(tng_data, &first_frame,
10280 sizeof(first_frame),
10281 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10282 {
10283 return(TNG_CRITICAL);
10284 }
10285
10286 if(tng_file_input_numerical(tng_data, &n_frames,
10287 sizeof(n_frames),
10288 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
10289 {
10290 return(TNG_CRITICAL);
10291 }
10292
10293 fseeko(tng_data->input_file, file_pos, SEEK_SET);
10294
10295 *n = first_frame + n_frames;
10296
10297 return(TNG_SUCCESS);
10298 }
10299
tng_compression_precision_get(const tng_trajectory_t tng_data,double * precision)10300 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get
10301 (const tng_trajectory_t tng_data,
10302 double *precision)
10303 {
10304 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10305
10306 *precision = tng_data->compression_precision;
10307
10308 return(TNG_SUCCESS);
10309 }
10310
tng_compression_precision_set(const tng_trajectory_t tng_data,const double precision)10311 tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set
10312 (const tng_trajectory_t tng_data,
10313 const double precision)
10314 {
10315 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10316
10317 tng_data->compression_precision = precision;
10318
10319 return(TNG_SUCCESS);
10320 }
10321
tng_implicit_num_particles_set(const tng_trajectory_t tng_data,const int64_t n)10322 tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set
10323 (const tng_trajectory_t tng_data,
10324 const int64_t n)
10325 {
10326 tng_molecule_t mol;
10327 tng_chain_t chain;
10328 tng_residue_t res;
10329 tng_atom_t atom;
10330 tng_function_status stat;
10331 int64_t diff, n_mod, n_impl;
10332
10333 TNG_ASSERT(n >= 0, "TNG library: The requested number of particles must be >= 0");
10334
10335 diff = n - tng_data->n_particles;
10336
10337 stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol);
10338 if(stat == TNG_SUCCESS)
10339 {
10340 if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS)
10341 {
10342 fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n",
10343 __FILE__, __LINE__);
10344 return(TNG_FAILURE);
10345 }
10346 diff -= n_impl * mol->n_atoms;
10347 }
10348
10349 if(diff == 0)
10350 {
10351 if(stat == TNG_SUCCESS)
10352 {
10353 stat = tng_molecule_cnt_set(tng_data, mol, 0);
10354 return(stat);
10355 }
10356 return(TNG_SUCCESS);
10357 }
10358 else if(diff < 0)
10359 {
10360 fprintf(stderr, "TNG library: Already more actual particles than requested implicit ");
10361 fprintf(stderr, "particle count.\n");
10362 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10363 __FILE__, __LINE__);
10364 /* FIXME: Should we set the count of all other molecules to 0 and add
10365 * implicit molecules? */
10366 return(TNG_FAILURE);
10367 }
10368 if(stat != TNG_SUCCESS)
10369 {
10370 stat = tng_molecule_add(tng_data,
10371 "TNG_IMPLICIT_MOL",
10372 &mol);
10373 if(stat != TNG_SUCCESS)
10374 {
10375 return(stat);
10376 }
10377 stat = tng_molecule_chain_add(tng_data, mol, "", &chain);
10378 if(stat != TNG_SUCCESS)
10379 {
10380 return(stat);
10381 }
10382 stat = tng_chain_residue_add(tng_data, chain, "", &res);
10383 if(stat != TNG_SUCCESS)
10384 {
10385 return(stat);
10386 }
10387 stat = tng_residue_atom_add(tng_data, res, "", "", &atom);
10388 if(stat != TNG_SUCCESS)
10389 {
10390 return(stat);
10391 }
10392 }
10393 else
10394 {
10395 if(mol->n_atoms > 1)
10396 {
10397 n_mod = diff % mol->n_atoms;
10398 if(n_mod != 0)
10399 {
10400 fprintf(stderr, "TNG library: Number of atoms in implicit molecule ");
10401 fprintf(stderr, "not compatible with requested implicit particle cnt.\n");
10402 fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n",
10403 __FILE__, __LINE__);
10404 return(TNG_FAILURE);
10405 }
10406 diff /= mol->n_atoms;
10407 }
10408 }
10409 stat = tng_molecule_cnt_set(tng_data, mol, diff);
10410
10411 return(stat);
10412 }
10413
tng_num_particles_get(const tng_trajectory_t tng_data,int64_t * n)10414 tng_function_status DECLSPECDLLEXPORT tng_num_particles_get
10415 (const tng_trajectory_t tng_data,
10416 int64_t *n)
10417 {
10418 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10419 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10420
10421 if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS)
10422 {
10423 *n = tng_data->n_particles;
10424 }
10425 else
10426 {
10427 *n = tng_data->current_trajectory_frame_set.n_particles;
10428 }
10429
10430 return(TNG_SUCCESS);
10431 }
10432
tng_num_particles_variable_get(const tng_trajectory_t tng_data,char * variable)10433 tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get
10434 (const tng_trajectory_t tng_data,
10435 char *variable)
10436 {
10437 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10438 TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer");
10439
10440 *variable = tng_data->var_num_atoms_flag;
10441
10442 return(TNG_SUCCESS);
10443 }
10444
tng_num_molecule_types_get(const tng_trajectory_t tng_data,int64_t * n)10445 tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get
10446 (const tng_trajectory_t tng_data,
10447 int64_t *n)
10448 {
10449 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10450 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10451
10452 *n = tng_data->n_molecules;
10453
10454 return(TNG_SUCCESS);
10455 }
10456
tng_num_molecules_get(const tng_trajectory_t tng_data,int64_t * n)10457 tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get
10458 (const tng_trajectory_t tng_data,
10459 int64_t *n)
10460 {
10461 int64_t *cnt_list = 0, cnt = 0, i;
10462
10463 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10464 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10465
10466 tng_molecule_cnt_list_get(tng_data, &cnt_list);
10467
10468 if(!cnt_list)
10469 {
10470 return(TNG_FAILURE);
10471 }
10472
10473 for(i = 0; i < tng_data->n_molecules; i++)
10474 {
10475 cnt += cnt_list[i];
10476 }
10477
10478 *n = cnt;
10479
10480 return(TNG_SUCCESS);
10481 }
10482
tng_molecule_cnt_list_get(const tng_trajectory_t tng_data,int64_t ** mol_cnt_list)10483 tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get
10484 (const tng_trajectory_t tng_data,
10485 int64_t **mol_cnt_list)
10486 {
10487 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10488
10489 if(tng_data->var_num_atoms_flag)
10490 {
10491 *mol_cnt_list = tng_data->current_trajectory_frame_set.
10492 molecule_cnt_list;
10493 }
10494 else
10495 {
10496 *mol_cnt_list = tng_data->molecule_cnt_list;
10497 }
10498 if(*mol_cnt_list == 0)
10499 {
10500 return(TNG_FAILURE);
10501 }
10502 return(TNG_SUCCESS);
10503 }
10504
tng_distance_unit_exponential_get(const tng_trajectory_t tng_data,int64_t * exp)10505 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get
10506 (const tng_trajectory_t tng_data,
10507 int64_t *exp)
10508 {
10509 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10510 TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer");
10511
10512 *exp = tng_data->distance_unit_exponential;
10513
10514 return(TNG_SUCCESS);
10515 }
10516
tng_distance_unit_exponential_set(const tng_trajectory_t tng_data,const int64_t exp)10517 tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set
10518 (const tng_trajectory_t tng_data,
10519 const int64_t exp)
10520 {
10521 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10522
10523 tng_data->distance_unit_exponential = exp;
10524
10525 return(TNG_SUCCESS);
10526 }
10527
tng_num_frames_per_frame_set_get(const tng_trajectory_t tng_data,int64_t * n)10528 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get
10529 (const tng_trajectory_t tng_data,
10530 int64_t *n)
10531 {
10532 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10533 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10534
10535 *n = tng_data->frame_set_n_frames;
10536
10537 return(TNG_SUCCESS);
10538 }
10539
tng_num_frames_per_frame_set_set(const tng_trajectory_t tng_data,const int64_t n)10540 tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set
10541 (const tng_trajectory_t tng_data,
10542 const int64_t n)
10543 {
10544 tng_trajectory_frame_set_t frame_set;
10545 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10546
10547 tng_data->frame_set_n_frames = n;
10548 frame_set = &tng_data->current_trajectory_frame_set;
10549 if(frame_set)
10550 {
10551 frame_set->n_frames = n;
10552 }
10553
10554 return(TNG_SUCCESS);
10555 }
10556
tng_num_frame_sets_get(const tng_trajectory_t tng_data,int64_t * n)10557 tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get
10558 (const tng_trajectory_t tng_data,
10559 int64_t *n)
10560 {
10561 int64_t long_stride_length, medium_stride_length;
10562 int64_t file_pos, orig_frame_set_file_pos;
10563 tng_trajectory_frame_set_t frame_set;
10564 struct tng_trajectory_frame_set orig_frame_set;
10565 tng_gen_block_t block;
10566 tng_function_status stat;
10567 int64_t cnt = 0;
10568
10569 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10570 TNG_ASSERT(n, "TNG library: n must not be a NULL pointer");
10571
10572 orig_frame_set = tng_data->current_trajectory_frame_set;
10573
10574 frame_set = &tng_data->current_trajectory_frame_set;
10575
10576 orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10577 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10578
10579 if(file_pos < 0)
10580 {
10581 *n = tng_data->n_trajectory_frame_sets = cnt;
10582 return(TNG_SUCCESS);
10583 }
10584
10585 tng_block_init(&block);
10586 fseeko(tng_data->input_file,
10587 file_pos,
10588 SEEK_SET);
10589 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10590 /* Read block headers first to see what block is found. */
10591 stat = tng_block_header_read(tng_data, block);
10592 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10593 {
10594 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10595 __FILE__, __LINE__);
10596 tng_block_destroy(&block);
10597 return(TNG_CRITICAL);
10598 }
10599
10600 if(tng_block_read_next(tng_data, block,
10601 TNG_SKIP_HASH) != TNG_SUCCESS)
10602 {
10603 tng_block_destroy(&block);
10604 return(TNG_CRITICAL);
10605 }
10606
10607 ++cnt;
10608
10609 long_stride_length = tng_data->long_stride_length;
10610 medium_stride_length = tng_data->medium_stride_length;
10611
10612 /* Take long steps forward until a long step forward would be too long or
10613 * the last frame set is found */
10614 file_pos = frame_set->long_stride_next_frame_set_file_pos;
10615 while(file_pos > 0)
10616 {
10617 if(file_pos > 0)
10618 {
10619 cnt += long_stride_length;
10620 fseeko(tng_data->input_file, file_pos, SEEK_SET);
10621 /* Read block headers first to see what block is found. */
10622 stat = tng_block_header_read(tng_data, block);
10623 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10624 {
10625 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10626 file_pos, __FILE__, __LINE__);
10627 tng_block_destroy(&block);
10628 return(TNG_CRITICAL);
10629 }
10630
10631 if(tng_block_read_next(tng_data, block,
10632 TNG_SKIP_HASH) != TNG_SUCCESS)
10633 {
10634 tng_block_destroy(&block);
10635 return(TNG_CRITICAL);
10636 }
10637 }
10638 file_pos = frame_set->long_stride_next_frame_set_file_pos;
10639 }
10640
10641 /* Take medium steps forward until a medium step forward would be too long
10642 * or the last frame set is found */
10643 file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10644 while(file_pos > 0)
10645 {
10646 if(file_pos > 0)
10647 {
10648 cnt += medium_stride_length;
10649 fseeko(tng_data->input_file,
10650 file_pos,
10651 SEEK_SET);
10652 /* Read block headers first to see what block is found. */
10653 stat = tng_block_header_read(tng_data, block);
10654 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10655 {
10656 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10657 file_pos, __FILE__, __LINE__);
10658 tng_block_destroy(&block);
10659 return(TNG_CRITICAL);
10660 }
10661
10662 if(tng_block_read_next(tng_data, block,
10663 TNG_SKIP_HASH) != TNG_SUCCESS)
10664 {
10665 tng_block_destroy(&block);
10666 return(TNG_CRITICAL);
10667 }
10668 }
10669 file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10670 }
10671
10672 /* Take one step forward until the last frame set is found */
10673 file_pos = frame_set->next_frame_set_file_pos;
10674 while(file_pos > 0)
10675 {
10676 if(file_pos > 0)
10677 {
10678 ++cnt;
10679 fseeko(tng_data->input_file,
10680 file_pos,
10681 SEEK_SET);
10682 /* Read block headers first to see what block is found. */
10683 stat = tng_block_header_read(tng_data, block);
10684 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10685 {
10686 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10687 file_pos, __FILE__, __LINE__);
10688 tng_block_destroy(&block);
10689 return(TNG_CRITICAL);
10690 }
10691
10692 if(tng_block_read_next(tng_data, block,
10693 TNG_SKIP_HASH) != TNG_SUCCESS)
10694 {
10695 tng_block_destroy(&block);
10696 return(TNG_CRITICAL);
10697 }
10698 }
10699 file_pos = frame_set->next_frame_set_file_pos;
10700 }
10701
10702 tng_block_destroy(&block);
10703
10704 *n = tng_data->n_trajectory_frame_sets = cnt;
10705
10706 *frame_set = orig_frame_set;
10707 /* The mapping block in the original frame set has been freed when reading
10708 * other frame sets. */
10709 frame_set->mappings = 0;
10710 frame_set->n_mapping_blocks = 0;
10711
10712 fseeko(tng_data->input_file,
10713 tng_data->first_trajectory_frame_set_input_file_pos,
10714 SEEK_SET);
10715
10716 tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos;
10717
10718 return(TNG_SUCCESS);
10719 }
10720
tng_current_frame_set_get(const tng_trajectory_t tng_data,tng_trajectory_frame_set_t * frame_set_p)10721 tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get
10722 (const tng_trajectory_t tng_data,
10723 tng_trajectory_frame_set_t *frame_set_p)
10724 {
10725 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10726
10727 *frame_set_p = &tng_data->current_trajectory_frame_set;
10728
10729 return(TNG_SUCCESS);
10730 }
10731
tng_frame_set_nr_find(const tng_trajectory_t tng_data,const int64_t nr)10732 tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find
10733 (const tng_trajectory_t tng_data,
10734 const int64_t nr)
10735 {
10736 int64_t long_stride_length, medium_stride_length;
10737 int64_t file_pos, curr_nr = 0, n_frame_sets;
10738 tng_trajectory_frame_set_t frame_set;
10739 tng_gen_block_t block;
10740 tng_function_status stat;
10741
10742 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
10743 TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0");
10744
10745 frame_set = &tng_data->current_trajectory_frame_set;
10746
10747 stat = tng_num_frame_sets_get(tng_data, &n_frame_sets);
10748
10749 if(stat != TNG_SUCCESS)
10750 {
10751 return(stat);
10752 }
10753
10754 if(nr >= n_frame_sets)
10755 {
10756 return(TNG_FAILURE);
10757 }
10758
10759 long_stride_length = tng_data->long_stride_length;
10760 medium_stride_length = tng_data->medium_stride_length;
10761
10762 /* FIXME: The frame set number of the current frame set is not stored */
10763
10764 if(nr < n_frame_sets - 1 - nr)
10765 {
10766 /* Start from the beginning */
10767 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
10768 }
10769 else
10770 {
10771 /* Start from the end */
10772 file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
10773 curr_nr = n_frame_sets - 1;
10774 }
10775 if(file_pos <= 0)
10776 {
10777 return(TNG_FAILURE);
10778 }
10779
10780 tng_block_init(&block);
10781 fseeko(tng_data->input_file,
10782 file_pos,
10783 SEEK_SET);
10784 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
10785 /* Read block headers first to see what block is found. */
10786 stat = tng_block_header_read(tng_data, block);
10787 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10788 {
10789 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
10790 __FILE__, __LINE__);
10791 tng_block_destroy(&block);
10792 return(TNG_CRITICAL);
10793 }
10794
10795 if(tng_block_read_next(tng_data, block,
10796 TNG_SKIP_HASH) != TNG_SUCCESS)
10797 {
10798 tng_block_destroy(&block);
10799 return(TNG_CRITICAL);
10800 }
10801
10802 if(curr_nr == nr)
10803 {
10804 tng_block_destroy(&block);
10805 return(TNG_SUCCESS);
10806 }
10807
10808 file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
10809
10810 /* Take long steps forward until a long step forward would be too long or
10811 * the right frame set is found */
10812 while(file_pos > 0 && curr_nr + long_stride_length <= nr)
10813 {
10814 file_pos = frame_set->long_stride_next_frame_set_file_pos;
10815 if(file_pos > 0)
10816 {
10817 curr_nr += long_stride_length;
10818 fseeko(tng_data->input_file, file_pos, SEEK_SET);
10819 /* Read block headers first to see what block is found. */
10820 stat = tng_block_header_read(tng_data, block);
10821 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10822 {
10823 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10824 file_pos, __FILE__, __LINE__);
10825 tng_block_destroy(&block);
10826 return(TNG_CRITICAL);
10827 }
10828
10829 if(tng_block_read_next(tng_data, block,
10830 TNG_SKIP_HASH) != TNG_SUCCESS)
10831 {
10832 tng_block_destroy(&block);
10833 return(TNG_CRITICAL);
10834 }
10835 if(curr_nr == nr)
10836 {
10837 tng_block_destroy(&block);
10838 return(TNG_SUCCESS);
10839 }
10840 }
10841 }
10842
10843 /* Take medium steps forward until a medium step forward would be too long
10844 * or the right frame set is found */
10845 while(file_pos > 0 && curr_nr + medium_stride_length <= nr)
10846 {
10847 file_pos = frame_set->medium_stride_next_frame_set_file_pos;
10848 if(file_pos > 0)
10849 {
10850 curr_nr += medium_stride_length;
10851 fseeko(tng_data->input_file,
10852 file_pos,
10853 SEEK_SET);
10854 /* Read block headers first to see what block is found. */
10855 stat = tng_block_header_read(tng_data, block);
10856 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10857 {
10858 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10859 file_pos, __FILE__, __LINE__);
10860 tng_block_destroy(&block);
10861 return(TNG_CRITICAL);
10862 }
10863
10864 if(tng_block_read_next(tng_data, block,
10865 TNG_SKIP_HASH) != TNG_SUCCESS)
10866 {
10867 tng_block_destroy(&block);
10868 return(TNG_CRITICAL);
10869 }
10870 if(curr_nr == nr)
10871 {
10872 tng_block_destroy(&block);
10873 return(TNG_SUCCESS);
10874 }
10875 }
10876 }
10877
10878 /* Take one step forward until the right frame set is found */
10879 while(file_pos > 0 && curr_nr < nr)
10880 {
10881 file_pos = frame_set->next_frame_set_file_pos;
10882
10883 if(file_pos > 0)
10884 {
10885 ++curr_nr;
10886 fseeko(tng_data->input_file,
10887 file_pos,
10888 SEEK_SET);
10889 /* Read block headers first to see what block is found. */
10890 stat = tng_block_header_read(tng_data, block);
10891 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10892 {
10893 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10894 file_pos, __FILE__, __LINE__);
10895 tng_block_destroy(&block);
10896 return(TNG_CRITICAL);
10897 }
10898
10899 if(tng_block_read_next(tng_data, block,
10900 TNG_SKIP_HASH) != TNG_SUCCESS)
10901 {
10902 tng_block_destroy(&block);
10903 return(TNG_CRITICAL);
10904 }
10905 if(curr_nr == nr)
10906 {
10907 tng_block_destroy(&block);
10908 return(TNG_SUCCESS);
10909 }
10910 }
10911 }
10912
10913 /* Take long steps backward until a long step backward would be too long
10914 * or the right frame set is found */
10915 while(file_pos > 0 && curr_nr - long_stride_length >= nr)
10916 {
10917 file_pos = frame_set->long_stride_prev_frame_set_file_pos;
10918 if(file_pos > 0)
10919 {
10920 curr_nr -= long_stride_length;
10921 fseeko(tng_data->input_file,
10922 file_pos,
10923 SEEK_SET);
10924 /* Read block headers first to see what block is found. */
10925 stat = tng_block_header_read(tng_data, block);
10926 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10927 {
10928 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10929 file_pos, __FILE__, __LINE__);
10930 tng_block_destroy(&block);
10931 return(TNG_CRITICAL);
10932 }
10933
10934 if(tng_block_read_next(tng_data, block,
10935 TNG_SKIP_HASH) != TNG_SUCCESS)
10936 {
10937 tng_block_destroy(&block);
10938 return(TNG_CRITICAL);
10939 }
10940 if(curr_nr == nr)
10941 {
10942 tng_block_destroy(&block);
10943 return(TNG_SUCCESS);
10944 }
10945 }
10946 }
10947
10948 /* Take medium steps backward until a medium step backward would be too long
10949 * or the right frame set is found */
10950 while(file_pos > 0 && curr_nr - medium_stride_length >= nr)
10951 {
10952 file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
10953 if(file_pos > 0)
10954 {
10955 curr_nr -= medium_stride_length;
10956 fseeko(tng_data->input_file,
10957 file_pos,
10958 SEEK_SET);
10959 /* Read block headers first to see what block is found. */
10960 stat = tng_block_header_read(tng_data, block);
10961 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10962 {
10963 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10964 file_pos, __FILE__, __LINE__);
10965 tng_block_destroy(&block);
10966 return(TNG_CRITICAL);
10967 }
10968
10969 if(tng_block_read_next(tng_data, block,
10970 TNG_SKIP_HASH) != TNG_SUCCESS)
10971 {
10972 tng_block_destroy(&block);
10973 return(TNG_CRITICAL);
10974 }
10975 if(curr_nr == nr)
10976 {
10977 tng_block_destroy(&block);
10978 return(TNG_SUCCESS);
10979 }
10980 }
10981 }
10982
10983 /* Take one step backward until the right frame set is found */
10984 while(file_pos > 0 && curr_nr > nr)
10985 {
10986 file_pos = frame_set->prev_frame_set_file_pos;
10987 if(file_pos > 0)
10988 {
10989 --curr_nr;
10990 fseeko(tng_data->input_file,
10991 file_pos,
10992 SEEK_SET);
10993 /* Read block headers first to see what block is found. */
10994 stat = tng_block_header_read(tng_data, block);
10995 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
10996 {
10997 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
10998 file_pos, __FILE__, __LINE__);
10999 tng_block_destroy(&block);
11000 return(TNG_CRITICAL);
11001 }
11002
11003 if(tng_block_read_next(tng_data, block,
11004 TNG_SKIP_HASH) != TNG_SUCCESS)
11005 {
11006 tng_block_destroy(&block);
11007 return(TNG_CRITICAL);
11008 }
11009 if(curr_nr == nr)
11010 {
11011 tng_block_destroy(&block);
11012 return(TNG_SUCCESS);
11013 }
11014 }
11015 }
11016
11017 /* If for some reason the current frame set is not yet found,
11018 * take one step forward until the right frame set is found */
11019 while(file_pos > 0 && curr_nr < nr)
11020 {
11021 file_pos = frame_set->next_frame_set_file_pos;
11022 if(file_pos > 0)
11023 {
11024 ++curr_nr;
11025 fseeko(tng_data->input_file,
11026 file_pos,
11027 SEEK_SET);
11028 /* Read block headers first to see what block is found. */
11029 stat = tng_block_header_read(tng_data, block);
11030 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11031 {
11032 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11033 file_pos, __FILE__, __LINE__);
11034 tng_block_destroy(&block);
11035 return(TNG_CRITICAL);
11036 }
11037
11038 if(tng_block_read_next(tng_data, block,
11039 TNG_SKIP_HASH) != TNG_SUCCESS)
11040 {
11041 tng_block_destroy(&block);
11042 return(TNG_CRITICAL);
11043 }
11044 if(curr_nr == nr)
11045 {
11046 tng_block_destroy(&block);
11047 return(TNG_SUCCESS);
11048 }
11049 }
11050 }
11051
11052 tng_block_destroy(&block);
11053 return(TNG_FAILURE);
11054 }
11055
tng_frame_set_of_frame_find(const tng_trajectory_t tng_data,const int64_t frame)11056 tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find
11057 (const tng_trajectory_t tng_data,
11058 const int64_t frame)
11059 {
11060 int64_t first_frame, last_frame, n_frames_per_frame_set;
11061 int64_t long_stride_length, medium_stride_length;
11062 int64_t file_pos, temp_frame, n_frames;
11063 tng_trajectory_frame_set_t frame_set;
11064 tng_gen_block_t block;
11065 tng_function_status stat;
11066
11067 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11068 TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0.");
11069
11070 frame_set = &tng_data->current_trajectory_frame_set;
11071
11072 tng_block_init(&block);
11073
11074 if(tng_data->current_trajectory_frame_set_input_file_pos < 0)
11075 {
11076 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11077 fseeko(tng_data->input_file,
11078 file_pos,
11079 SEEK_SET);
11080 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11081 /* Read block headers first to see what block is found. */
11082 stat = tng_block_header_read(tng_data, block);
11083 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11084 {
11085 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11086 file_pos, __FILE__, __LINE__);
11087 tng_block_destroy(&block);
11088 return(TNG_CRITICAL);
11089 }
11090
11091 if(tng_block_read_next(tng_data, block,
11092 TNG_SKIP_HASH) != TNG_SUCCESS)
11093 {
11094 tng_block_destroy(&block);
11095 return(TNG_CRITICAL);
11096 }
11097 }
11098
11099 first_frame = tng_max_i64(frame_set->first_frame, 0);
11100 last_frame = first_frame + frame_set->n_frames - 1;
11101 /* Is this the right frame set? */
11102 if(first_frame <= frame && frame <= last_frame)
11103 {
11104 tng_block_destroy(&block);
11105 return(TNG_SUCCESS);
11106 }
11107
11108 n_frames_per_frame_set = tng_data->frame_set_n_frames;
11109 long_stride_length = tng_data->long_stride_length;
11110 medium_stride_length = tng_data->medium_stride_length;
11111
11112 if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) ==
11113 TNG_SUCCESS)
11114 {
11115 if(temp_frame - first_frame > n_frames_per_frame_set)
11116 {
11117 n_frames_per_frame_set = temp_frame - first_frame;
11118 }
11119 }
11120
11121 tng_num_frames_get(tng_data, &n_frames);
11122
11123 if(frame >= n_frames)
11124 {
11125 tng_block_destroy(&block);
11126 return(TNG_FAILURE);
11127 }
11128
11129 if(first_frame - frame >= frame ||
11130 frame - last_frame >
11131 tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame)
11132 {
11133 /* Start from the beginning */
11134 if(first_frame - frame >= frame)
11135 {
11136 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11137
11138 if(file_pos <= 0)
11139 {
11140 tng_block_destroy(&block);
11141 return(TNG_FAILURE);
11142 }
11143 }
11144 /* Start from the end */
11145 else if(frame - first_frame > (n_frames - 1) - frame)
11146 {
11147 file_pos = tng_data->last_trajectory_frame_set_input_file_pos;
11148
11149 /* If the last frame set position is not set start from the current
11150 * frame set, since it will be closer than the first frame set. */
11151 }
11152 /* Start from current */
11153 else
11154 {
11155 file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11156 }
11157
11158 if(file_pos > 0)
11159 {
11160 fseeko(tng_data->input_file,
11161 file_pos,
11162 SEEK_SET);
11163 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11164 /* Read block headers first to see what block is found. */
11165 stat = tng_block_header_read(tng_data, block);
11166 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11167 {
11168 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11169 file_pos, __FILE__, __LINE__);
11170 tng_block_destroy(&block);
11171 return(TNG_CRITICAL);
11172 }
11173
11174 if(tng_block_read_next(tng_data, block,
11175 TNG_SKIP_HASH) != TNG_SUCCESS)
11176 {
11177 tng_block_destroy(&block);
11178 return(TNG_CRITICAL);
11179 }
11180 }
11181 }
11182
11183 first_frame = tng_max_i64(frame_set->first_frame, 0);
11184 last_frame = first_frame + frame_set->n_frames - 1;
11185
11186 if(frame >= first_frame && frame <= last_frame)
11187 {
11188 tng_block_destroy(&block);
11189 return(TNG_SUCCESS);
11190 }
11191
11192 file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11193
11194 /* Take long steps forward until a long step forward would be too long or
11195 * the right frame set is found */
11196 while(file_pos > 0 && first_frame + long_stride_length *
11197 n_frames_per_frame_set <= frame)
11198 {
11199 file_pos = frame_set->long_stride_next_frame_set_file_pos;
11200 if(file_pos > 0)
11201 {
11202 fseeko(tng_data->input_file, file_pos, SEEK_SET);
11203 /* Read block headers first to see what block is found. */
11204 stat = tng_block_header_read(tng_data, block);
11205 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11206 {
11207 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11208 file_pos, __FILE__, __LINE__);
11209 tng_block_destroy(&block);
11210 return(TNG_CRITICAL);
11211 }
11212
11213 if(tng_block_read_next(tng_data, block,
11214 TNG_SKIP_HASH) != TNG_SUCCESS)
11215 {
11216 tng_block_destroy(&block);
11217 return(TNG_CRITICAL);
11218 }
11219 }
11220 first_frame = tng_max_i64(frame_set->first_frame, 0);
11221 last_frame = first_frame + frame_set->n_frames - 1;
11222 if(frame >= first_frame && frame <= last_frame)
11223 {
11224 tng_block_destroy(&block);
11225 return(TNG_SUCCESS);
11226 }
11227 }
11228
11229 /* Take medium steps forward until a medium step forward would be too long
11230 * or the right frame set is found */
11231 while(file_pos > 0 && first_frame + medium_stride_length *
11232 n_frames_per_frame_set <= frame)
11233 {
11234 file_pos = frame_set->medium_stride_next_frame_set_file_pos;
11235 if(file_pos > 0)
11236 {
11237 fseeko(tng_data->input_file,
11238 file_pos,
11239 SEEK_SET);
11240 /* Read block headers first to see what block is found. */
11241 stat = tng_block_header_read(tng_data, block);
11242 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11243 {
11244 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11245 file_pos, __FILE__, __LINE__);
11246 tng_block_destroy(&block);
11247 return(TNG_CRITICAL);
11248 }
11249
11250 if(tng_block_read_next(tng_data, block,
11251 TNG_SKIP_HASH) != TNG_SUCCESS)
11252 {
11253 tng_block_destroy(&block);
11254 return(TNG_CRITICAL);
11255 }
11256 }
11257 first_frame = tng_max_i64(frame_set->first_frame, 0);
11258 last_frame = first_frame + frame_set->n_frames - 1;
11259 if(frame >= first_frame && frame <= last_frame)
11260 {
11261 tng_block_destroy(&block);
11262 return(TNG_SUCCESS);
11263 }
11264 }
11265
11266 /* Take one step forward until the right frame set is found */
11267 while(file_pos > 0 && first_frame < frame && last_frame < frame)
11268 {
11269 file_pos = frame_set->next_frame_set_file_pos;
11270 if(file_pos > 0)
11271 {
11272 fseeko(tng_data->input_file,
11273 file_pos,
11274 SEEK_SET);
11275 /* Read block headers first to see what block is found. */
11276 stat = tng_block_header_read(tng_data, block);
11277 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11278 {
11279 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11280 file_pos, __FILE__, __LINE__);
11281 tng_block_destroy(&block);
11282 return(TNG_CRITICAL);
11283 }
11284
11285 if(tng_block_read_next(tng_data, block,
11286 TNG_SKIP_HASH) != TNG_SUCCESS)
11287 {
11288 tng_block_destroy(&block);
11289 return(TNG_CRITICAL);
11290 }
11291 }
11292 first_frame = tng_max_i64(frame_set->first_frame, 0);
11293 last_frame = first_frame + frame_set->n_frames - 1;
11294 if(frame >= first_frame && frame <= last_frame)
11295 {
11296 tng_block_destroy(&block);
11297 return(TNG_SUCCESS);
11298 }
11299 }
11300
11301 /* Take long steps backward until a long step backward would be too long
11302 * or the right frame set is found */
11303 while(file_pos > 0 && first_frame - long_stride_length *
11304 n_frames_per_frame_set >= frame)
11305 {
11306 file_pos = frame_set->long_stride_prev_frame_set_file_pos;
11307 if(file_pos > 0)
11308 {
11309 fseeko(tng_data->input_file,
11310 file_pos,
11311 SEEK_SET);
11312 /* Read block headers first to see what block is found. */
11313 stat = tng_block_header_read(tng_data, block);
11314 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11315 {
11316 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11317 file_pos, __FILE__, __LINE__);
11318 tng_block_destroy(&block);
11319 return(TNG_CRITICAL);
11320 }
11321
11322 if(tng_block_read_next(tng_data, block,
11323 TNG_SKIP_HASH) != TNG_SUCCESS)
11324 {
11325 tng_block_destroy(&block);
11326 return(TNG_CRITICAL);
11327 }
11328 }
11329 first_frame = tng_max_i64(frame_set->first_frame, 0);
11330 last_frame = first_frame + frame_set->n_frames - 1;
11331 if(frame >= first_frame && frame <= last_frame)
11332 {
11333 tng_block_destroy(&block);
11334 return(TNG_SUCCESS);
11335 }
11336 }
11337
11338 /* Take medium steps backward until a medium step backward would be too long
11339 * or the right frame set is found */
11340 while(file_pos > 0 && first_frame - medium_stride_length *
11341 n_frames_per_frame_set >= frame)
11342 {
11343 file_pos = frame_set->medium_stride_prev_frame_set_file_pos;
11344 if(file_pos > 0)
11345 {
11346 fseeko(tng_data->input_file,
11347 file_pos,
11348 SEEK_SET);
11349 /* Read block headers first to see what block is found. */
11350 stat = tng_block_header_read(tng_data, block);
11351 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11352 {
11353 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11354 file_pos, __FILE__, __LINE__);
11355 tng_block_destroy(&block);
11356 return(TNG_CRITICAL);
11357 }
11358
11359 if(tng_block_read_next(tng_data, block,
11360 TNG_SKIP_HASH) != TNG_SUCCESS)
11361 {
11362 tng_block_destroy(&block);
11363 return(TNG_CRITICAL);
11364 }
11365 }
11366 first_frame = tng_max_i64(frame_set->first_frame, 0);
11367 last_frame = first_frame + frame_set->n_frames - 1;
11368 if(frame >= first_frame && frame <= last_frame)
11369 {
11370 tng_block_destroy(&block);
11371 return(TNG_SUCCESS);
11372 }
11373 }
11374
11375 /* Take one step backward until the right frame set is found */
11376 while(file_pos > 0 && first_frame > frame && last_frame > frame)
11377 {
11378 file_pos = frame_set->prev_frame_set_file_pos;
11379 if(file_pos > 0)
11380 {
11381 fseeko(tng_data->input_file,
11382 file_pos,
11383 SEEK_SET);
11384 /* Read block headers first to see what block is found. */
11385 stat = tng_block_header_read(tng_data, block);
11386 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11387 {
11388 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11389 file_pos, __FILE__, __LINE__);
11390 tng_block_destroy(&block);
11391 return(TNG_CRITICAL);
11392 }
11393
11394 if(tng_block_read_next(tng_data, block,
11395 TNG_SKIP_HASH) != TNG_SUCCESS)
11396 {
11397 tng_block_destroy(&block);
11398 return(TNG_CRITICAL);
11399 }
11400 }
11401 first_frame = tng_max_i64(frame_set->first_frame, 0);
11402 last_frame = first_frame + frame_set->n_frames - 1;
11403 if(frame >= first_frame && frame <= last_frame)
11404 {
11405 tng_block_destroy(&block);
11406 return(TNG_SUCCESS);
11407 }
11408 }
11409
11410 /* If for some reason the current frame set is not yet found,
11411 * take one step forward until the right frame set is found */
11412 while(file_pos > 0 && first_frame < frame && last_frame < frame)
11413 {
11414 file_pos = frame_set->next_frame_set_file_pos;
11415 if(file_pos > 0)
11416 {
11417 fseeko(tng_data->input_file,
11418 file_pos,
11419 SEEK_SET);
11420 /* Read block headers first to see what block is found. */
11421 stat = tng_block_header_read(tng_data, block);
11422 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11423 {
11424 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11425 file_pos, __FILE__, __LINE__);
11426 tng_block_destroy(&block);
11427 return(TNG_CRITICAL);
11428 }
11429
11430 if(tng_block_read_next(tng_data, block,
11431 TNG_SKIP_HASH) != TNG_SUCCESS)
11432 {
11433 tng_block_destroy(&block);
11434 return(TNG_CRITICAL);
11435 }
11436 }
11437 first_frame = tng_max_i64(frame_set->first_frame, 0);
11438 last_frame = first_frame + frame_set->n_frames - 1;
11439 if(frame >= first_frame && frame <= last_frame)
11440 {
11441 tng_block_destroy(&block);
11442 return(TNG_SUCCESS);
11443 }
11444 }
11445
11446 tng_block_destroy(&block);
11447 return(TNG_FAILURE);
11448 }
11449
tng_frame_set_next_frame_set_file_pos_get(const tng_trajectory_t tng_data,const tng_trajectory_frame_set_t frame_set,int64_t * pos)11450 tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get
11451 (const tng_trajectory_t tng_data,
11452 const tng_trajectory_frame_set_t frame_set,
11453 int64_t *pos)
11454 {
11455 (void)tng_data;
11456
11457 TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11458 TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11459
11460 *pos = frame_set->next_frame_set_file_pos;
11461
11462 return(TNG_SUCCESS);
11463 }
11464
tng_frame_set_prev_frame_set_file_pos_get(const tng_trajectory_t tng_data,const tng_trajectory_frame_set_t frame_set,int64_t * pos)11465 tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get
11466 (const tng_trajectory_t tng_data,
11467 const tng_trajectory_frame_set_t frame_set,
11468 int64_t *pos)
11469 {
11470 (void)tng_data;
11471
11472 TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data.");
11473 TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer");
11474
11475 *pos = frame_set->prev_frame_set_file_pos;
11476
11477 return(TNG_SUCCESS);
11478 }
11479
tng_frame_set_frame_range_get(const tng_trajectory_t tng_data,const tng_trajectory_frame_set_t frame_set,int64_t * first_frame,int64_t * last_frame)11480 tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get
11481 (const tng_trajectory_t tng_data,
11482 const tng_trajectory_frame_set_t frame_set,
11483 int64_t *first_frame,
11484 int64_t *last_frame)
11485 {
11486 (void)tng_data;
11487
11488 TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer");
11489 TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer");
11490 TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer");
11491
11492 *first_frame = frame_set->first_frame;
11493 *last_frame = *first_frame + frame_set->n_frames - 1;
11494
11495 return(TNG_SUCCESS);
11496 }
11497
11498 /**
11499 * @brief Translate from the particle numbering used in a frame set to the real
11500 * particle numbering - used in the molecule description.
11501 * @param frame_set is the frame_set containing the mappings to use.
11502 * @param local is the index number of the atom in this frame set
11503 * @param real is set to the index of the atom in the molecular system.
11504 * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11505 * cannot be found.
11506 */
tng_particle_mapping_get_real_particle(const tng_trajectory_frame_set_t frame_set,const int64_t local,int64_t * real)11507 static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle
11508 (const tng_trajectory_frame_set_t frame_set,
11509 const int64_t local,
11510 int64_t *real)
11511 {
11512 int64_t i, n_blocks = frame_set->n_mapping_blocks, first;
11513 tng_particle_mapping_t mapping;
11514 if(n_blocks <= 0)
11515 {
11516 *real = local;
11517 return(TNG_SUCCESS);
11518 }
11519 for(i = 0; i < n_blocks; i++)
11520 {
11521 mapping = &frame_set->mappings[i];
11522 first = mapping->num_first_particle;
11523 if(local < first ||
11524 local >= first + mapping->n_particles)
11525 {
11526 continue;
11527 }
11528 *real = mapping->real_particle_numbers[local-first];
11529 return(TNG_SUCCESS);
11530 }
11531 *real = local;
11532 return(TNG_FAILURE);
11533 }
11534
11535 /**
11536 * @brief Translate from the real particle numbering to the particle numbering
11537 * used in a frame set.
11538 * @param frame_set is the frame_set containing the mappings to use.
11539 * @param real is the index number of the atom in the molecular system.
11540 * @param local is set to the index of the atom in this frame set.
11541 * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping
11542 * cannot be found.
11543 */
11544 /*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle
11545 (const tng_trajectory_frame_set_t frame_set,
11546 const int64_t real,
11547 int64_t *local)
11548 {
11549 int64_t i, j, n_blocks = frame_set->n_mapping_blocks;
11550 tng_particle_mapping_t mapping;
11551 if(n_blocks <= 0)
11552 {
11553 *local = real;
11554 return(TNG_SUCCESS);
11555 }
11556 for(i = 0; i < n_blocks; i++)
11557 {
11558 mapping = &frame_set->mappings[i];
11559 for(j = mapping->n_particles; j--;)
11560 {
11561 if(mapping->real_particle_numbers[j] == real)
11562 {
11563 *local = j;
11564 return(TNG_SUCCESS);
11565 }
11566 }
11567 }
11568 return(TNG_FAILURE);
11569 }
11570 */
11571
tng_file_headers_len_get(const tng_trajectory_t tng_data,int64_t * len)11572 static tng_function_status tng_file_headers_len_get
11573 (const tng_trajectory_t tng_data,
11574 int64_t *len)
11575 {
11576 int64_t orig_pos;
11577 tng_gen_block_t block;
11578
11579 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11580
11581 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11582 {
11583 return(TNG_CRITICAL);
11584 }
11585
11586 *len = 0;
11587
11588 orig_pos = ftello(tng_data->input_file);
11589
11590 fseeko(tng_data->input_file, 0, SEEK_SET);
11591
11592 tng_block_init(&block);
11593 /* Read through the headers of non-trajectory blocks (they come before the
11594 * trajectory blocks in the file) */
11595 while (*len < tng_data->input_file_len &&
11596 tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11597 block->id != -1 &&
11598 block->id != TNG_TRAJECTORY_FRAME_SET)
11599 {
11600 *len += block->header_contents_size + block->block_contents_size;
11601 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11602 }
11603
11604 fseeko(tng_data->input_file, orig_pos, SEEK_SET);
11605
11606 tng_block_destroy(&block);
11607
11608 return(TNG_SUCCESS);
11609 }
11610
tng_file_headers_read(const tng_trajectory_t tng_data,const char hash_mode)11611 tng_function_status DECLSPECDLLEXPORT tng_file_headers_read
11612 (const tng_trajectory_t tng_data,
11613 const char hash_mode)
11614 {
11615 int64_t prev_pos = 0;
11616 tng_gen_block_t block;
11617
11618 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11619
11620 tng_data->n_trajectory_frame_sets = 0;
11621
11622 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11623 {
11624 return(TNG_CRITICAL);
11625 }
11626
11627 fseeko(tng_data->input_file, 0, SEEK_SET);
11628
11629 tng_block_init(&block);
11630 /* Non trajectory blocks (they come before the trajectory
11631 * blocks in the file) */
11632 while (prev_pos < tng_data->input_file_len &&
11633 tng_block_header_read(tng_data, block) != TNG_CRITICAL &&
11634 block->id != -1 &&
11635 block->id != TNG_TRAJECTORY_FRAME_SET)
11636 {
11637 tng_block_read_next(tng_data, block, hash_mode);
11638 prev_pos = ftello(tng_data->input_file);
11639 }
11640
11641 /* Go back if a trajectory block was encountered */
11642 if(block->id == TNG_TRAJECTORY_FRAME_SET)
11643 {
11644 fseeko(tng_data->input_file, prev_pos, SEEK_SET);
11645 }
11646
11647 tng_block_destroy(&block);
11648
11649 return(TNG_SUCCESS);
11650 }
11651
tng_file_headers_write(const tng_trajectory_t tng_data,const char hash_mode)11652 tng_function_status DECLSPECDLLEXPORT tng_file_headers_write
11653 (const tng_trajectory_t tng_data,
11654 const char hash_mode)
11655 {
11656 int i;
11657 int64_t len, orig_len, tot_len = 0, data_start_pos, temp_pos = -1;
11658 tng_function_status stat;
11659 tng_gen_block_t block;
11660
11661 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11662
11663 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
11664 {
11665 return(TNG_CRITICAL);
11666 }
11667
11668 if(tng_data->n_trajectory_frame_sets > 0)
11669 {
11670 stat = tng_file_headers_len_get(tng_data, &orig_len);
11671 if(stat != TNG_SUCCESS)
11672 {
11673 return(stat);
11674 }
11675
11676 tng_block_init(&block);
11677 block->name = (char *)malloc(TNG_MAX_STR_LEN);
11678 if(!block->name)
11679 {
11680 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
11681 __FILE__, __LINE__);
11682 tng_block_destroy(&block);
11683 return(TNG_CRITICAL);
11684 }
11685 strcpy(block->name, "GENERAL INFO");
11686 tng_block_header_len_calculate(tng_data, block, &len);
11687 tot_len += len;
11688 tng_general_info_block_len_calculate(tng_data, &len);
11689 tot_len += len;
11690 strcpy(block->name, "MOLECULES");
11691 tng_block_header_len_calculate(tng_data, block, &len);
11692 tot_len += len;
11693 tng_molecules_block_len_calculate(tng_data, &len);
11694 tot_len += len;
11695
11696 for(i = 0; i < tng_data->n_data_blocks; i++)
11697 {
11698 strcpy(block->name, tng_data->non_tr_data[i].block_name);
11699 tng_block_header_len_calculate(tng_data, block, &len);
11700 tot_len += len;
11701 tng_data_block_len_calculate(tng_data,
11702 (tng_data_t)&tng_data->non_tr_data[i],
11703 TNG_FALSE, 1, 1, 1, 0, 1,
11704 &data_start_pos,
11705 &len);
11706 tot_len += len;
11707 }
11708 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11709 {
11710 strcpy(block->name, tng_data->non_tr_particle_data[i].block_name);
11711 tng_block_header_len_calculate(tng_data, block, &len);
11712 tot_len += len;
11713 tng_data_block_len_calculate(tng_data,
11714 &tng_data->non_tr_particle_data[i],
11715 TNG_TRUE, 1, 1, 1, 0,
11716 tng_data->n_particles,
11717 &data_start_pos,
11718 &len);
11719 tot_len += len;
11720 }
11721 tng_block_destroy(&block);
11722
11723 if(tot_len > orig_len)
11724 {
11725 tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
11726 tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos;
11727 }
11728
11729 stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
11730 if(stat == TNG_CRITICAL)
11731 {
11732 fprintf(stderr, "TNG library: Cannot read frame set. %s: %d\n",
11733 __FILE__, __LINE__);
11734 return(TNG_CRITICAL);
11735 }
11736
11737 /* In order to write non-trajectory data the current_trajectory_frame_set_output_file_pos
11738 * must temporarily be reset */
11739 temp_pos = tng_data->current_trajectory_frame_set_output_file_pos;
11740 tng_data->current_trajectory_frame_set_output_file_pos = -1;
11741 }
11742
11743 if(tng_general_info_block_write(tng_data, hash_mode)
11744 != TNG_SUCCESS)
11745 {
11746 fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n",
11747 tng_data->input_file_path, __FILE__, __LINE__);
11748 return(TNG_CRITICAL);
11749 }
11750
11751 if(tng_molecules_block_write(tng_data, hash_mode)
11752 != TNG_SUCCESS)
11753 {
11754 fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n",
11755 tng_data->input_file_path, __FILE__, __LINE__);
11756 return(TNG_CRITICAL);
11757 }
11758
11759 /* FIXME: Currently writing non-trajectory data blocks here.
11760 * Should perhaps be moved. */
11761 tng_block_init(&block);
11762 for(i = 0; i < tng_data->n_data_blocks; i++)
11763 {
11764 block->id = tng_data->non_tr_data[i].block_id;
11765 tng_data_block_write(tng_data, block,
11766 i, TNG_FALSE, 0, hash_mode);
11767 }
11768
11769 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
11770 {
11771 block->id = tng_data->non_tr_particle_data[i].block_id;
11772 tng_data_block_write(tng_data, block,
11773 i, TNG_TRUE, 0, hash_mode);
11774 }
11775
11776 tng_block_destroy(&block);
11777
11778 /* Continue writing at the end of the file. */
11779 fseeko(tng_data->output_file, 0, SEEK_END);
11780 if(temp_pos > 0)
11781 {
11782 tng_data->current_trajectory_frame_set_output_file_pos = temp_pos;
11783 }
11784
11785 return(TNG_SUCCESS);
11786 }
11787
tng_block_read_next(const tng_trajectory_t tng_data,const tng_gen_block_t block,const char hash_mode)11788 tng_function_status DECLSPECDLLEXPORT tng_block_read_next
11789 (const tng_trajectory_t tng_data,
11790 const tng_gen_block_t block,
11791 const char hash_mode)
11792 {
11793 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11794 TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer.");
11795
11796 switch(block->id)
11797 {
11798 case TNG_TRAJECTORY_FRAME_SET:
11799 return(tng_frame_set_block_read(tng_data, block, hash_mode));
11800 case TNG_PARTICLE_MAPPING:
11801 return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode));
11802 case TNG_GENERAL_INFO:
11803 return(tng_general_info_block_read(tng_data, block, hash_mode));
11804 case TNG_MOLECULES:
11805 return(tng_molecules_block_read(tng_data, block, hash_mode));
11806 default:
11807 if(block->id >= TNG_TRAJ_BOX_SHAPE)
11808 {
11809 return(tng_data_block_contents_read(tng_data, block, hash_mode));
11810 }
11811 else
11812 {
11813 /* Skip to the next block */
11814 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11815 return(TNG_FAILURE);
11816 }
11817 }
11818 }
11819
tng_frame_set_read(const tng_trajectory_t tng_data,const char hash_mode)11820 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read
11821 (const tng_trajectory_t tng_data,
11822 const char hash_mode)
11823 {
11824 int64_t file_pos;
11825 tng_gen_block_t block;
11826 tng_function_status stat;
11827
11828 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11829
11830 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11831 {
11832 return(TNG_CRITICAL);
11833 }
11834
11835 file_pos = ftello(tng_data->input_file);
11836
11837 tng_block_init(&block);
11838
11839 /* Read block headers first to see what block is found. */
11840 stat = tng_block_header_read(tng_data, block);
11841 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
11842 block->id == -1)
11843 {
11844 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11845 file_pos, __FILE__, __LINE__);
11846 tng_block_destroy(&block);
11847 return(TNG_CRITICAL);
11848 }
11849
11850 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
11851
11852 if(tng_block_read_next(tng_data, block,
11853 hash_mode) == TNG_SUCCESS)
11854 {
11855 tng_data->n_trajectory_frame_sets++;
11856 file_pos = ftello(tng_data->input_file);
11857 /* Read all blocks until next frame set block */
11858 stat = tng_block_header_read(tng_data, block);
11859 while(file_pos < tng_data->input_file_len &&
11860 stat != TNG_CRITICAL &&
11861 block->id != TNG_TRAJECTORY_FRAME_SET &&
11862 block->id != -1)
11863 {
11864 stat = tng_block_read_next(tng_data, block,
11865 hash_mode);
11866 if(stat != TNG_CRITICAL)
11867 {
11868 file_pos = ftello(tng_data->input_file);
11869 if(file_pos < tng_data->input_file_len)
11870 {
11871 stat = tng_block_header_read(tng_data, block);
11872 }
11873 }
11874 }
11875 if(stat == TNG_CRITICAL)
11876 {
11877 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11878 file_pos, __FILE__, __LINE__);
11879 tng_block_destroy(&block);
11880 return(stat);
11881 }
11882
11883 if(block->id == TNG_TRAJECTORY_FRAME_SET)
11884 {
11885 fseeko(tng_data->input_file, file_pos, SEEK_SET);
11886 }
11887 }
11888
11889 tng_block_destroy(&block);
11890
11891 return(TNG_SUCCESS);
11892 }
11893
11894
tng_frame_set_read_current_only_data_from_block_id(const tng_trajectory_t tng_data,const char hash_mode,const int64_t block_id)11895 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id
11896 (const tng_trajectory_t tng_data,
11897 const char hash_mode,
11898 const int64_t block_id)
11899 {
11900 int64_t file_pos;
11901 tng_gen_block_t block;
11902 tng_function_status stat;
11903 int found_flag = 1;
11904
11905 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
11906
11907 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
11908 {
11909 return(TNG_CRITICAL);
11910 }
11911
11912 file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
11913
11914 if(file_pos < 0)
11915 {
11916 /* No current frame set. This means that the first frame set must be
11917 * read */
11918 found_flag = 0;
11919 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
11920 }
11921
11922 if(file_pos > 0)
11923 {
11924 fseeko(tng_data->input_file,
11925 file_pos,
11926 SEEK_SET);
11927 }
11928 else
11929 {
11930 return(TNG_FAILURE);
11931 }
11932
11933 tng_block_init(&block);
11934
11935 /* Read block headers first to see what block is found. */
11936 stat = tng_block_header_read(tng_data, block);
11937 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
11938 {
11939 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
11940 file_pos, __FILE__, __LINE__);
11941 tng_block_destroy(&block);
11942 return(TNG_CRITICAL);
11943 }
11944 /* If the current frame set had already been read skip its block contents */
11945 if(found_flag)
11946 {
11947 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11948 }
11949 /* Otherwise read the frame set block */
11950 else
11951 {
11952 stat = tng_block_read_next(tng_data, block,
11953 hash_mode);
11954 if(stat != TNG_SUCCESS)
11955 {
11956 fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__);
11957 tng_block_destroy(&block);
11958 return(stat);
11959 }
11960 }
11961 file_pos = ftello(tng_data->input_file);
11962
11963 found_flag = 0;
11964
11965 /* Read only blocks of the requested ID
11966 * until next frame set block */
11967 stat = tng_block_header_read(tng_data, block);
11968 while(file_pos < tng_data->input_file_len &&
11969 stat != TNG_CRITICAL &&
11970 block->id != TNG_TRAJECTORY_FRAME_SET &&
11971 block->id != -1)
11972 {
11973 if(block->id == block_id)
11974 {
11975 stat = tng_block_read_next(tng_data, block,
11976 hash_mode);
11977 if(stat != TNG_CRITICAL)
11978 {
11979 file_pos = ftello(tng_data->input_file);
11980 found_flag = 1;
11981 if(file_pos < tng_data->input_file_len)
11982 {
11983 stat = tng_block_header_read(tng_data, block);
11984 }
11985 }
11986 }
11987 else
11988 {
11989 file_pos += block->block_contents_size + block->header_contents_size;
11990 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
11991 if(file_pos < tng_data->input_file_len)
11992 {
11993 stat = tng_block_header_read(tng_data, block);
11994 }
11995 }
11996 }
11997 if(stat == TNG_CRITICAL)
11998 {
11999 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12000 file_pos, __FILE__, __LINE__);
12001 tng_block_destroy(&block);
12002 return(stat);
12003 }
12004
12005 if(block->id == TNG_TRAJECTORY_FRAME_SET)
12006 {
12007 fseeko(tng_data->input_file, file_pos, SEEK_SET);
12008 }
12009
12010 tng_block_destroy(&block);
12011
12012 if(found_flag)
12013 {
12014 return(TNG_SUCCESS);
12015 }
12016 else
12017 {
12018 return(TNG_FAILURE);
12019 }
12020 }
12021
tng_frame_set_read_next(const tng_trajectory_t tng_data,const char hash_mode)12022 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next
12023 (const tng_trajectory_t tng_data,
12024 const char hash_mode)
12025 {
12026 int64_t file_pos;
12027
12028 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12029
12030 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12031 {
12032 return(TNG_CRITICAL);
12033 }
12034
12035 file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12036
12037 if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12038 {
12039 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12040 }
12041
12042 if(file_pos > 0)
12043 {
12044 fseeko(tng_data->input_file,
12045 file_pos,
12046 SEEK_SET);
12047 }
12048 else
12049 {
12050 return(TNG_FAILURE);
12051 }
12052
12053 return(tng_frame_set_read(tng_data, hash_mode));
12054 }
12055
tng_frame_set_read_next_only_data_from_block_id(const tng_trajectory_t tng_data,const char hash_mode,const int64_t block_id)12056 tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id
12057 (const tng_trajectory_t tng_data,
12058 const char hash_mode,
12059 const int64_t block_id)
12060 {
12061 int64_t file_pos;
12062 tng_gen_block_t block;
12063 tng_function_status stat;
12064
12065 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12066
12067 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
12068 {
12069 return(TNG_CRITICAL);
12070 }
12071
12072 file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos;
12073
12074 if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12075 {
12076 file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12077 }
12078
12079 if(file_pos > 0)
12080 {
12081 fseeko(tng_data->input_file,
12082 file_pos,
12083 SEEK_SET);
12084 }
12085 else
12086 {
12087 return(TNG_FAILURE);
12088 }
12089
12090 tng_block_init(&block);
12091
12092 /* Read block headers first to see what block is found. */
12093 stat = tng_block_header_read(tng_data, block);
12094 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12095 {
12096 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12097 file_pos, __FILE__, __LINE__);
12098 tng_block_destroy(&block);
12099 return(TNG_CRITICAL);
12100 }
12101
12102 tng_data->current_trajectory_frame_set_input_file_pos = file_pos;
12103
12104 if(tng_block_read_next(tng_data, block,
12105 hash_mode) == TNG_SUCCESS)
12106 {
12107 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id);
12108 }
12109
12110 tng_block_destroy(&block);
12111
12112 return(stat);
12113 }
12114
tng_frame_set_write(const tng_trajectory_t tng_data,const char hash_mode)12115 tng_function_status tng_frame_set_write
12116 (const tng_trajectory_t tng_data,
12117 const char hash_mode)
12118 {
12119 int i, j;
12120 tng_gen_block_t block;
12121 tng_trajectory_frame_set_t frame_set;
12122 tng_function_status stat;
12123
12124 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12125
12126 frame_set = &tng_data->current_trajectory_frame_set;
12127
12128 if(frame_set->n_written_frames == frame_set->n_frames)
12129 {
12130 return(TNG_SUCCESS);
12131 }
12132
12133 tng_data->current_trajectory_frame_set_output_file_pos =
12134 ftello(tng_data->output_file);
12135 tng_data->last_trajectory_frame_set_output_file_pos =
12136 tng_data->current_trajectory_frame_set_output_file_pos;
12137
12138 if(tng_data->current_trajectory_frame_set_output_file_pos <= 0)
12139 {
12140 return(TNG_FAILURE);
12141 }
12142
12143 if(tng_data->first_trajectory_frame_set_output_file_pos == -1)
12144 {
12145 tng_data->first_trajectory_frame_set_output_file_pos =
12146 tng_data->current_trajectory_frame_set_output_file_pos;
12147 }
12148
12149 tng_block_init(&block);
12150
12151 if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS)
12152 {
12153 tng_block_destroy(&block);
12154 return(TNG_FAILURE);
12155 }
12156
12157 /* Write non-particle data blocks */
12158 for(i = 0; i<frame_set->n_data_blocks; i++)
12159 {
12160 block->id = frame_set->tr_data[i].block_id;
12161 tng_data_block_write(tng_data, block, i, TNG_FALSE, 0, hash_mode);
12162 }
12163 /* Write the mapping blocks and particle data blocks*/
12164 if(frame_set->n_mapping_blocks)
12165 {
12166 for(i = 0; i < frame_set->n_mapping_blocks; i++)
12167 {
12168 block->id = TNG_PARTICLE_MAPPING;
12169 if(frame_set->mappings[i].n_particles > 0)
12170 {
12171 tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode);
12172 for(j = 0; j<frame_set->n_particle_data_blocks; j++)
12173 {
12174 block->id = frame_set->tr_particle_data[j].block_id;
12175 tng_data_block_write(tng_data, block,
12176 j, TNG_TRUE, &frame_set->mappings[i],
12177 hash_mode);
12178 }
12179 }
12180 }
12181 }
12182 else
12183 {
12184 for(i = 0; i<frame_set->n_particle_data_blocks; i++)
12185 {
12186 block->id = frame_set->tr_particle_data[i].block_id;
12187 tng_data_block_write(tng_data, block,
12188 i, TNG_TRUE, 0, hash_mode);
12189 }
12190 }
12191
12192
12193 /* Update pointers in the general info block */
12194 stat = tng_header_pointers_update(tng_data, hash_mode);
12195
12196 if(stat == TNG_SUCCESS)
12197 {
12198 stat = tng_frame_set_pointers_update(tng_data, hash_mode);
12199 }
12200
12201 tng_block_destroy(&block);
12202
12203 frame_set->n_unwritten_frames = 0;
12204
12205 fflush(tng_data->output_file);
12206
12207 return(stat);
12208 }
12209
tng_frame_set_premature_write(const tng_trajectory_t tng_data,const char hash_mode)12210 tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write
12211 (const tng_trajectory_t tng_data,
12212 const char hash_mode)
12213 {
12214 tng_trajectory_frame_set_t frame_set;
12215
12216 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12217
12218 frame_set = &tng_data->current_trajectory_frame_set;
12219
12220 if(frame_set->n_unwritten_frames == 0)
12221 {
12222 return(TNG_SUCCESS);
12223 }
12224 frame_set->n_frames = frame_set->n_unwritten_frames;
12225
12226 return(tng_frame_set_write(tng_data, hash_mode));
12227 }
12228
tng_frame_set_new(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t n_frames)12229 tng_function_status DECLSPECDLLEXPORT tng_frame_set_new
12230 (const tng_trajectory_t tng_data,
12231 const int64_t first_frame,
12232 const int64_t n_frames)
12233 {
12234 tng_gen_block_t block;
12235 tng_trajectory_frame_set_t frame_set;
12236 FILE *temp = tng_data->input_file;
12237 int64_t curr_file_pos;
12238
12239 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12240 TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12241 TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12242
12243 frame_set = &tng_data->current_trajectory_frame_set;
12244
12245 curr_file_pos = ftello(tng_data->output_file);
12246
12247 if(curr_file_pos <= 10)
12248 {
12249 tng_file_headers_write(tng_data, TNG_USE_HASH);
12250 }
12251
12252 /* Set pointer to previous frame set to the one that was loaded
12253 * before.
12254 * FIXME: This is a bit risky. If they are not added in order
12255 * it will be wrong. */
12256 if(tng_data->n_trajectory_frame_sets)
12257 {
12258 frame_set->prev_frame_set_file_pos =
12259 tng_data->last_trajectory_frame_set_output_file_pos;
12260 }
12261
12262 frame_set->next_frame_set_file_pos = -1;
12263
12264 tng_data->current_trajectory_frame_set_output_file_pos =
12265 ftello(tng_data->output_file);
12266
12267 tng_data->n_trajectory_frame_sets++;
12268
12269 /* Set the medium range pointers */
12270 if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1)
12271 {
12272 frame_set->medium_stride_prev_frame_set_file_pos =
12273 tng_data->first_trajectory_frame_set_output_file_pos;
12274 }
12275 else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12276 {
12277 /* FIXME: Currently only working if the previous frame set has its
12278 * medium stride pointer already set. This might need some fixing. */
12279 if(frame_set->medium_stride_prev_frame_set_file_pos != -1 &&
12280 frame_set->medium_stride_prev_frame_set_file_pos != 0)
12281 {
12282 tng_block_init(&block);
12283 tng_data->input_file = tng_data->output_file;
12284
12285 curr_file_pos = ftello(tng_data->output_file);
12286 fseeko(tng_data->output_file,
12287 frame_set->medium_stride_prev_frame_set_file_pos,
12288 SEEK_SET);
12289
12290 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12291 {
12292 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12293 __FILE__, __LINE__);
12294 tng_data->input_file = temp;
12295 tng_block_destroy(&block);
12296 return(TNG_CRITICAL);
12297 }
12298
12299 /* Read the next frame set from the previous frame set and one
12300 * medium stride step back */
12301 fseeko(tng_data->output_file, block->block_contents_size - (6 *
12302 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12303 if(fread(&frame_set->medium_stride_prev_frame_set_file_pos,
12304 sizeof(frame_set->medium_stride_prev_frame_set_file_pos),
12305 1, tng_data->output_file) == 0)
12306 {
12307 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12308 tng_data->input_file = temp;
12309 tng_block_destroy(&block);
12310 return(TNG_CRITICAL);
12311 }
12312
12313 if(tng_data->input_endianness_swap_func_64)
12314 {
12315 if(tng_data->input_endianness_swap_func_64(tng_data,
12316 (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos)
12317 != TNG_SUCCESS)
12318 {
12319 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12320 __FILE__, __LINE__);
12321 }
12322 }
12323
12324 tng_block_destroy(&block);
12325
12326 /* Set the long range pointers */
12327 if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1)
12328 {
12329 frame_set->long_stride_prev_frame_set_file_pos =
12330 tng_data->first_trajectory_frame_set_output_file_pos;
12331 }
12332 else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1)
12333 {
12334 /* FIXME: Currently only working if the previous frame set has its
12335 * long stride pointer already set. This might need some fixing. */
12336 if(frame_set->long_stride_prev_frame_set_file_pos != -1 &&
12337 frame_set->long_stride_prev_frame_set_file_pos != 0)
12338 {
12339 tng_block_init(&block);
12340 tng_data->input_file = tng_data->output_file;
12341
12342 fseeko(tng_data->output_file,
12343 frame_set->long_stride_prev_frame_set_file_pos,
12344 SEEK_SET);
12345
12346 if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
12347 {
12348 fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n",
12349 __FILE__, __LINE__);
12350 tng_data->input_file = temp;
12351 tng_block_destroy(&block);
12352 return(TNG_CRITICAL);
12353 }
12354
12355 /* Read the next frame set from the previous frame set and one
12356 * long stride step back */
12357 fseeko(tng_data->output_file, block->block_contents_size - (6 *
12358 sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR);
12359
12360 tng_block_destroy(&block);
12361
12362 if(fread(&frame_set->long_stride_prev_frame_set_file_pos,
12363 sizeof(frame_set->long_stride_prev_frame_set_file_pos),
12364 1, tng_data->output_file) == 0)
12365 {
12366 fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__);
12367 tng_data->input_file = temp;
12368 return(TNG_CRITICAL);
12369 }
12370
12371 if(tng_data->input_endianness_swap_func_64)
12372 {
12373 if(tng_data->input_endianness_swap_func_64(tng_data,
12374 (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos)
12375 != TNG_SUCCESS)
12376 {
12377 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
12378 __FILE__, __LINE__);
12379 }
12380 }
12381
12382 }
12383 }
12384
12385 tng_data->input_file = temp;
12386 fseeko(tng_data->output_file, curr_file_pos, SEEK_SET);
12387 }
12388 }
12389
12390 frame_set->first_frame = first_frame;
12391 frame_set->n_frames = n_frames;
12392 frame_set->n_written_frames = 0;
12393 frame_set->n_unwritten_frames = 0;
12394 frame_set->first_frame_time = -1;
12395
12396 if(tng_data->first_trajectory_frame_set_output_file_pos == -1 ||
12397 tng_data->first_trajectory_frame_set_output_file_pos == 0)
12398 {
12399 tng_data->first_trajectory_frame_set_output_file_pos =
12400 tng_data->current_trajectory_frame_set_output_file_pos;
12401 }
12402 /* FIXME: Should check the frame number instead of the file_pos,
12403 * in case frame sets are not in order */
12404 if(tng_data->last_trajectory_frame_set_output_file_pos == -1 ||
12405 tng_data->last_trajectory_frame_set_output_file_pos == 0 ||
12406 tng_data->last_trajectory_frame_set_output_file_pos <
12407 tng_data->current_trajectory_frame_set_output_file_pos)
12408 {
12409 tng_data->last_trajectory_frame_set_output_file_pos =
12410 tng_data->current_trajectory_frame_set_output_file_pos;
12411 }
12412
12413 return(TNG_SUCCESS);
12414 }
12415
tng_frame_set_with_time_new(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t n_frames,const double first_frame_time)12416 tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new
12417 (const tng_trajectory_t tng_data,
12418 const int64_t first_frame,
12419 const int64_t n_frames,
12420 const double first_frame_time)
12421 {
12422 tng_function_status stat;
12423
12424 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12425 TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0.");
12426 TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0.");
12427 TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12428
12429
12430 stat = tng_frame_set_new(tng_data, first_frame, n_frames);
12431 if(stat != TNG_SUCCESS)
12432 {
12433 return(stat);
12434 }
12435 stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time);
12436
12437 return(stat);
12438 }
12439
tng_frame_set_first_frame_time_set(const tng_trajectory_t tng_data,const double first_frame_time)12440 tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set
12441 (const tng_trajectory_t tng_data,
12442 const double first_frame_time)
12443 {
12444 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12445 TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0.");
12446
12447 tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time;
12448
12449 return(TNG_SUCCESS);
12450 }
12451
tng_first_frame_nr_of_next_frame_set_get(const tng_trajectory_t tng_data,int64_t * frame)12452 tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get
12453 (const tng_trajectory_t tng_data,
12454 int64_t *frame)
12455 {
12456 int64_t file_pos, next_frame_set_file_pos;
12457 tng_gen_block_t block;
12458 tng_function_status stat;
12459
12460 tng_trajectory_frame_set_t frame_set;
12461
12462 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12463 TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set");
12464 TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer");
12465
12466 file_pos = ftello(tng_data->input_file);
12467
12468 if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12469 {
12470 next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
12471 }
12472 else
12473 {
12474 frame_set = &tng_data->current_trajectory_frame_set;
12475 next_frame_set_file_pos = frame_set->next_frame_set_file_pos;
12476 }
12477
12478 if(next_frame_set_file_pos <= 0)
12479 {
12480 return(TNG_FAILURE);
12481 }
12482
12483 fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET);
12484 /* Read block headers first to see that a frame set block is found. */
12485 tng_block_init(&block);
12486 stat = tng_block_header_read(tng_data, block);
12487 if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
12488 {
12489 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
12490 file_pos, __FILE__, __LINE__);
12491 return(TNG_CRITICAL);
12492 }
12493 /* if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
12494 {
12495 tng_block_read_next(tng_data, block, TNG_USE_HASH);
12496 }*/
12497 tng_block_destroy(&block);
12498
12499 if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0)
12500 {
12501 fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n",
12502 __FILE__, __LINE__);
12503 return(TNG_CRITICAL);
12504 }
12505 fseeko(tng_data->input_file, file_pos, SEEK_SET);
12506
12507 return(TNG_SUCCESS);
12508 }
12509
tng_gen_data_block_add(const tng_trajectory_t tng_data,const int64_t id,const tng_bool is_particle_data,const char * block_name,const char datatype,const char block_type_flag,int64_t n_frames,const int64_t n_values_per_frame,int64_t stride_length,const int64_t num_first_particle,const int64_t n_particles,const int64_t codec_id,void * new_data)12510 static tng_function_status tng_gen_data_block_add
12511 (const tng_trajectory_t tng_data,
12512 const int64_t id,
12513 const tng_bool is_particle_data,
12514 const char *block_name,
12515 const char datatype,
12516 const char block_type_flag,
12517 int64_t n_frames,
12518 const int64_t n_values_per_frame,
12519 int64_t stride_length,
12520 const int64_t num_first_particle,
12521 const int64_t n_particles,
12522 const int64_t codec_id,
12523 void *new_data)
12524 {
12525 int i, size, len;
12526 int64_t j, k;
12527 int64_t tot_n_particles, n_frames_div;
12528 char ***first_dim_values, **second_dim_values;
12529 tng_trajectory_frame_set_t frame_set;
12530 tng_data_t data;
12531 char *new_data_c = (char *)new_data;
12532 tng_function_status stat;
12533
12534 frame_set = &tng_data->current_trajectory_frame_set;
12535
12536 if(stride_length <= 0)
12537 {
12538 stride_length = 1;
12539 }
12540
12541 if(is_particle_data)
12542 {
12543 stat = tng_particle_data_find(tng_data, id, &data);
12544 }
12545 else
12546 {
12547 stat = tng_data_find(tng_data, id, &data);
12548 }
12549 /* If the block does not exist, create it */
12550 if(stat != TNG_SUCCESS)
12551 {
12552 if(is_particle_data)
12553 {
12554 stat = tng_particle_data_block_create(tng_data, block_type_flag);
12555 }
12556 else
12557 {
12558 stat = tng_data_block_create(tng_data, block_type_flag);
12559 }
12560
12561 if(stat != TNG_SUCCESS)
12562 {
12563 fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n",
12564 __FILE__, __LINE__);
12565 return(TNG_CRITICAL);
12566 }
12567 if(is_particle_data)
12568 {
12569 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12570 {
12571 data = &frame_set->tr_particle_data[frame_set->
12572 n_particle_data_blocks - 1];
12573 }
12574 else
12575 {
12576 data = &tng_data->non_tr_particle_data[tng_data->
12577 n_particle_data_blocks - 1];
12578 }
12579 }
12580 else
12581 {
12582 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
12583 {
12584 data = &frame_set->tr_data[frame_set->n_data_blocks - 1];
12585 }
12586 else
12587 {
12588 data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1];
12589 }
12590 }
12591 data->block_id = id;
12592
12593 len = tng_min_size(strlen(block_name) + 1, TNG_MAX_STR_LEN);
12594 data->block_name = (char *)malloc(len);
12595 if(!data->block_name)
12596 {
12597 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12598 __FILE__, __LINE__);
12599 return(TNG_CRITICAL);
12600 }
12601 strncpy(data->block_name, block_name, len);
12602
12603 data->values = 0;
12604 /* FIXME: Memory leak from strings. */
12605 data->strings = 0;
12606 data->last_retrieved_frame = -1;
12607 }
12608
12609 data->datatype = datatype;
12610 data->stride_length = tng_max_i64(stride_length, 1);
12611 data->n_values_per_frame = n_values_per_frame;
12612 data->n_frames = n_frames;
12613 if(is_particle_data)
12614 {
12615 data->dependency = TNG_PARTICLE_DEPENDENT;
12616 }
12617 else
12618 {
12619 data->dependency = 0;
12620 }
12621 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
12622 (n_frames > 1 ||
12623 frame_set->n_frames == n_frames ||
12624 stride_length > 1))
12625 {
12626 data->dependency += TNG_FRAME_DEPENDENT;
12627 }
12628 data->codec_id = codec_id;
12629 data->compression_multiplier = 1.0;
12630 /* FIXME: This can cause problems. */
12631 data->first_frame_with_data = frame_set->first_frame;
12632
12633 if(is_particle_data)
12634 {
12635 if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag)
12636 {
12637 tot_n_particles = frame_set->n_particles;
12638 }
12639 else
12640 {
12641 tot_n_particles = tng_data->n_particles;
12642 }
12643 }
12644 /* This is just to keep the compiler happy - avoid it considering tot_n_particles
12645 * uninitialized. */
12646 else
12647 {
12648 tot_n_particles = 0;
12649 }
12650
12651 /* If data values are supplied add that data to the data block. */
12652 if(new_data_c)
12653 {
12654 /* Allocate memory */
12655 if(is_particle_data)
12656 {
12657 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
12658 stride_length, tot_n_particles,
12659 n_values_per_frame);
12660 }
12661 else
12662 {
12663 stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length,
12664 n_values_per_frame);
12665 }
12666 if(stat != TNG_SUCCESS)
12667 {
12668 fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n",
12669 __FILE__, __LINE__);
12670 return(TNG_CRITICAL);
12671 }
12672
12673 if(n_frames > frame_set->n_unwritten_frames)
12674 {
12675 frame_set->n_unwritten_frames = n_frames;
12676 }
12677
12678 n_frames_div = (n_frames % stride_length) ?
12679 n_frames / stride_length + 1:
12680 n_frames / stride_length;
12681
12682 if(datatype == TNG_CHAR_DATA)
12683 {
12684 if(is_particle_data)
12685 {
12686 for(i = 0; i < n_frames_div; i++)
12687 {
12688 first_dim_values = data->strings[i];
12689 for(j = num_first_particle; j < num_first_particle + n_particles;
12690 j++)
12691 {
12692 second_dim_values = first_dim_values[j];
12693 for(k = 0; k < n_values_per_frame; k++)
12694 {
12695 len = tng_min_size(strlen(new_data_c) + 1,
12696 TNG_MAX_STR_LEN);
12697 if(second_dim_values[k])
12698 {
12699 free(second_dim_values[k]);
12700 }
12701 second_dim_values[k] = (char *)malloc(len);
12702 if(!second_dim_values[k])
12703 {
12704 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12705 __FILE__, __LINE__);
12706 return(TNG_CRITICAL);
12707 }
12708 strncpy(second_dim_values[k],
12709 new_data_c, len);
12710 new_data_c += len;
12711 }
12712 }
12713 }
12714 }
12715 else
12716 {
12717 for(i = 0; i < n_frames_div; i++)
12718 {
12719 second_dim_values = data->strings[0][i];
12720 for(j = 0; j < n_values_per_frame; j++)
12721 {
12722 len = tng_min_size(strlen(new_data_c) + 1,
12723 TNG_MAX_STR_LEN);
12724 if(second_dim_values[j])
12725 {
12726 free(second_dim_values[j]);
12727 }
12728 second_dim_values[j] = (char *)malloc(len);
12729 if(!second_dim_values[j])
12730 {
12731 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
12732 __FILE__, __LINE__);
12733 return(TNG_CRITICAL);
12734 }
12735 strncpy(second_dim_values[j],
12736 new_data_c, len);
12737 new_data_c += len;
12738 }
12739 }
12740 }
12741 }
12742 else
12743 {
12744 switch(datatype)
12745 {
12746 case TNG_INT_DATA:
12747 size = sizeof(int64_t);
12748 break;
12749 case TNG_FLOAT_DATA:
12750 size = sizeof(float);
12751 break;
12752 case TNG_DOUBLE_DATA:
12753 default:
12754 size = sizeof(double);
12755 }
12756
12757 if(is_particle_data)
12758 {
12759 memcpy(data->values, new_data, size * n_frames_div *
12760 n_particles * n_values_per_frame);
12761 }
12762 else
12763 {
12764 memcpy(data->values, new_data, size * n_frames_div *
12765 n_values_per_frame);
12766 }
12767 }
12768 }
12769
12770 return(TNG_SUCCESS);
12771 }
12772
tng_data_block_add(const tng_trajectory_t tng_data,const int64_t id,const char * block_name,const char datatype,const char block_type_flag,int64_t n_frames,const int64_t n_values_per_frame,int64_t stride_length,const int64_t codec_id,void * new_data)12773 tng_function_status DECLSPECDLLEXPORT tng_data_block_add
12774 (const tng_trajectory_t tng_data,
12775 const int64_t id,
12776 const char *block_name,
12777 const char datatype,
12778 const char block_type_flag,
12779 int64_t n_frames,
12780 const int64_t n_values_per_frame,
12781 int64_t stride_length,
12782 const int64_t codec_id,
12783 void *new_data)
12784 {
12785 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12786 TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer.");
12787 TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12788
12789 return(tng_gen_data_block_add(tng_data, id, TNG_FALSE, block_name, datatype,
12790 block_type_flag, n_frames, n_values_per_frame,
12791 stride_length, 0, 0, codec_id, new_data));
12792 }
12793
tng_particle_data_block_add(const tng_trajectory_t tng_data,const int64_t id,const char * block_name,const char datatype,const char block_type_flag,int64_t n_frames,const int64_t n_values_per_frame,int64_t stride_length,const int64_t num_first_particle,const int64_t n_particles,const int64_t codec_id,void * new_data)12794 tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add
12795 (const tng_trajectory_t tng_data,
12796 const int64_t id,
12797 const char *block_name,
12798 const char datatype,
12799 const char block_type_flag,
12800 int64_t n_frames,
12801 const int64_t n_values_per_frame,
12802 int64_t stride_length,
12803 const int64_t num_first_particle,
12804 const int64_t n_particles,
12805 const int64_t codec_id,
12806 void *new_data)
12807 {
12808 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12809 TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer.");
12810 TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer.");
12811 TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0.");
12812 TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0.");
12813
12814 return(tng_gen_data_block_add(tng_data, id, TNG_TRUE, block_name, datatype,
12815 block_type_flag, n_frames, n_values_per_frame,
12816 stride_length, num_first_particle, n_particles,
12817 codec_id, new_data));
12818 }
12819
tng_data_block_name_get(const tng_trajectory_t tng_data,const int64_t block_id,char * name,const int max_len)12820 tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get
12821 (const tng_trajectory_t tng_data,
12822 const int64_t block_id,
12823 char *name,
12824 const int max_len)
12825 {
12826 int64_t i;
12827 tng_trajectory_frame_set_t frame_set;
12828 tng_function_status stat;
12829 tng_data_t data;
12830 int block_type = -1;
12831
12832 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12833 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
12834
12835 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12836 {
12837 data = &tng_data->non_tr_particle_data[i];
12838 if(data->block_id == block_id)
12839 {
12840 strncpy(name, data->block_name, max_len);
12841 name[max_len - 1] = '\0';
12842 return(TNG_SUCCESS);
12843 }
12844 }
12845 for(i = 0; i < tng_data->n_data_blocks; i++)
12846 {
12847 data = &tng_data->non_tr_data[i];
12848 if(data->block_id == block_id)
12849 {
12850 strncpy(name, data->block_name, max_len);
12851 name[max_len - 1] = '\0';
12852 return(TNG_SUCCESS);
12853 }
12854 }
12855
12856 frame_set = &tng_data->current_trajectory_frame_set;
12857
12858 stat = tng_particle_data_find(tng_data, block_id, &data);
12859 if(stat == TNG_SUCCESS)
12860 {
12861 block_type = TNG_PARTICLE_BLOCK_DATA;
12862 }
12863 else
12864 {
12865 stat = tng_data_find(tng_data, block_id, &data);
12866 if(stat == TNG_SUCCESS)
12867 {
12868 block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12869 }
12870 else
12871 {
12872 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12873 if(stat != TNG_SUCCESS)
12874 {
12875 return(stat);
12876 }
12877 stat = tng_particle_data_find(tng_data, block_id, &data);
12878 if(stat == TNG_SUCCESS)
12879 {
12880 block_type = TNG_PARTICLE_BLOCK_DATA;
12881 }
12882 else
12883 {
12884 stat = tng_data_find(tng_data, block_id, &data);
12885 if(stat == TNG_SUCCESS)
12886 {
12887 block_type = TNG_NON_PARTICLE_BLOCK_DATA;
12888 }
12889 }
12890 }
12891 }
12892 if(block_type == TNG_PARTICLE_BLOCK_DATA)
12893 {
12894 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
12895 {
12896 data = &frame_set->tr_particle_data[i];
12897 if(data->block_id == block_id)
12898 {
12899 strncpy(name, data->block_name, max_len);
12900 name[max_len - 1] = '\0';
12901 return(TNG_SUCCESS);
12902 }
12903 }
12904 }
12905 else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
12906 {
12907 for(i = 0; i < frame_set->n_data_blocks; i++)
12908 {
12909 data = &frame_set->tr_data[i];
12910 if(data->block_id == block_id)
12911 {
12912 strncpy(name, data->block_name, max_len);
12913 name[max_len - 1] = '\0';
12914 return(TNG_SUCCESS);
12915 }
12916 }
12917 }
12918
12919 return(TNG_FAILURE);
12920 }
12921
tng_data_block_dependency_get(const tng_trajectory_t tng_data,const int64_t block_id,int * block_dependency)12922 tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get
12923 (const tng_trajectory_t tng_data,
12924 const int64_t block_id,
12925 int *block_dependency)
12926 {
12927 int64_t i;
12928 tng_function_status stat;
12929 tng_data_t data;
12930
12931 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
12932 TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer.");
12933
12934 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
12935 {
12936 data = &tng_data->non_tr_particle_data[i];
12937 if(data->block_id == block_id)
12938 {
12939 *block_dependency = TNG_PARTICLE_DEPENDENT;
12940 return(TNG_SUCCESS);
12941 }
12942 }
12943 for(i = 0; i < tng_data->n_data_blocks; i++)
12944 {
12945 data = &tng_data->non_tr_data[i];
12946 if(data->block_id == block_id)
12947 {
12948 *block_dependency = 0;
12949 return(TNG_SUCCESS);
12950 }
12951 }
12952
12953 stat = tng_particle_data_find(tng_data, block_id, &data);
12954 if(stat == TNG_SUCCESS)
12955 {
12956 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12957 return(TNG_SUCCESS);
12958 }
12959 else
12960 {
12961 stat = tng_data_find(tng_data, block_id, &data);
12962 if(stat == TNG_SUCCESS)
12963 {
12964 *block_dependency = TNG_FRAME_DEPENDENT;
12965 return(TNG_SUCCESS);
12966 }
12967 else
12968 {
12969 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
12970 if(stat != TNG_SUCCESS)
12971 {
12972 return(stat);
12973 }
12974 stat = tng_particle_data_find(tng_data, block_id, &data);
12975 if(stat == TNG_SUCCESS)
12976 {
12977 *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT;
12978 return(TNG_SUCCESS);
12979 }
12980 else
12981 {
12982 stat = tng_data_find(tng_data, block_id, &data);
12983 if(stat == TNG_SUCCESS)
12984 {
12985 *block_dependency = TNG_FRAME_DEPENDENT;
12986 return(TNG_SUCCESS);
12987 }
12988 }
12989 }
12990 }
12991
12992 return(TNG_FAILURE);
12993 }
12994
tng_data_block_num_values_per_frame_get(const tng_trajectory_t tng_data,const int64_t block_id,int64_t * n_values_per_frame)12995 tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get
12996 (const tng_trajectory_t tng_data,
12997 const int64_t block_id,
12998 int64_t *n_values_per_frame)
12999 {
13000 int64_t i;
13001 tng_function_status stat;
13002 tng_data_t data;
13003
13004 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13005 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
13006
13007 for(i = 0; i < tng_data->n_particle_data_blocks; i++)
13008 {
13009 data = &tng_data->non_tr_particle_data[i];
13010 if(data->block_id == block_id)
13011 {
13012 *n_values_per_frame = data->n_values_per_frame;
13013 return(TNG_SUCCESS);
13014 }
13015 }
13016 for(i = 0; i < tng_data->n_data_blocks; i++)
13017 {
13018 data = &tng_data->non_tr_data[i];
13019 if(data->block_id == block_id)
13020 {
13021 *n_values_per_frame = data->n_values_per_frame;
13022 return(TNG_SUCCESS);
13023 }
13024 }
13025
13026 stat = tng_particle_data_find(tng_data, block_id, &data);
13027 if(stat == TNG_SUCCESS)
13028 {
13029 *n_values_per_frame = data->n_values_per_frame;
13030 return(TNG_SUCCESS);
13031 }
13032 else
13033 {
13034 stat = tng_data_find(tng_data, block_id, &data);
13035 if(stat == TNG_SUCCESS)
13036 {
13037 *n_values_per_frame = data->n_values_per_frame;
13038 return(TNG_SUCCESS);
13039 }
13040 else
13041 {
13042 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
13043 if(stat != TNG_SUCCESS)
13044 {
13045 return(stat);
13046 }
13047 stat = tng_particle_data_find(tng_data, block_id, &data);
13048 if(stat == TNG_SUCCESS)
13049 {
13050 *n_values_per_frame = data->n_values_per_frame;
13051 return(TNG_SUCCESS);
13052 }
13053 else
13054 {
13055 stat = tng_data_find(tng_data, block_id, &data);
13056 if(stat == TNG_SUCCESS)
13057 {
13058 *n_values_per_frame = data->n_values_per_frame;
13059 return(TNG_SUCCESS);
13060 }
13061 }
13062 }
13063 }
13064
13065 return(TNG_FAILURE);
13066 }
13067
tng_frame_set_n_frames_of_data_block_get(const tng_trajectory_t tng_data,const int64_t block_id,int64_t * n_frames)13068 tng_function_status DECLSPECDLLEXPORT tng_frame_set_n_frames_of_data_block_get
13069 (const tng_trajectory_t tng_data,
13070 const int64_t block_id,
13071 int64_t *n_frames)
13072 {
13073 tng_gen_block_t block;
13074 tng_function_status stat;
13075 char datatype, dependency, sparse_data;
13076 int64_t n_values, codec_id, first_frame_with_data, stride_length, curr_n_frames;
13077 int64_t num_first_particle, block_n_particles;
13078 double multiplier;
13079 md5_state_t md5_state;
13080 int found = TNG_FALSE;
13081
13082 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13083
13084 tng_block_init(&block);
13085
13086 stat = tng_block_header_read(tng_data, block);
13087 /* If the block header could not be read the reading position might not have been
13088 * at the start of a block. Try again from the file position of the current frame
13089 * set. */
13090 if(stat != TNG_SUCCESS)
13091 {
13092 fseeko(tng_data->input_file, tng_data->current_trajectory_frame_set_input_file_pos, SEEK_SET);
13093 stat = tng_block_header_read(tng_data, block);
13094 if(stat != TNG_SUCCESS)
13095 {
13096 tng_block_destroy(&block);
13097 return(stat);
13098 }
13099 }
13100 if(block->id == TNG_TRAJECTORY_FRAME_SET)
13101 {
13102 stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH);
13103 if(stat != TNG_SUCCESS)
13104 {
13105 tng_block_destroy(&block);
13106 return(stat);
13107 }
13108 stat = tng_block_header_read(tng_data, block);
13109 }
13110 while(stat == TNG_SUCCESS && block->id != TNG_TRAJECTORY_FRAME_SET && found == TNG_FALSE)
13111 {
13112 if(block->id == block_id)
13113 {
13114 stat = tng_data_block_meta_information_read(tng_data, &datatype,
13115 &dependency, &sparse_data,
13116 &n_values, &codec_id,
13117 &first_frame_with_data,
13118 &stride_length, &curr_n_frames,
13119 &num_first_particle,
13120 &block_n_particles,
13121 &multiplier, TNG_SKIP_HASH,
13122 &md5_state);
13123 if(stat == TNG_SUCCESS)
13124 {
13125 found = TNG_TRUE;
13126 }
13127 }
13128 else
13129 {
13130 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
13131 stat = tng_block_header_read(tng_data, block);
13132 }
13133 }
13134 if(found == TNG_TRUE)
13135 {
13136 *n_frames = (tng_data->current_trajectory_frame_set.n_frames -
13137 (tng_data->current_trajectory_frame_set.first_frame - first_frame_with_data)) / stride_length;
13138 }
13139 else if(stat == TNG_SUCCESS)
13140 {
13141 *n_frames = 0;
13142 }
13143
13144 tng_block_destroy(&block);
13145
13146 return(stat);
13147 }
13148
tng_frame_gen_data_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const int64_t block_id,const tng_bool is_particle_data,const int64_t val_first_particle,const int64_t val_n_particles,const void * values,const char hash_mode)13149 static tng_function_status tng_frame_gen_data_write
13150 (const tng_trajectory_t tng_data,
13151 const int64_t frame_nr,
13152 const int64_t block_id,
13153 const tng_bool is_particle_data,
13154 const int64_t val_first_particle,
13155 const int64_t val_n_particles,
13156 const void *values,
13157 const char hash_mode)
13158 {
13159 int64_t header_pos, file_pos, tot_n_particles;
13160 int64_t output_file_len, n_values_per_frame, size, contents_size;
13161 int64_t header_size, temp_first, temp_last;
13162 int64_t mapping_block_end_pos, num_first_particle, block_n_particles;
13163 int64_t i, last_frame, temp_current, write_n_particles;
13164 tng_gen_block_t block;
13165 tng_trajectory_frame_set_t frame_set;
13166 FILE *temp = tng_data->input_file;
13167 struct tng_data data;
13168 tng_function_status stat;
13169 tng_particle_mapping_t mapping;
13170 char dependency, sparse_data, datatype;
13171 void *copy;
13172
13173 if(tng_output_file_init(tng_data) != TNG_SUCCESS)
13174 {
13175 fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n",
13176 __FILE__, __LINE__);
13177 return(TNG_CRITICAL);
13178 }
13179
13180 temp_first = tng_data->first_trajectory_frame_set_input_file_pos;
13181 temp_last = tng_data->last_trajectory_frame_set_input_file_pos;
13182 temp_current = tng_data->current_trajectory_frame_set_input_file_pos;
13183 tng_data->first_trajectory_frame_set_input_file_pos =
13184 tng_data->first_trajectory_frame_set_output_file_pos;
13185 tng_data->last_trajectory_frame_set_input_file_pos =
13186 tng_data->last_trajectory_frame_set_output_file_pos;
13187 tng_data->current_trajectory_frame_set_input_file_pos =
13188 tng_data->current_trajectory_frame_set_output_file_pos;
13189
13190 tng_data->input_file = tng_data->output_file;
13191
13192 stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
13193
13194 frame_set = &tng_data->current_trajectory_frame_set;
13195
13196 if(stat != TNG_SUCCESS)
13197 {
13198 last_frame = frame_set->first_frame +
13199 frame_set->n_frames - 1;
13200 /* If the wanted frame would be in the frame set after the last
13201 * frame set create a new frame set. */
13202 if(stat == TNG_FAILURE &&
13203 last_frame < frame_nr)
13204 /* (last_frame < frame_nr &&
13205 tng_data->current_trajectory_frame_set.first_frame +
13206 tng_data->frame_set_n_frames >= frame_nr))*/
13207 {
13208 if(last_frame + tng_data->frame_set_n_frames < frame_nr)
13209 {
13210 last_frame = frame_nr - 1;
13211 }
13212 tng_frame_set_new(tng_data,
13213 last_frame+1,
13214 tng_data->frame_set_n_frames);
13215 file_pos = ftello(tng_data->output_file);
13216 fseeko(tng_data->output_file, 0, SEEK_END);
13217 output_file_len = ftello(tng_data->output_file);
13218 fseeko(tng_data->output_file, file_pos, SEEK_SET);
13219
13220 /* Read mapping blocks from the last frame set */
13221 tng_block_init(&block);
13222
13223 stat = tng_block_header_read(tng_data, block);
13224 while(file_pos < output_file_len &&
13225 stat != TNG_CRITICAL &&
13226 block->id != TNG_TRAJECTORY_FRAME_SET &&
13227 block->id != -1)
13228 {
13229 if(block->id == TNG_PARTICLE_MAPPING)
13230 {
13231 tng_trajectory_mapping_block_read(tng_data, block,
13232 hash_mode);
13233 }
13234 else
13235 {
13236 fseeko(tng_data->output_file, block->block_contents_size,
13237 SEEK_CUR);
13238 }
13239 file_pos = ftello(tng_data->output_file);
13240 if(file_pos < output_file_len)
13241 {
13242 stat = tng_block_header_read(tng_data, block);
13243 }
13244 }
13245
13246 tng_block_destroy(&block);
13247 /* Write the frame set to disk */
13248 if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS)
13249 {
13250 fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__);
13251 return(TNG_CRITICAL);
13252 }
13253 }
13254 else
13255 {
13256 tng_data->input_file = temp;
13257 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13258 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13259 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13260 return(stat);
13261 }
13262 }
13263
13264 tng_block_init(&block);
13265
13266 file_pos = tng_data->current_trajectory_frame_set_output_file_pos;
13267
13268 fseeko(tng_data->output_file, 0, SEEK_END);
13269 output_file_len = ftello(tng_data->output_file);
13270 fseeko(tng_data->output_file, file_pos, SEEK_SET);
13271
13272 /* Read past the frame set block first */
13273 stat = tng_block_header_read(tng_data, block);
13274 if(stat == TNG_CRITICAL)
13275 {
13276 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13277 file_pos, __FILE__, __LINE__);
13278 tng_block_destroy(&block);
13279 tng_data->input_file = temp;
13280
13281 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13282 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13283 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13284 return(stat);
13285 }
13286 fseeko(tng_data->output_file, block->block_contents_size,
13287 SEEK_CUR);
13288
13289 if(is_particle_data == TNG_TRUE)
13290 {
13291 if(tng_data->var_num_atoms_flag)
13292 {
13293 tot_n_particles = frame_set->n_particles;
13294 }
13295 else
13296 {
13297 tot_n_particles = tng_data->n_particles;
13298 }
13299
13300 if(val_n_particles < tot_n_particles)
13301 {
13302 mapping_block_end_pos = -1;
13303 /* Read all mapping blocks to find the right place to put the data */
13304 stat = tng_block_header_read(tng_data, block);
13305 while(file_pos < output_file_len &&
13306 stat != TNG_CRITICAL &&
13307 block->id != TNG_TRAJECTORY_FRAME_SET &&
13308 block->id != -1)
13309 {
13310 if(block->id == TNG_PARTICLE_MAPPING)
13311 {
13312 tng_trajectory_mapping_block_read(tng_data, block, hash_mode);
13313 }
13314 else
13315 {
13316 fseeko(tng_data->output_file, block->block_contents_size,
13317 SEEK_CUR);
13318 }
13319 file_pos = ftello(tng_data->output_file);
13320 if(block->id == TNG_PARTICLE_MAPPING)
13321 {
13322 mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1];
13323 if(val_first_particle >= mapping->num_first_particle &&
13324 val_first_particle < mapping->num_first_particle +
13325 mapping->n_particles &&
13326 val_first_particle + val_n_particles <=
13327 mapping->num_first_particle + mapping->n_particles)
13328 {
13329 mapping_block_end_pos = file_pos;
13330 }
13331 }
13332 if(file_pos < output_file_len)
13333 {
13334 stat = tng_block_header_read(tng_data, block);
13335 }
13336 }
13337 if(stat == TNG_CRITICAL)
13338 {
13339 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13340 file_pos, __FILE__, __LINE__);
13341 tng_block_destroy(&block);
13342 tng_data->input_file = temp;
13343
13344 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13345 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13346 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13347 return(stat);
13348 }
13349 if(mapping_block_end_pos < 0)
13350 {
13351 tng_block_destroy(&block);
13352 tng_data->input_file = temp;
13353
13354 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13355 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13356 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13357 return(TNG_FAILURE);
13358 }
13359 fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET);
13360 }
13361 }
13362
13363 /* Read all block headers until next frame set block or
13364 * until the wanted block id is found */
13365 stat = tng_block_header_read(tng_data, block);
13366 while(file_pos < output_file_len &&
13367 stat != TNG_CRITICAL &&
13368 block->id != block_id &&
13369 (is_particle_data != TNG_TRUE || block->id != TNG_PARTICLE_MAPPING) &&
13370 block->id != TNG_TRAJECTORY_FRAME_SET &&
13371 block->id != -1)
13372 {
13373 fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR);
13374 file_pos = ftello(tng_data->output_file);
13375 if(file_pos < output_file_len)
13376 {
13377 stat = tng_block_header_read(tng_data, block);
13378 }
13379 }
13380 if(stat == TNG_CRITICAL)
13381 {
13382 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13383 file_pos, __FILE__, __LINE__);
13384 tng_block_destroy(&block);
13385 tng_data->input_file = temp;
13386 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13387 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13388 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13389 return(stat);
13390 }
13391
13392 contents_size = block->block_contents_size;
13393 header_size = block->header_contents_size;
13394
13395 header_pos = ftello(tng_data->output_file) - header_size;
13396 frame_set = &tng_data->current_trajectory_frame_set;
13397
13398 if(tng_file_input_numerical(tng_data, &datatype,
13399 sizeof(datatype),
13400 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13401 {
13402 tng_block_destroy(&block);
13403 return(TNG_CRITICAL);
13404 }
13405 if(tng_file_input_numerical(tng_data, &dependency,
13406 sizeof(dependency),
13407 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13408 {
13409 tng_block_destroy(&block);
13410 return(TNG_CRITICAL);
13411 }
13412 data.datatype = datatype;
13413
13414 if(!(dependency & TNG_FRAME_DEPENDENT) ||
13415 (is_particle_data == TNG_FALSE && dependency & TNG_PARTICLE_DEPENDENT) ||
13416 (is_particle_data == TNG_TRUE && !(dependency & TNG_PARTICLE_DEPENDENT)))
13417 {
13418 tng_block_destroy(&block);
13419 tng_data->input_file = temp;
13420
13421 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13422 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13423 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13424 return(TNG_FAILURE);
13425 }
13426
13427 if(tng_file_input_numerical(tng_data, &sparse_data,
13428 sizeof(sparse_data),
13429 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13430 {
13431 tng_block_destroy(&block);
13432 return(TNG_CRITICAL);
13433 }
13434
13435 if(tng_file_input_numerical(tng_data, &data.n_values_per_frame,
13436 sizeof(data.n_values_per_frame),
13437 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13438 {
13439 tng_block_destroy(&block);
13440 return(TNG_CRITICAL);
13441 }
13442
13443 if(tng_file_input_numerical(tng_data, &data.codec_id,
13444 sizeof(data.codec_id),
13445 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13446 {
13447 tng_block_destroy(&block);
13448 return(TNG_CRITICAL);
13449 }
13450
13451 if(data.codec_id != TNG_UNCOMPRESSED)
13452 {
13453 if(tng_file_input_numerical(tng_data, &data.compression_multiplier,
13454 sizeof(data.compression_multiplier),
13455 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13456 {
13457 tng_block_destroy(&block);
13458 return(TNG_CRITICAL);
13459 }
13460 }
13461 else
13462 {
13463 data.compression_multiplier = 1;
13464 }
13465
13466 if(sparse_data)
13467 {
13468 if(tng_file_input_numerical(tng_data, &data.first_frame_with_data,
13469 sizeof(data.first_frame_with_data),
13470 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13471 {
13472 tng_block_destroy(&block);
13473 return(TNG_CRITICAL);
13474 }
13475
13476 if(tng_file_input_numerical(tng_data, &data.stride_length,
13477 sizeof(data.stride_length),
13478 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13479 {
13480 tng_block_destroy(&block);
13481 return(TNG_CRITICAL);
13482 }
13483 }
13484 else
13485 {
13486 data.first_frame_with_data = 0;
13487 data.stride_length = 1;
13488 }
13489 data.n_frames = tng_data->current_trajectory_frame_set.n_frames;
13490
13491 if(is_particle_data == TNG_TRUE)
13492 {
13493 if(tng_file_input_numerical(tng_data, &num_first_particle,
13494 sizeof(num_first_particle),
13495 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13496 {
13497 tng_block_destroy(&block);
13498 return(TNG_CRITICAL);
13499 }
13500
13501 if(tng_file_input_numerical(tng_data, &block_n_particles,
13502 sizeof(block_n_particles),
13503 TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL)
13504 {
13505 tng_block_destroy(&block);
13506 return(TNG_CRITICAL);
13507 }
13508 }
13509
13510 tng_data->input_file = temp;
13511
13512 tng_data->first_trajectory_frame_set_input_file_pos = temp_first;
13513 tng_data->last_trajectory_frame_set_input_file_pos = temp_last;
13514 tng_data->current_trajectory_frame_set_input_file_pos = temp_current;
13515
13516 switch(data.datatype)
13517 {
13518 case(TNG_INT_DATA):
13519 size = sizeof(int64_t);
13520 break;
13521 case(TNG_FLOAT_DATA):
13522 size = sizeof(float);
13523 break;
13524 case(TNG_DOUBLE_DATA):
13525 size = sizeof(double);
13526 break;
13527 default:
13528 fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__,
13529 __LINE__);
13530 tng_block_destroy(&block);
13531 return(TNG_FAILURE);
13532 }
13533
13534 n_values_per_frame = data.n_values_per_frame;
13535
13536 file_pos = (frame_nr - tng_max_i64(frame_set->first_frame,
13537 data.first_frame_with_data)) /
13538 data.stride_length;
13539 if(is_particle_data == TNG_TRUE)
13540 {
13541 file_pos *= block_n_particles * size * n_values_per_frame;
13542 }
13543 else
13544 {
13545 file_pos *= size * n_values_per_frame;
13546 }
13547
13548 if(file_pos > contents_size)
13549 {
13550 fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__,
13551 __LINE__);
13552 tng_block_destroy(&block);
13553 return(TNG_FAILURE);
13554 }
13555
13556 fseeko(tng_data->output_file, file_pos, SEEK_CUR);
13557
13558 if(is_particle_data == TNG_TRUE)
13559 {
13560 write_n_particles = val_n_particles;
13561 }
13562 else
13563 {
13564 write_n_particles = 1;
13565 }
13566
13567 /* If the endianness is not big endian the data needs to be swapped */
13568 if((data.datatype == TNG_INT_DATA ||
13569 data.datatype == TNG_DOUBLE_DATA) &&
13570 tng_data->output_endianness_swap_func_64)
13571 {
13572 copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13573 memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13574 for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13575 {
13576 if(tng_data->output_endianness_swap_func_64(tng_data,
13577 (uint64_t *) copy+i)
13578 != TNG_SUCCESS)
13579 {
13580 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13581 __FILE__, __LINE__);
13582 }
13583 }
13584 fwrite(copy, write_n_particles * n_values_per_frame, size,
13585 tng_data->output_file);
13586 free(copy);
13587 }
13588 else if(data.datatype == TNG_FLOAT_DATA &&
13589 tng_data->output_endianness_swap_func_32)
13590 {
13591 copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
13592 memcpy(copy, values, write_n_particles * n_values_per_frame * size);
13593 for(i = 0; i < write_n_particles * n_values_per_frame; i++)
13594 {
13595 if(tng_data->output_endianness_swap_func_32(tng_data,
13596 (uint32_t *) copy+i)
13597 != TNG_SUCCESS)
13598 {
13599 fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
13600 __FILE__, __LINE__);
13601 }
13602 }
13603 fwrite(copy, write_n_particles * n_values_per_frame, size,
13604 tng_data->output_file);
13605 free(copy);
13606 }
13607
13608 else
13609 {
13610 fwrite(values, write_n_particles * n_values_per_frame, size, tng_data->output_file);
13611 }
13612
13613 fflush(tng_data->output_file);
13614
13615 /* Update the number of written frames in the frame set. */
13616 if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames)
13617 {
13618 frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1;
13619 }
13620
13621 /* If the last frame has been written update the hash */
13622 if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length -
13623 data.first_frame_with_data) >=
13624 frame_set->n_frames)
13625 {
13626 tng_md5_hash_update(tng_data, block, header_pos, header_pos +
13627 header_size);
13628 }
13629
13630 tng_block_destroy(&block);
13631
13632 return(TNG_SUCCESS);
13633 }
13634
tng_frame_data_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const int64_t block_id,const void * values,const char hash_mode)13635 tng_function_status DECLSPECDLLEXPORT tng_frame_data_write
13636 (const tng_trajectory_t tng_data,
13637 const int64_t frame_nr,
13638 const int64_t block_id,
13639 const void *values,
13640 const char hash_mode)
13641 {
13642 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13643 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13644 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13645
13646 /* This is now just calling the generic data writing function. This
13647 * function must keep its signature to let the API be backwards
13648 * compatible. */
13649 return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13650 TNG_FALSE, 0, 0, values, hash_mode));
13651 }
13652
tng_frame_particle_data_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const int64_t block_id,const int64_t val_first_particle,const int64_t val_n_particles,const void * values,const char hash_mode)13653 tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write
13654 (const tng_trajectory_t tng_data,
13655 const int64_t frame_nr,
13656 const int64_t block_id,
13657 const int64_t val_first_particle,
13658 const int64_t val_n_particles,
13659 const void *values,
13660 const char hash_mode)
13661 {
13662 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
13663 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
13664 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer.");
13665 TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0.");
13666 TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0.");
13667
13668 /* This is now just calling the generic data writing function. This
13669 * function must keep its signature to let the API be backwards
13670 * compatible. */
13671 return(tng_frame_gen_data_write(tng_data, frame_nr, block_id,
13672 TNG_TRUE, val_first_particle, val_n_particles,
13673 values, hash_mode));
13674 }
13675
tng_data_values_alloc(const tng_trajectory_t tng_data,union data_values *** values,const int64_t n_frames,const int64_t n_values_per_frame,const char type)13676 static tng_function_status tng_data_values_alloc
13677 (const tng_trajectory_t tng_data,
13678 union data_values ***values,
13679 const int64_t n_frames,
13680 const int64_t n_values_per_frame,
13681 const char type)
13682 {
13683 int64_t i;
13684 tng_function_status stat;
13685
13686 if(n_frames <= 0 || n_values_per_frame <= 0)
13687 {
13688 return(TNG_FAILURE);
13689 }
13690
13691 if(*values)
13692 {
13693 stat = tng_data_values_free(tng_data, *values, n_frames,
13694 n_values_per_frame,
13695 type);
13696 if(stat != TNG_SUCCESS)
13697 {
13698 fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13699 __FILE__, __LINE__);
13700 return(stat);
13701 }
13702 }
13703 *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames);
13704 if(!*values)
13705 {
13706 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13707 __FILE__, __LINE__);
13708 return(TNG_CRITICAL);
13709
13710 }
13711
13712 for(i = 0; i < n_frames; i++)
13713 {
13714 (*values)[i] = (union data_values *)malloc(sizeof(union data_values) *
13715 n_values_per_frame);
13716 if(!(*values)[i])
13717 {
13718 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13719 __FILE__, __LINE__);
13720 free(values);
13721 values = 0;
13722 return(TNG_CRITICAL);
13723 }
13724 }
13725 return(TNG_SUCCESS);
13726 }
13727
13728 /* FIXME: This needs ***values */
tng_data_values_free(const tng_trajectory_t tng_data,union data_values ** values,const int64_t n_frames,const int64_t n_values_per_frame,const char type)13729 tng_function_status DECLSPECDLLEXPORT tng_data_values_free
13730 (const tng_trajectory_t tng_data,
13731 union data_values **values,
13732 const int64_t n_frames,
13733 const int64_t n_values_per_frame,
13734 const char type)
13735 {
13736 int64_t i, j;
13737 (void)tng_data;
13738
13739 if(values)
13740 {
13741 for(i = 0; i < n_frames; i++)
13742 {
13743 if(values[i])
13744 {
13745 if(type == TNG_CHAR_DATA)
13746 {
13747 for(j = 0; j < n_values_per_frame; j++)
13748 {
13749 if(values[i][j].c)
13750 {
13751 free(values[i][j].c);
13752 values[i][j].c = 0;
13753 }
13754 }
13755 }
13756 free(values[i]);
13757 values[i] = 0;
13758 }
13759 }
13760 free(values);
13761 values = 0;
13762 }
13763
13764 return(TNG_SUCCESS);
13765 }
13766
tng_particle_data_values_alloc(const tng_trajectory_t tng_data,union data_values **** values,const int64_t n_frames,const int64_t n_particles,const int64_t n_values_per_frame,const char type)13767 static tng_function_status tng_particle_data_values_alloc
13768 (const tng_trajectory_t tng_data,
13769 union data_values ****values,
13770 const int64_t n_frames,
13771 const int64_t n_particles,
13772 const int64_t n_values_per_frame,
13773 const char type)
13774 {
13775 int64_t i, j;
13776 tng_function_status stat;
13777
13778 if(n_particles == 0 || n_values_per_frame == 0)
13779 {
13780 return(TNG_FAILURE);
13781 }
13782
13783 if(*values)
13784 {
13785 stat = tng_particle_data_values_free(tng_data, *values, n_frames,
13786 n_particles, n_values_per_frame,
13787 type);
13788 if(stat != TNG_SUCCESS)
13789 {
13790 fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n",
13791 __FILE__, __LINE__);
13792 return(stat);
13793 }
13794 }
13795 *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames);
13796 if(!*values)
13797 {
13798 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13799 __FILE__, __LINE__);
13800 return(TNG_CRITICAL);
13801
13802 }
13803
13804 for(i = 0; i < n_frames; i++)
13805 {
13806 (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) *
13807 n_particles);
13808 if(!(*values)[i])
13809 {
13810 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13811 __FILE__, __LINE__);
13812 free(*values);
13813 *values = 0;
13814 return(TNG_CRITICAL);
13815 }
13816 for(j = 0; j < n_particles; j++)
13817 {
13818 (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) *
13819 n_values_per_frame);
13820 if(!(*values)[i][j])
13821 {
13822 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
13823 __FILE__, __LINE__);
13824 tng_particle_data_values_free(tng_data, *values, n_frames,
13825 n_particles, n_values_per_frame,
13826 type);
13827 *values = 0;
13828 return(TNG_CRITICAL);
13829 }
13830 }
13831 }
13832 return(TNG_SUCCESS);
13833 }
13834
13835 /* FIXME: This needs ****values */
tng_particle_data_values_free(const tng_trajectory_t tng_data,union data_values *** values,const int64_t n_frames,const int64_t n_particles,const int64_t n_values_per_frame,const char type)13836 tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free
13837 (const tng_trajectory_t tng_data,
13838 union data_values ***values,
13839 const int64_t n_frames,
13840 const int64_t n_particles,
13841 const int64_t n_values_per_frame,
13842 const char type)
13843 {
13844 int64_t i, j, k;
13845 (void)tng_data;
13846
13847 if(values)
13848 {
13849 for(i = 0; i < n_frames; i++)
13850 {
13851 if(values[i])
13852 {
13853 for(j = 0; j < n_particles; j++)
13854 {
13855 if(type == TNG_CHAR_DATA)
13856 {
13857 for(k = 0; k < n_values_per_frame; k++)
13858 {
13859 if(values[i][j][k].c)
13860 {
13861 free(values[i][j][k].c);
13862 values[i][j][k].c = 0;
13863 }
13864 }
13865 }
13866 free(values[i][j]);
13867 values[i][j] = 0;
13868 }
13869 free(values[i]);
13870 values[i] = 0;
13871 }
13872 }
13873 free(values);
13874 values = 0;
13875 }
13876
13877 return(TNG_SUCCESS);
13878 }
13879
tng_gen_data_get(const tng_trajectory_t tng_data,const int64_t block_id,const tng_bool is_particle_data,union data_values **** values,int64_t * n_frames,int64_t * n_particles,int64_t * n_values_per_frame,char * type)13880 static tng_function_status tng_gen_data_get
13881 (const tng_trajectory_t tng_data,
13882 const int64_t block_id,
13883 const tng_bool is_particle_data,
13884 union data_values ****values,
13885 int64_t *n_frames,
13886 int64_t *n_particles,
13887 int64_t *n_values_per_frame,
13888 char *type)
13889 {
13890 int64_t i, j, k, mapping, file_pos, i_step, block_index;
13891 int size;
13892 size_t len;
13893 tng_data_t data;
13894 tng_trajectory_frame_set_t frame_set;
13895 tng_gen_block_t block;
13896 char block_type_flag;
13897 tng_function_status stat;
13898
13899 frame_set = &tng_data->current_trajectory_frame_set;
13900
13901 block_index = -1;
13902 data = 0;
13903
13904 if(is_particle_data == TNG_TRUE)
13905 {
13906 stat = tng_particle_data_find(tng_data, block_id, &data);
13907 }
13908 else
13909 {
13910 stat = tng_data_find(tng_data, block_id, &data);
13911 }
13912
13913 if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
13914 {
13915 block_type_flag = TNG_TRAJECTORY_BLOCK;
13916 }
13917 else
13918 {
13919 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
13920 }
13921
13922 if(stat != TNG_SUCCESS)
13923 {
13924 tng_block_init(&block);
13925 file_pos = ftello(tng_data->input_file);
13926 /* Read all blocks until next frame set block */
13927 stat = tng_block_header_read(tng_data, block);
13928 while(file_pos < tng_data->input_file_len &&
13929 stat != TNG_CRITICAL &&
13930 block->id != TNG_TRAJECTORY_FRAME_SET &&
13931 block->id != -1)
13932 {
13933 /* Use hash by default */
13934 stat = tng_block_read_next(tng_data, block,
13935 TNG_USE_HASH);
13936 if(stat != TNG_CRITICAL)
13937 {
13938 file_pos = ftello(tng_data->input_file);
13939 if(file_pos < tng_data->input_file_len)
13940 {
13941 stat = tng_block_header_read(tng_data, block);
13942 }
13943 }
13944 }
13945 tng_block_destroy(&block);
13946 if(stat == TNG_CRITICAL)
13947 {
13948 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
13949 file_pos, __FILE__, __LINE__);
13950 return(stat);
13951 }
13952
13953 if(is_particle_data == TNG_TRUE)
13954 {
13955 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
13956 {
13957 data = &frame_set->tr_particle_data[i];
13958 if(data->block_id == block_id)
13959 {
13960 block_index = i;
13961 block_type_flag = TNG_TRAJECTORY_BLOCK;
13962 break;
13963 }
13964 }
13965 }
13966 else
13967 {
13968 for(i = 0; i < frame_set->n_data_blocks; i++)
13969 {
13970 data = &frame_set->tr_data[i];
13971 if(data->block_id == block_id)
13972 {
13973 block_index = i;
13974 break;
13975 }
13976 }
13977 }
13978 if(block_index < 0)
13979 {
13980 return(TNG_FAILURE);
13981 }
13982 }
13983
13984 if(is_particle_data == TNG_TRUE)
13985 {
13986 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
13987 tng_data->var_num_atoms_flag)
13988 {
13989 *n_particles = frame_set->n_particles;
13990 }
13991 else
13992 {
13993 *n_particles = tng_data->n_particles;
13994 }
13995 }
13996
13997 *n_frames = tng_max_i64(1, data->n_frames);
13998 *n_values_per_frame = data->n_values_per_frame;
13999 *type = data->datatype;
14000
14001 if(is_particle_data == TNG_TRUE)
14002 {
14003 if(*values == 0)
14004 {
14005 if(tng_particle_data_values_alloc(tng_data, values, *n_frames,
14006 *n_particles, *n_values_per_frame,
14007 *type) != TNG_SUCCESS)
14008 {
14009 return(TNG_CRITICAL);
14010 }
14011 }
14012
14013 i_step = (*n_particles) * (*n_values_per_frame);
14014
14015 /* It's not very elegant to reuse so much of the code in the different case
14016 * statements, but it's unnecessarily slow to have the switch-case block
14017 * inside the for loops. */
14018 switch(*type)
14019 {
14020 case TNG_CHAR_DATA:
14021 for(i = 0; i < *n_frames; i++)
14022 {
14023 for(j = 0; j < *n_particles; j++)
14024 {
14025 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14026 for(k = 0; k < *n_values_per_frame; k++)
14027 {
14028 len = strlen(data->strings[i][j][k]) + 1;
14029 (*values)[i][mapping][k].c = (char *)malloc(len);
14030 strncpy((*values)[i][mapping][k].c,
14031 data->strings[i][j][k], len);
14032 }
14033 }
14034 }
14035 break;
14036 case TNG_INT_DATA:
14037 size = sizeof(int);
14038 for(i = 0; i < *n_frames; i++)
14039 {
14040 for(j = 0; j < *n_particles; j++)
14041 {
14042 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14043 for(k = 0; k < *n_values_per_frame; k++)
14044 {
14045 (*values)[i][mapping][k].i = *(int *)
14046 ((char *)data->values + size *
14047 (i * i_step + j *
14048 (*n_values_per_frame) + k));
14049 }
14050 }
14051 }
14052 break;
14053 case TNG_FLOAT_DATA:
14054 size = sizeof(float);
14055 for(i = 0; i < *n_frames; i++)
14056 {
14057 for(j = 0; j < *n_particles; j++)
14058 {
14059 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14060 for(k = 0; k < *n_values_per_frame; k++)
14061 {
14062 (*values)[i][mapping][k].f = *(float *)
14063 ((char *)data->values + size *
14064 (i * i_step + j *
14065 (*n_values_per_frame) + k));
14066 }
14067 }
14068 }
14069 break;
14070 case TNG_DOUBLE_DATA:
14071 default:
14072 size = sizeof(double);
14073 for(i = 0; i < *n_frames; i++)
14074 {
14075 for(j = 0; j < *n_particles; j++)
14076 {
14077 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14078 for(k = 0; k < *n_values_per_frame; k++)
14079 {
14080 (*values)[i][mapping][k].d = *(double *)
14081 ((char *)data->values + size *
14082 (i * i_step + j *
14083 (*n_values_per_frame) + k));
14084 }
14085 }
14086 }
14087 }
14088 }
14089 else
14090 {
14091 if(*(values[0]) == 0)
14092 {
14093 if(tng_data_values_alloc(tng_data, values[0], *n_frames,
14094 *n_values_per_frame,
14095 *type) != TNG_SUCCESS)
14096 {
14097 return(TNG_CRITICAL);
14098 }
14099 }
14100 switch(*type)
14101 {
14102 case TNG_CHAR_DATA:
14103 for(i = 0; i < *n_frames; i++)
14104 {
14105 for(j = 0; j < *n_values_per_frame; j++)
14106 {
14107 len = strlen(data->strings[0][i][j]) + 1;
14108 (*values)[0][i][j].c = (char *)malloc(len);
14109 strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
14110 }
14111 }
14112 break;
14113 case TNG_INT_DATA:
14114 size = sizeof(int);
14115 for(i = 0; i < *n_frames; i++)
14116 {
14117 for(j = 0; j < *n_values_per_frame; j++)
14118 {
14119 (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14120 (i*(*n_values_per_frame) + j));
14121 }
14122 }
14123 break;
14124 case TNG_FLOAT_DATA:
14125 size = sizeof(float);
14126 for(i = 0; i < *n_frames; i++)
14127 {
14128 for(j = 0; j < *n_values_per_frame; j++)
14129 {
14130 (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14131 (i*(*n_values_per_frame) + j));
14132 }
14133 }
14134 break;
14135 case TNG_DOUBLE_DATA:
14136 default:
14137 size = sizeof(double);
14138 for(i = 0; i < *n_frames; i++)
14139 {
14140 for(j = 0; j < *n_values_per_frame; j++)
14141 {
14142 (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14143 (i*(*n_values_per_frame) + j));
14144 }
14145 }
14146 }
14147 }
14148
14149 data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14150
14151 return(TNG_SUCCESS);
14152 }
14153
tng_data_get(const tng_trajectory_t tng_data,const int64_t block_id,union data_values *** values,int64_t * n_frames,int64_t * n_values_per_frame,char * type)14154 tng_function_status DECLSPECDLLEXPORT tng_data_get
14155 (const tng_trajectory_t tng_data,
14156 const int64_t block_id,
14157 union data_values ***values,
14158 int64_t *n_frames,
14159 int64_t *n_values_per_frame,
14160 char *type)
14161 {
14162 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14163 TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14164 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14165 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14166
14167 return(tng_gen_data_get(tng_data, block_id, TNG_FALSE, &values, n_frames, 0,
14168 n_values_per_frame, type));
14169 }
14170
tng_gen_data_vector_get(const tng_trajectory_t tng_data,const int64_t block_id,const tng_bool is_particle_data,void ** values,int64_t * n_frames,int64_t * stride_length,int64_t * n_particles,int64_t * n_values_per_frame,char * type)14171 static tng_function_status tng_gen_data_vector_get
14172 (const tng_trajectory_t tng_data,
14173 const int64_t block_id,
14174 const tng_bool is_particle_data,
14175 void **values,
14176 int64_t *n_frames,
14177 int64_t *stride_length,
14178 int64_t *n_particles,
14179 int64_t *n_values_per_frame,
14180 char *type)
14181 {
14182 int64_t i, j, mapping, file_pos, i_step, full_data_len, n_frames_div;
14183 int64_t block_index;
14184 int size;
14185 tng_data_t data;
14186 tng_trajectory_frame_set_t frame_set;
14187 tng_gen_block_t block;
14188 void *temp;
14189 char block_type_flag;
14190 tng_function_status stat;
14191
14192 frame_set = &tng_data->current_trajectory_frame_set;
14193
14194 block_index = -1;
14195 data = 0;
14196
14197 if(is_particle_data == TNG_TRUE)
14198 {
14199 stat = tng_particle_data_find(tng_data, block_id, &data);
14200 }
14201 else
14202 {
14203 stat = tng_data_find(tng_data, block_id, &data);
14204 }
14205
14206 if(stat != TNG_SUCCESS)
14207 {
14208 tng_block_init(&block);
14209 file_pos = ftello(tng_data->input_file);
14210 /* Read all blocks until next frame set block */
14211 stat = tng_block_header_read(tng_data, block);
14212 while(file_pos < tng_data->input_file_len &&
14213 stat != TNG_CRITICAL &&
14214 block->id != TNG_TRAJECTORY_FRAME_SET &&
14215 block->id != -1)
14216 {
14217 /* Use hash by default */
14218 stat = tng_block_read_next(tng_data, block,
14219 TNG_USE_HASH);
14220 if(stat != TNG_CRITICAL)
14221 {
14222 file_pos = ftello(tng_data->input_file);
14223 if(file_pos < tng_data->input_file_len)
14224 {
14225 stat = tng_block_header_read(tng_data, block);
14226 }
14227 }
14228 }
14229 tng_block_destroy(&block);
14230 if(stat == TNG_CRITICAL)
14231 {
14232 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14233 file_pos, __FILE__, __LINE__);
14234 return(stat);
14235 }
14236
14237 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
14238 {
14239 data = &frame_set->tr_particle_data[i];
14240 if(data->block_id == block_id)
14241 {
14242 block_index = i;
14243 break;
14244 }
14245 }
14246 if(block_index < 0)
14247 {
14248 return(TNG_FAILURE);
14249 }
14250 }
14251
14252 if(is_particle_data == TNG_TRUE)
14253 {
14254 if(tng_data->current_trajectory_frame_set_input_file_pos > 0)
14255 {
14256 block_type_flag = TNG_TRAJECTORY_BLOCK;
14257 }
14258 else
14259 {
14260 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
14261 }
14262
14263 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14264 tng_data->var_num_atoms_flag)
14265 {
14266 *n_particles = frame_set->n_particles;
14267 }
14268 else
14269 {
14270 *n_particles = tng_data->n_particles;
14271 }
14272 }
14273
14274 *type = data->datatype;
14275
14276 switch(*type)
14277 {
14278 case TNG_CHAR_DATA:
14279 return(TNG_FAILURE);
14280 case TNG_INT_DATA:
14281 size = sizeof(int64_t);
14282 break;
14283 case TNG_FLOAT_DATA:
14284 size = sizeof(float);
14285 break;
14286 case TNG_DOUBLE_DATA:
14287 default:
14288 size = sizeof(double);
14289 }
14290
14291 *n_frames = tng_max_i64(1, data->n_frames);
14292 *n_values_per_frame = data->n_values_per_frame;
14293 *stride_length = data->stride_length;
14294
14295 n_frames_div = (*n_frames % *stride_length) ?
14296 *n_frames / *stride_length + 1:
14297 *n_frames / *stride_length;
14298
14299 full_data_len = n_frames_div * size *
14300 (*n_values_per_frame);
14301 if(is_particle_data == TNG_TRUE)
14302 {
14303 full_data_len *= (*n_particles);
14304 }
14305
14306 temp = (char *)realloc(*values, full_data_len);
14307 if(!temp)
14308 {
14309 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14310 __FILE__, __LINE__);
14311 free(*values);
14312 *values = 0;
14313 return(TNG_CRITICAL);
14314 }
14315
14316 *values = temp;
14317
14318 if(is_particle_data != TNG_TRUE || frame_set->n_mapping_blocks <= 0)
14319 {
14320 memcpy(*values, data->values, full_data_len);
14321 }
14322 else
14323 {
14324 i_step = (*n_particles) * (*n_values_per_frame);
14325 for(i = 0; i < *n_frames; i++)
14326 {
14327 for(j = 0; j < *n_particles; j++)
14328 {
14329 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14330 memcpy(((char *)*values) + size * (i * i_step + mapping *
14331 (*n_values_per_frame)),
14332 (char *)data->values + size *
14333 (i * i_step + j * (*n_values_per_frame)),
14334 size * (*n_values_per_frame));
14335 }
14336 }
14337 }
14338
14339 data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1;
14340
14341 return(TNG_SUCCESS);
14342 }
14343
tng_data_vector_get(const tng_trajectory_t tng_data,const int64_t block_id,void ** values,int64_t * n_frames,int64_t * stride_length,int64_t * n_values_per_frame,char * type)14344 tng_function_status DECLSPECDLLEXPORT tng_data_vector_get
14345 (const tng_trajectory_t tng_data,
14346 const int64_t block_id,
14347 void **values,
14348 int64_t *n_frames,
14349 int64_t *stride_length,
14350 int64_t *n_values_per_frame,
14351 char *type)
14352 {
14353 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14354 TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
14355 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14356 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14357 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14358
14359 return(tng_gen_data_vector_get(tng_data, block_id, TNG_FALSE, values,
14360 n_frames, stride_length, 0, n_values_per_frame,
14361 type));
14362 }
14363
tng_gen_data_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const tng_bool is_particle_data,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,union data_values **** values,int64_t * n_particles,int64_t * n_values_per_frame,char * type)14364 static tng_function_status tng_gen_data_interval_get
14365 (const tng_trajectory_t tng_data,
14366 const int64_t block_id,
14367 const tng_bool is_particle_data,
14368 const int64_t start_frame_nr,
14369 const int64_t end_frame_nr,
14370 const char hash_mode,
14371 union data_values ****values,
14372 int64_t *n_particles,
14373 int64_t *n_values_per_frame,
14374 char *type)
14375 {
14376 int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step;
14377 int64_t first_frame, block_index;
14378 int size;
14379 size_t len;
14380 tng_data_t data;
14381 tng_trajectory_frame_set_t frame_set;
14382 tng_gen_block_t block;
14383 char block_type_flag;
14384 tng_function_status stat;
14385
14386 block_index = -1;
14387
14388 frame_set = &tng_data->current_trajectory_frame_set;
14389 first_frame = frame_set->first_frame;
14390
14391 stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14392 if(stat != TNG_SUCCESS)
14393 {
14394 return(stat);
14395 }
14396
14397 /* Do not re-read the frame set. */
14398 if((is_particle_data == TNG_TRUE &&
14399 (first_frame != frame_set->first_frame ||
14400 frame_set->n_particle_data_blocks <= 0)) ||
14401 (is_particle_data == TNG_FALSE &&
14402 (first_frame != frame_set->first_frame ||
14403 frame_set->n_data_blocks <= 0)))
14404 {
14405 tng_block_init(&block);
14406 file_pos = ftello(tng_data->input_file);
14407 /* Read all blocks until next frame set block */
14408 stat = tng_block_header_read(tng_data, block);
14409 while(file_pos < tng_data->input_file_len &&
14410 stat != TNG_CRITICAL &&
14411 block->id != TNG_TRAJECTORY_FRAME_SET &&
14412 block->id != -1)
14413 {
14414 stat = tng_block_read_next(tng_data, block,
14415 hash_mode);
14416 if(stat != TNG_CRITICAL)
14417 {
14418 file_pos = ftello(tng_data->input_file);
14419 if(file_pos < tng_data->input_file_len)
14420 {
14421 stat = tng_block_header_read(tng_data, block);
14422 }
14423 }
14424 }
14425 tng_block_destroy(&block);
14426 if(stat == TNG_CRITICAL)
14427 {
14428 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14429 file_pos, __FILE__, __LINE__);
14430 return(stat);
14431 }
14432 }
14433
14434 /* See if there is already a data block of this ID.
14435 * Start checking the last read frame set */
14436 if(is_particle_data == TNG_TRUE)
14437 {
14438 for(i = frame_set->n_particle_data_blocks; i-- ;)
14439 {
14440 data = &frame_set->tr_particle_data[i];
14441 if(data->block_id == block_id)
14442 {
14443 block_index = i;
14444 block_type_flag = TNG_TRAJECTORY_BLOCK;
14445 break;
14446 }
14447 }
14448 }
14449 else
14450 {
14451 for(i = 0; i < frame_set->n_data_blocks; i++)
14452 {
14453 data = &frame_set->tr_data[i];
14454 if(data->block_id == block_id)
14455 {
14456 block_index = i;
14457 break;
14458 }
14459 }
14460 }
14461
14462 if(block_index < 0)
14463 {
14464 fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n",
14465 block_id, __FILE__, __LINE__);
14466 return(TNG_FAILURE);
14467 }
14468
14469 if(is_particle_data == TNG_TRUE)
14470 {
14471 if(block_type_flag == TNG_TRAJECTORY_BLOCK &&
14472 tng_data->var_num_atoms_flag)
14473 {
14474 *n_particles = frame_set->n_particles;
14475 }
14476 else
14477 {
14478 *n_particles = tng_data->n_particles;
14479 }
14480 }
14481
14482 n_frames = end_frame_nr - start_frame_nr + 1;
14483 *n_values_per_frame = data->n_values_per_frame;
14484 *type = data->datatype;
14485
14486 if(*values == 0)
14487 {
14488 if(is_particle_data == TNG_TRUE)
14489 {
14490 if(tng_particle_data_values_alloc(tng_data, values, n_frames,
14491 *n_particles, *n_values_per_frame,
14492 *type) != TNG_SUCCESS)
14493 {
14494 return(TNG_CRITICAL);
14495 }
14496 }
14497 else
14498 {
14499 if(tng_data_values_alloc(tng_data, *values, n_frames,
14500 *n_values_per_frame,
14501 *type) != TNG_SUCCESS)
14502 {
14503 return(TNG_CRITICAL);
14504 }
14505 }
14506 }
14507
14508 current_frame_pos = start_frame_nr - frame_set->first_frame;
14509
14510 if(is_particle_data == TNG_TRUE)
14511 {
14512 i_step = (*n_particles) * (*n_values_per_frame);
14513 }
14514 else
14515 {
14516 i_step = (*n_values_per_frame);
14517 }
14518 /* It's not very elegant to reuse so much of the code in the different case
14519 * statements, but it's unnecessarily slow to have the switch-case block
14520 * inside the for loops. */
14521 switch(*type)
14522 {
14523 case TNG_CHAR_DATA:
14524 for(i=0; i<n_frames; i++)
14525 {
14526 if(current_frame_pos == frame_set->n_frames)
14527 {
14528 stat = tng_frame_set_read_next(tng_data, hash_mode);
14529 if(stat != TNG_SUCCESS)
14530 {
14531 return(stat);
14532 }
14533 current_frame_pos = 0;
14534 }
14535 if(is_particle_data == TNG_TRUE)
14536 {
14537 for(j = 0; j < *n_particles; j++)
14538 {
14539 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14540 for(k = 0; k < *n_values_per_frame; k++)
14541 {
14542 len = strlen(data->strings[current_frame_pos][j][k]) + 1;
14543 (*values)[i][mapping][k].c = (char *)malloc(len);
14544 strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
14545 }
14546 }
14547 }
14548 else
14549 {
14550 for(j = 0; j < *n_values_per_frame; j++)
14551 {
14552 len = strlen(data->strings[0][current_frame_pos][j]) + 1;
14553 (*values)[0][i][j].c = (char *)malloc(len);
14554 strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
14555 }
14556 }
14557 current_frame_pos++;
14558 }
14559 break;
14560 case TNG_INT_DATA:
14561 size = sizeof(int);
14562 for(i=0; i<n_frames; i++)
14563 {
14564 if(current_frame_pos == frame_set->n_frames)
14565 {
14566 stat = tng_frame_set_read_next(tng_data, hash_mode);
14567 if(stat != TNG_SUCCESS)
14568 {
14569 return(stat);
14570 }
14571 current_frame_pos = 0;
14572 }
14573 if(is_particle_data == TNG_TRUE)
14574 {
14575 for(j = 0; j < *n_particles; j++)
14576 {
14577 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14578 for(k = 0; k < *n_values_per_frame; k++)
14579 {
14580 (*values)[i][mapping][k].i = *(int *)
14581 ((char *)data->values + size *
14582 (current_frame_pos *
14583 i_step + j *
14584 (*n_values_per_frame) + k));
14585 }
14586 }
14587 current_frame_pos++;
14588 }
14589 else
14590 {
14591 for(j = 0; j < *n_values_per_frame; j++)
14592 {
14593 (*values)[0][i][j].i = *(int *)((char *)data->values + size *
14594 (current_frame_pos *
14595 i_step + j));
14596 }
14597 }
14598 }
14599 break;
14600 case TNG_FLOAT_DATA:
14601 size = sizeof(float);
14602 for(i=0; i<n_frames; i++)
14603 {
14604 if(current_frame_pos == frame_set->n_frames)
14605 {
14606 stat = tng_frame_set_read_next(tng_data, hash_mode);
14607 if(stat != TNG_SUCCESS)
14608 {
14609 return(stat);
14610 }
14611 current_frame_pos = 0;
14612 }
14613 if(is_particle_data == TNG_TRUE)
14614 {
14615 for(j=0; j<*n_particles; j++)
14616 {
14617 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14618 for(k=0; k<*n_values_per_frame; k++)
14619 {
14620 (*values)[i][mapping][k].f = *(float *)
14621 ((char *)data->values + size *
14622 (current_frame_pos *
14623 i_step + j *
14624 (*n_values_per_frame) + k));
14625 }
14626 }
14627 }
14628 else
14629 {
14630 for(j = 0; j < *n_values_per_frame; j++)
14631 {
14632 (*values)[0][i][j].f = *(float *)((char *)data->values + size *
14633 (current_frame_pos *
14634 i_step + j));
14635 }
14636 }
14637 current_frame_pos++;
14638 }
14639 break;
14640 case TNG_DOUBLE_DATA:
14641 default:
14642 size = sizeof(double);
14643 for(i=0; i<n_frames; i++)
14644 {
14645 if(current_frame_pos == frame_set->n_frames)
14646 {
14647 stat = tng_frame_set_read_next(tng_data, hash_mode);
14648 if(stat != TNG_SUCCESS)
14649 {
14650 return(stat);
14651 }
14652 current_frame_pos = 0;
14653 }
14654 if(is_particle_data == TNG_TRUE)
14655 {
14656 for(j=0; j<*n_particles; j++)
14657 {
14658 tng_particle_mapping_get_real_particle(frame_set, j, &mapping);
14659 for(k=0; k<*n_values_per_frame; k++)
14660 {
14661 (*values)[i][mapping][k].d = *(double *)
14662 ((char *)data->values + size *
14663 (current_frame_pos *
14664 i_step + j *
14665 (*n_values_per_frame) + k));
14666 }
14667 }
14668 }
14669 else
14670 {
14671 for(j = 0; j < *n_values_per_frame; j++)
14672 {
14673 (*values)[0][i][j].d = *(double *)((char *)data->values + size *
14674 (current_frame_pos *
14675 i_step + j));
14676 }
14677 }
14678 current_frame_pos++;
14679 }
14680 }
14681
14682 data->last_retrieved_frame = end_frame_nr;
14683
14684 return(TNG_SUCCESS);
14685 }
14686
tng_data_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,union data_values *** values,int64_t * n_values_per_frame,char * type)14687 tng_function_status DECLSPECDLLEXPORT tng_data_interval_get
14688 (const tng_trajectory_t tng_data,
14689 const int64_t block_id,
14690 const int64_t start_frame_nr,
14691 const int64_t end_frame_nr,
14692 const char hash_mode,
14693 union data_values ***values,
14694 int64_t *n_values_per_frame,
14695 char *type)
14696 {
14697 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14698 TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
14699 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14700 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14701
14702 return(tng_gen_data_interval_get(tng_data, block_id, TNG_FALSE, start_frame_nr,
14703 end_frame_nr, hash_mode, &values, 0,
14704 n_values_per_frame, type));
14705 }
14706
tng_gen_data_vector_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const tng_bool is_particle_data,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,void ** values,int64_t * n_particles,int64_t * stride_length,int64_t * n_values_per_frame,char * type)14707 static tng_function_status tng_gen_data_vector_interval_get
14708 (const tng_trajectory_t tng_data,
14709 const int64_t block_id,
14710 const tng_bool is_particle_data,
14711 const int64_t start_frame_nr,
14712 const int64_t end_frame_nr,
14713 const char hash_mode,
14714 void **values,
14715 int64_t *n_particles,
14716 int64_t *stride_length,
14717 int64_t *n_values_per_frame,
14718 char *type)
14719 {
14720 int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame;
14721 int64_t file_pos, current_frame_pos, last_frame_pos, full_data_len, frame_size;
14722 int size;
14723 tng_trajectory_frame_set_t frame_set;
14724 tng_data_t data;
14725 tng_gen_block_t block;
14726 void *current_values = 0, *temp;
14727 tng_function_status stat;
14728
14729 frame_set = &tng_data->current_trajectory_frame_set;
14730 first_frame = frame_set->first_frame;
14731
14732 stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr);
14733 if(stat != TNG_SUCCESS)
14734 {
14735 return(stat);
14736 }
14737
14738 /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */
14739 /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */
14740 if(is_particle_data == TNG_TRUE)
14741 {
14742 stat = tng_particle_data_find(tng_data, block_id, &data);
14743 }
14744 else
14745 {
14746 stat = tng_data_find(tng_data, block_id, &data);
14747 }
14748
14749 if(first_frame != frame_set->first_frame ||
14750 stat != TNG_SUCCESS)
14751 {
14752 tng_block_init(&block);
14753 if(stat != TNG_SUCCESS)
14754 {
14755 fseeko(tng_data->input_file,
14756 tng_data->current_trajectory_frame_set_input_file_pos,
14757 SEEK_SET);
14758 stat = tng_block_header_read(tng_data, block);
14759 if(stat != TNG_SUCCESS)
14760 {
14761 fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n",
14762 __FILE__, __LINE__);
14763 return(stat);
14764 }
14765
14766 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14767 }
14768 file_pos = ftello(tng_data->input_file);
14769 /* Read until next frame set block */
14770 stat = tng_block_header_read(tng_data, block);
14771 while(file_pos < tng_data->input_file_len &&
14772 stat != TNG_CRITICAL &&
14773 block->id != TNG_TRAJECTORY_FRAME_SET &&
14774 block->id != -1)
14775 {
14776 if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING)
14777 {
14778 stat = tng_block_read_next(tng_data, block,
14779 hash_mode);
14780 if(stat != TNG_CRITICAL)
14781 {
14782 file_pos = ftello(tng_data->input_file);
14783 if(file_pos < tng_data->input_file_len)
14784 {
14785 stat = tng_block_header_read(tng_data, block);
14786 }
14787 }
14788 }
14789 else
14790 {
14791 file_pos += block->block_contents_size + block->header_contents_size;
14792 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
14793 if(file_pos < tng_data->input_file_len)
14794 {
14795 stat = tng_block_header_read(tng_data, block);
14796 }
14797 }
14798 }
14799 tng_block_destroy(&block);
14800 if(stat == TNG_CRITICAL)
14801 {
14802 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
14803 file_pos, __FILE__, __LINE__);
14804 return(stat);
14805 }
14806 }
14807 if(is_particle_data == TNG_TRUE)
14808 {
14809 stat = tng_particle_data_find(tng_data, block_id, &data);
14810 }
14811 else
14812 {
14813 stat = tng_data_find(tng_data, block_id, &data);
14814 }
14815 if(stat != TNG_SUCCESS)
14816 {
14817 return(stat);
14818 }
14819
14820 stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14821 ¤t_values, &n_frames, stride_length,
14822 n_particles, n_values_per_frame, type);
14823
14824 if(stat != TNG_SUCCESS || (is_particle_data && *n_particles == 0))
14825 {
14826 if(current_values)
14827 {
14828 free(current_values);
14829 }
14830 return(stat);
14831 }
14832
14833 if(n_frames == 1 && n_frames < frame_set->n_frames)
14834 {
14835 tot_n_frames = 1;
14836 }
14837 else
14838 {
14839 tot_n_frames = end_frame_nr - start_frame_nr + 1;
14840 }
14841
14842 switch(*type)
14843 {
14844 case TNG_CHAR_DATA:
14845 return(TNG_FAILURE);
14846 case TNG_INT_DATA:
14847 size = sizeof(int64_t);
14848 break;
14849 case TNG_FLOAT_DATA:
14850 size = sizeof(float);
14851 break;
14852 case TNG_DOUBLE_DATA:
14853 default:
14854 size = sizeof(double);
14855 }
14856
14857 n_frames_div = (tot_n_frames % *stride_length) ?
14858 tot_n_frames / *stride_length + 1:
14859 tot_n_frames / *stride_length;
14860
14861 full_data_len = n_frames_div * size * (*n_values_per_frame);
14862 if(is_particle_data)
14863 {
14864 full_data_len *= (*n_particles);
14865 }
14866
14867 temp = (char *)realloc(*values, full_data_len);
14868 if(!temp)
14869 {
14870 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
14871 __FILE__, __LINE__);
14872 free(*values);
14873 *values = 0;
14874 return(TNG_CRITICAL);
14875 }
14876
14877 *values = temp;
14878
14879 if( n_frames == 1 && n_frames < frame_set->n_frames)
14880 {
14881 if(is_particle_data)
14882 {
14883 memcpy(*values, current_values, size * (*n_particles) *
14884 (*n_values_per_frame));
14885 }
14886 else
14887 {
14888 memcpy(*values, current_values, size * (*n_values_per_frame));
14889 }
14890 }
14891 else
14892 {
14893 current_frame_pos = start_frame_nr - frame_set->first_frame;
14894
14895 frame_size = size * (*n_values_per_frame);
14896 if(is_particle_data)
14897 {
14898 frame_size *= (*n_particles);
14899 }
14900
14901 last_frame_pos = tng_min_i64(n_frames,
14902 end_frame_nr - start_frame_nr);
14903
14904 n_frames_div = current_frame_pos / *stride_length;
14905 n_frames_div_2 = (last_frame_pos % *stride_length) ?
14906 last_frame_pos / *stride_length + 1:
14907 last_frame_pos / *stride_length;
14908 n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1);
14909
14910 memcpy(*values, (char *)current_values + n_frames_div * frame_size,
14911 n_frames_div_2 * frame_size);
14912
14913 current_frame_pos += n_frames - current_frame_pos;
14914
14915 while(current_frame_pos <= end_frame_nr - start_frame_nr)
14916 {
14917 stat = tng_frame_set_read_next(tng_data, hash_mode);
14918 if(stat != TNG_SUCCESS)
14919 {
14920 if(current_values)
14921 {
14922 free(current_values);
14923 }
14924 free(*values);
14925 *values = 0;
14926 return(stat);
14927 }
14928
14929 stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data,
14930 ¤t_values, &n_frames,
14931 stride_length, n_particles,
14932 n_values_per_frame, type);
14933
14934 if(stat != TNG_SUCCESS)
14935 {
14936 if(current_values)
14937 {
14938 free(current_values);
14939 }
14940 free(*values);
14941 *values = 0;
14942 return(stat);
14943 }
14944
14945 last_frame_pos = tng_min_i64(n_frames,
14946 end_frame_nr - current_frame_pos);
14947
14948 n_frames_div = current_frame_pos / *stride_length;
14949 n_frames_div_2 = (last_frame_pos % *stride_length) ?
14950 last_frame_pos / *stride_length + 1:
14951 last_frame_pos / *stride_length;
14952 n_frames_div_2 = tng_max_i64(1, n_frames_div_2);
14953
14954 memcpy(((char *)*values) + n_frames_div * frame_size,
14955 current_values,
14956 n_frames_div_2 * frame_size);
14957
14958 current_frame_pos += n_frames;
14959 }
14960 }
14961
14962 if(current_values)
14963 {
14964 free(current_values);
14965 }
14966
14967 data->last_retrieved_frame = end_frame_nr;
14968
14969 return(TNG_SUCCESS);
14970 }
14971
14972
tng_data_vector_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,void ** values,int64_t * stride_length,int64_t * n_values_per_frame,char * type)14973 tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get
14974 (const tng_trajectory_t tng_data,
14975 const int64_t block_id,
14976 const int64_t start_frame_nr,
14977 const int64_t end_frame_nr,
14978 const char hash_mode,
14979 void **values,
14980 int64_t *stride_length,
14981 int64_t *n_values_per_frame,
14982 char *type)
14983 {
14984 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
14985 TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr.");
14986 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
14987 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
14988 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
14989
14990 return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_FALSE,
14991 start_frame_nr, end_frame_nr,
14992 hash_mode, values, 0, stride_length,
14993 n_values_per_frame, type));
14994 }
14995
tng_particle_data_get(const tng_trajectory_t tng_data,const int64_t block_id,union data_values **** values,int64_t * n_frames,int64_t * n_particles,int64_t * n_values_per_frame,char * type)14996 tng_function_status DECLSPECDLLEXPORT tng_particle_data_get
14997 (const tng_trajectory_t tng_data,
14998 const int64_t block_id,
14999 union data_values ****values,
15000 int64_t *n_frames,
15001 int64_t *n_particles,
15002 int64_t *n_values_per_frame,
15003 char *type)
15004 {
15005 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15006 TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer.");
15007 TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15008 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15009 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15010
15011 return(tng_gen_data_get(tng_data, block_id, TNG_TRUE, values, n_frames, n_particles,
15012 n_values_per_frame, type));
15013 }
15014
tng_particle_data_vector_get(const tng_trajectory_t tng_data,const int64_t block_id,void ** values,int64_t * n_frames,int64_t * stride_length,int64_t * n_particles,int64_t * n_values_per_frame,char * type)15015 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get
15016 (const tng_trajectory_t tng_data,
15017 const int64_t block_id,
15018 void **values,
15019 int64_t *n_frames,
15020 int64_t *stride_length,
15021 int64_t *n_particles,
15022 int64_t *n_values_per_frame,
15023 char *type)
15024 {
15025 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15026 TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15027 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15028 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15029 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15030
15031 return(tng_gen_data_vector_get(tng_data, block_id, TNG_TRUE, values,
15032 n_frames, stride_length, n_particles,
15033 n_values_per_frame, type));
15034 }
15035
tng_particle_data_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,union data_values **** values,int64_t * n_particles,int64_t * n_values_per_frame,char * type)15036 tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get
15037 (const tng_trajectory_t tng_data,
15038 const int64_t block_id,
15039 const int64_t start_frame_nr,
15040 const int64_t end_frame_nr,
15041 const char hash_mode,
15042 union data_values ****values,
15043 int64_t *n_particles,
15044 int64_t *n_values_per_frame,
15045 char *type)
15046 {
15047 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15048 TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15049 TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15050 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15051 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15052
15053 return(tng_gen_data_interval_get(tng_data, block_id, TNG_TRUE, start_frame_nr,
15054 end_frame_nr, hash_mode, values, n_particles,
15055 n_values_per_frame, type));
15056 }
15057
tng_particle_data_vector_interval_get(const tng_trajectory_t tng_data,const int64_t block_id,const int64_t start_frame_nr,const int64_t end_frame_nr,const char hash_mode,void ** values,int64_t * n_particles,int64_t * stride_length,int64_t * n_values_per_frame,char * type)15058 tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get
15059 (const tng_trajectory_t tng_data,
15060 const int64_t block_id,
15061 const int64_t start_frame_nr,
15062 const int64_t end_frame_nr,
15063 const char hash_mode,
15064 void **values,
15065 int64_t *n_particles,
15066 int64_t *stride_length,
15067 int64_t *n_values_per_frame,
15068 char *type)
15069 {
15070 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15071 TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr.");
15072 TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer.");
15073 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer.");
15074 TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer.");
15075 TNG_ASSERT(type, "TNG library: type must not be a NULL pointer.");
15076
15077 return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_TRUE,
15078 start_frame_nr, end_frame_nr,
15079 hash_mode, values, n_particles,
15080 stride_length, n_values_per_frame,
15081 type));
15082 }
15083
tng_data_get_stride_length(const tng_trajectory_t tng_data,const int64_t block_id,int64_t frame,int64_t * stride_length)15084 tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length
15085 (const tng_trajectory_t tng_data,
15086 const int64_t block_id,
15087 int64_t frame,
15088 int64_t *stride_length)
15089 {
15090 tng_function_status stat;
15091 tng_data_t data;
15092 int64_t orig_file_pos, file_pos;
15093 int is_particle_data;
15094
15095 if(tng_data->current_trajectory_frame_set_input_file_pos <= 0)
15096 {
15097 frame = 0;
15098 }
15099
15100 if(frame >= 0)
15101 {
15102 stat = tng_frame_set_of_frame_find(tng_data, frame);
15103 if(stat != TNG_SUCCESS)
15104 {
15105 return(stat);
15106 }
15107 }
15108 orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
15109 stat = tng_data_find(tng_data, block_id, &data);
15110 if(stat != TNG_SUCCESS)
15111 {
15112 stat = tng_particle_data_find(tng_data, block_id, &data);
15113 if(stat != TNG_SUCCESS)
15114 {
15115 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15116 /* If no specific frame was required read until this data block is found */
15117 if(frame < 0)
15118 {
15119 file_pos = ftello(tng_data->input_file);
15120 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15121 {
15122 stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15123 file_pos = ftello(tng_data->input_file);
15124 }
15125 }
15126 if(stat != TNG_SUCCESS)
15127 {
15128 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15129
15130 return(stat);
15131 }
15132 stat = tng_data_find(tng_data, block_id, &data);
15133 if(stat != TNG_SUCCESS)
15134 {
15135 stat = tng_particle_data_find(tng_data, block_id, &data);
15136 if(stat != TNG_SUCCESS)
15137 {
15138 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15139
15140 return(stat);
15141 }
15142 else
15143 {
15144 is_particle_data = 1;
15145 }
15146 }
15147 else
15148 {
15149 is_particle_data = 0;
15150 }
15151 }
15152 else
15153 {
15154 is_particle_data = 1;
15155 }
15156 }
15157 else
15158 {
15159 is_particle_data = 0;
15160 }
15161 if(is_particle_data)
15162 {
15163 *stride_length = data->stride_length;
15164 }
15165 else
15166 {
15167 *stride_length = data->stride_length;
15168 }
15169 tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos);
15170
15171 return(TNG_SUCCESS);
15172 }
15173
tng_time_get_str(const tng_trajectory_t tng_data,char * time)15174 tng_function_status DECLSPECDLLEXPORT tng_time_get_str
15175 (const tng_trajectory_t tng_data,
15176 char *time)
15177 {
15178 struct tm *time_data;
15179 time_t secs;
15180 int retval;
15181
15182 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15183 TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15184
15185 secs = tng_data->time;
15186
15187 time_data = localtime(&secs); /* Returns a statically allocated variable. */
15188 retval = TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN,
15189 "%4d-%02d-%02d %02d:%02d:%02d",
15190 time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday,
15191 time_data->tm_hour, time_data->tm_min, time_data->tm_sec);
15192
15193 /* handle return value (also) to quiet a -Wformat-truncation warning */
15194 return( (retval < 0) ? TNG_SUCCESS : TNG_FAILURE );
15195 }
15196
15197
tng_util_trajectory_open(const char * filename,const char mode,tng_trajectory_t * tng_data_p)15198 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open
15199 (const char *filename,
15200 const char mode,
15201 tng_trajectory_t *tng_data_p)
15202 {
15203 tng_function_status stat;
15204
15205 TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer.");
15206
15207 if(mode != 'r' && mode != 'w' && mode != 'a')
15208 {
15209 return(TNG_FAILURE);
15210 }
15211
15212 if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS)
15213 {
15214 tng_trajectory_destroy(tng_data_p);
15215 return(TNG_CRITICAL);
15216 }
15217
15218 if(mode == 'w')
15219 {
15220 stat = tng_output_file_set(*tng_data_p, filename);
15221 return(stat);
15222 }
15223 tng_input_file_set(*tng_data_p, filename);
15224
15225 /* Read the file headers */
15226 tng_file_headers_read(*tng_data_p, TNG_USE_HASH);
15227
15228 stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets);
15229
15230 if(stat != TNG_SUCCESS)
15231 {
15232 return(stat);
15233 }
15234
15235 if(mode == 'a')
15236 {
15237 if((*tng_data_p)->output_file)
15238 {
15239 fclose((*tng_data_p)->output_file);
15240 }
15241 (*tng_data_p)->output_file = (*tng_data_p)->input_file;
15242 fseeko((*tng_data_p)->input_file,
15243 (*tng_data_p)->last_trajectory_frame_set_input_file_pos,
15244 SEEK_SET);
15245
15246 stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH);
15247 if(stat != TNG_SUCCESS)
15248 {
15249 fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n",
15250 __FILE__, __LINE__);
15251 }
15252 (*tng_data_p)->output_file = 0;
15253
15254 (*tng_data_p)->first_trajectory_frame_set_output_file_pos =
15255 (*tng_data_p)->first_trajectory_frame_set_input_file_pos;
15256 (*tng_data_p)->last_trajectory_frame_set_output_file_pos =
15257 (*tng_data_p)->last_trajectory_frame_set_input_file_pos;
15258 (*tng_data_p)->current_trajectory_frame_set_output_file_pos =
15259 (*tng_data_p)->current_trajectory_frame_set_input_file_pos;
15260 if((*tng_data_p)->input_file)
15261 {
15262 fclose((*tng_data_p)->input_file);
15263 (*tng_data_p)->input_file = 0;
15264 }
15265 if((*tng_data_p)->input_file_path)
15266 {
15267 free((*tng_data_p)->input_file_path);
15268 (*tng_data_p)->input_file_path = 0;
15269 }
15270 tng_output_append_file_set(*tng_data_p, filename);
15271
15272 fseeko((*tng_data_p)->output_file, 0, SEEK_END);
15273
15274 (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32;
15275 (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64;
15276 }
15277
15278 return(stat);
15279 }
15280
tng_util_trajectory_close(tng_trajectory_t * tng_data_p)15281 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close
15282 (tng_trajectory_t *tng_data_p)
15283 {
15284 tng_trajectory_frame_set_t frame_set;
15285
15286 if(tng_data_p == 0)
15287 {
15288 fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n",
15289 __FILE__, __LINE__);
15290 return(TNG_FAILURE);
15291 }
15292
15293 if(*tng_data_p == 0)
15294 {
15295 return(TNG_SUCCESS);
15296 }
15297
15298 frame_set = &(*tng_data_p)->current_trajectory_frame_set;
15299
15300 if(frame_set->n_unwritten_frames > 0)
15301 {
15302 frame_set->n_frames = frame_set->n_unwritten_frames;
15303 tng_frame_set_write(*tng_data_p, TNG_USE_HASH);
15304 }
15305
15306 return(tng_trajectory_destroy(tng_data_p));
15307 }
15308
tng_util_time_of_frame_get(const tng_trajectory_t tng_data,const int64_t frame_nr,double * time)15309 tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get
15310 (const tng_trajectory_t tng_data,
15311 const int64_t frame_nr,
15312 double *time)
15313 {
15314 int64_t first_frame;
15315 tng_trajectory_frame_set_t frame_set;
15316 tng_function_status stat;
15317
15318 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15319 TNG_ASSERT(time, "TNG library: time must not be a NULL pointer");
15320
15321 stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
15322 if(stat != TNG_SUCCESS)
15323 {
15324 fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n",
15325 frame_nr, __FILE__, __LINE__);
15326 return(stat);
15327 }
15328
15329 frame_set = &tng_data->current_trajectory_frame_set;
15330 first_frame = frame_set->first_frame;
15331
15332 if(tng_data->time_per_frame <= 0)
15333 {
15334 return(TNG_FAILURE);
15335 }
15336
15337 *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame));
15338
15339 return(TNG_SUCCESS);
15340 }
15341
15342 /*
15343 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get
15344 (const tng_trajectory_t tng_data,
15345 int64_t *n_mols,
15346 int64_t **molecule_cnt_list,
15347 tng_molecule_t *mols)
15348 {
15349 tng_trajectory_frame_set_t frame_set;
15350
15351 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15352 TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer.");
15353
15354 *n_mols = tng_data->n_molecules;
15355
15356 frame_set = &tng_data->current_trajectory_frame_set;
15357 if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list)
15358 {
15359 *molecule_cnt_list = frame_set->molecule_cnt_list;
15360 }
15361 else
15362 {
15363 *molecule_cnt_list = tng_data->molecule_cnt_list;
15364 }
15365
15366 *mols = tng_data->molecules;
15367
15368 return(TNG_SUCCESS);
15369 }
15370 */
15371 /*
15372 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add
15373 (const tng_trajectory_t tng_data,
15374 const char *name,
15375 const int64_t cnt,
15376 tng_molecule_t *mol)
15377 {
15378 tng_function_status stat;
15379
15380 TNG_ASSERT(name, "TNG library: name must not be a NULL pointer");
15381 TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0");
15382
15383 stat = tng_molecule_add(tng_data, name, mol);
15384 if(stat != TNG_SUCCESS)
15385 {
15386 return(stat);
15387 }
15388 stat = tng_molecule_cnt_set(tng_data, *mol, cnt);
15389
15390 return(stat);
15391 }
15392 */
tng_util_molecule_particles_get(const tng_trajectory_t tng_data,const tng_molecule_t mol,int64_t * n_particles,char *** names,char *** types,char *** res_names,int64_t ** res_ids,char *** chain_names,int64_t ** chain_ids)15393 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get
15394 (const tng_trajectory_t tng_data,
15395 const tng_molecule_t mol,
15396 int64_t *n_particles,
15397 char ***names,
15398 char ***types,
15399 char ***res_names,
15400 int64_t **res_ids,
15401 char ***chain_names,
15402 int64_t **chain_ids)
15403 {
15404 tng_atom_t atom;
15405 tng_residue_t res;
15406 tng_chain_t chain;
15407 int64_t i;
15408 (void)tng_data;
15409
15410 *n_particles = mol->n_atoms;
15411
15412 *names = (char **)malloc(sizeof(char *) * *n_particles);
15413 *types = (char **)malloc(sizeof(char *) * *n_particles);
15414 *res_names = (char **)malloc(sizeof(char *) * *n_particles);
15415 *chain_names = (char **)malloc(sizeof(char *) * *n_particles);
15416 *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15417 *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
15418
15419 for(i = 0; i < *n_particles; i++)
15420 {
15421 atom = &mol->atoms[i];
15422 res = atom->residue;
15423 chain = res->chain;
15424 (*names)[i] = (char *)malloc(strlen(atom->name));
15425 strcpy(*names[i], atom->name);
15426 (*types)[i] = (char *)malloc(strlen(atom->atom_type));
15427 strcpy(*types[i], atom->atom_type);
15428 (*res_names)[i] = (char *)malloc(strlen(res->name));
15429 strcpy(*res_names[i], res->name);
15430 (*chain_names)[i] = (char *)malloc(strlen(chain->name));
15431 strcpy(*chain_names[i], chain->name);
15432 (*res_ids)[i] = res->id;
15433 (*chain_ids)[i] = chain->id;
15434 }
15435
15436 return(TNG_SUCCESS);
15437 }
15438
tng_util_molecule_particles_set(const tng_trajectory_t tng_data,const tng_molecule_t mol,const int64_t n_particles,const char ** names,const char ** types,const char ** res_names,const int64_t * res_ids,const char ** chain_names,const int64_t * chain_ids)15439 tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set
15440 (const tng_trajectory_t tng_data,
15441 const tng_molecule_t mol,
15442 const int64_t n_particles,
15443 const char **names,
15444 const char **types,
15445 const char **res_names,
15446 const int64_t *res_ids,
15447 const char **chain_names,
15448 const int64_t *chain_ids)
15449 {
15450 int64_t i;
15451 tng_chain_t chain;
15452 tng_residue_t residue;
15453 tng_atom_t atom;
15454 tng_function_status stat;
15455
15456 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15457 TNG_ASSERT(names, "TNG library: names must not be a NULL pointer");
15458 TNG_ASSERT(types, "TNG library: types must not be a NULL pointer");
15459 TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer");
15460 TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer");
15461 TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer");
15462 TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer");
15463
15464 for(i = 0; i < n_particles; i++)
15465 {
15466 if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i],
15467 &chain) == TNG_FAILURE)
15468 {
15469 stat = tng_molecule_chain_add(tng_data, mol, chain_names[i],
15470 &chain);
15471 if(stat != TNG_SUCCESS)
15472 {
15473 return(stat);
15474 }
15475 }
15476 if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i],
15477 &residue) == TNG_FAILURE)
15478 {
15479 stat = tng_chain_residue_add(tng_data, chain, res_names[i],
15480 &residue);
15481 if(stat != TNG_SUCCESS)
15482 {
15483 return(stat);
15484 }
15485 }
15486 stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom);
15487 if(stat != TNG_SUCCESS)
15488 {
15489 return(stat);
15490 }
15491 }
15492 return(TNG_SUCCESS);
15493 }
15494
tng_util_pos_read(const tng_trajectory_t tng_data,float ** positions,int64_t * stride_length)15495 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read
15496 (const tng_trajectory_t tng_data,
15497 float **positions, int64_t *stride_length)
15498 {
15499 int64_t n_frames, n_particles, n_values_per_frame;
15500 char type;
15501 tng_function_status stat;
15502
15503 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15504 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15505 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15506
15507 stat = tng_num_frames_get(tng_data, &n_frames);
15508 if(stat != TNG_SUCCESS)
15509 {
15510 return(stat);
15511 }
15512
15513 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15514 0, n_frames - 1, TNG_USE_HASH,
15515 (void **)positions,
15516 &n_particles,
15517 stride_length,
15518 &n_values_per_frame,
15519 &type);
15520
15521 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15522 {
15523 return(TNG_FAILURE);
15524 }
15525
15526 return(stat);
15527 }
15528
tng_util_vel_read(const tng_trajectory_t tng_data,float ** velocities,int64_t * stride_length)15529 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read
15530 (const tng_trajectory_t tng_data,
15531 float **velocities, int64_t *stride_length)
15532 {
15533 int64_t n_frames, n_particles, n_values_per_frame;
15534 char type;
15535 tng_function_status stat;
15536
15537 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15538 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
15539 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15540
15541 stat = tng_num_frames_get(tng_data, &n_frames);
15542 if(stat != TNG_SUCCESS)
15543 {
15544 return(stat);
15545 }
15546
15547 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
15548 0, n_frames - 1, TNG_USE_HASH,
15549 (void **)velocities,
15550 &n_particles,
15551 stride_length,
15552 &n_values_per_frame,
15553 &type);
15554
15555 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15556 {
15557 return(TNG_FAILURE);
15558 }
15559
15560 return(stat);
15561 }
15562
tng_util_force_read(const tng_trajectory_t tng_data,float ** forces,int64_t * stride_length)15563 tng_function_status DECLSPECDLLEXPORT tng_util_force_read
15564 (const tng_trajectory_t tng_data,
15565 float **forces, int64_t *stride_length)
15566 {
15567 int64_t n_frames, n_particles, n_values_per_frame;
15568 char type;
15569 tng_function_status stat;
15570
15571 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15572 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
15573 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15574
15575 stat = tng_num_frames_get(tng_data, &n_frames);
15576 if(stat != TNG_SUCCESS)
15577 {
15578 return(stat);
15579 }
15580
15581 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
15582 0, n_frames - 1, TNG_USE_HASH,
15583 (void **)forces,
15584 &n_particles,
15585 stride_length,
15586 &n_values_per_frame,
15587 &type);
15588
15589 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15590 {
15591 return(TNG_FAILURE);
15592 }
15593
15594 return(stat);
15595 }
15596
tng_util_box_shape_read(const tng_trajectory_t tng_data,float ** box_shape,int64_t * stride_length)15597 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read
15598 (const tng_trajectory_t tng_data,
15599 float **box_shape,
15600 int64_t *stride_length)
15601 {
15602 int64_t n_frames, n_values_per_frame;
15603 char type;
15604 tng_function_status stat;
15605
15606 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15607 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
15608 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15609
15610 stat = tng_num_frames_get(tng_data, &n_frames);
15611 if(stat != TNG_SUCCESS)
15612 {
15613 return(stat);
15614 }
15615
15616 stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
15617 0, n_frames - 1, TNG_USE_HASH,
15618 (void **)box_shape,
15619 stride_length,
15620 &n_values_per_frame,
15621 &type);
15622
15623 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15624 {
15625 return(TNG_FAILURE);
15626 }
15627
15628 return(stat);
15629 }
15630
tng_util_particle_data_next_frame_read(const tng_trajectory_t tng_data,const int64_t block_id,void ** values,char * data_type,int64_t * retrieved_frame_number,double * retrieved_time)15631 tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read
15632 (const tng_trajectory_t tng_data,
15633 const int64_t block_id,
15634 void **values,
15635 char *data_type,
15636 int64_t *retrieved_frame_number,
15637 double *retrieved_time)
15638 {
15639 tng_trajectory_frame_set_t frame_set;
15640 tng_data_t data = 0;
15641 tng_function_status stat;
15642 int size;
15643 int64_t i, full_data_len, n_particles;
15644 void *temp;
15645 int64_t file_pos;
15646
15647 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15648 TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15649 TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15650 TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15651 TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15652
15653 frame_set = &tng_data->current_trajectory_frame_set;
15654
15655 stat = tng_particle_data_find(tng_data, block_id, &data);
15656 if(stat != TNG_SUCCESS)
15657 {
15658 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15659 file_pos = ftello(tng_data->input_file);
15660 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15661 {
15662 stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15663 file_pos = ftello(tng_data->input_file);
15664 }
15665 if(stat != TNG_SUCCESS)
15666 {
15667 return(stat);
15668 }
15669 stat = tng_particle_data_find(tng_data, block_id, &data);
15670 if(stat != TNG_SUCCESS)
15671 {
15672 return(stat);
15673 }
15674 }
15675 if(data->last_retrieved_frame < 0)
15676 {
15677 fseeko(tng_data->input_file,
15678 tng_data->first_trajectory_frame_set_input_file_pos,
15679 SEEK_SET);
15680 stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15681 if(stat != TNG_SUCCESS)
15682 {
15683 return(stat);
15684 }
15685 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15686 if(stat != TNG_SUCCESS)
15687 {
15688 return(stat);
15689 }
15690
15691 i = data->first_frame_with_data;
15692 }
15693 else
15694 {
15695 if(data->n_frames == 1 && frame_set->n_frames == 1)
15696 {
15697 i = data->last_retrieved_frame + 1;
15698 }
15699 else
15700 {
15701 i = data->last_retrieved_frame + data->stride_length;
15702 }
15703 if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15704 {
15705 stat = tng_frame_set_of_frame_find(tng_data, i);
15706 if(stat != TNG_SUCCESS)
15707 {
15708 /* If the frame set search found the frame set after the starting
15709 * frame set there is a gap in the frame sets. So, even if the frame
15710 * was not found the next frame with data is still in the found
15711 * frame set. */
15712 if(stat == TNG_CRITICAL)
15713 {
15714 return(stat);
15715 }
15716 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15717 {
15718 return(TNG_FAILURE);
15719 }
15720 i = frame_set->first_frame;
15721 }
15722 }
15723 if(data->last_retrieved_frame < frame_set->first_frame)
15724 {
15725 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15726 if(stat != TNG_SUCCESS)
15727 {
15728 return(stat);
15729 }
15730 }
15731 }
15732 data->last_retrieved_frame = i;
15733 *retrieved_frame_number = i;
15734 if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15735 {
15736 *retrieved_time = frame_set->first_frame_time +
15737 (i - frame_set->first_frame) *
15738 tng_data->time_per_frame;
15739 }
15740 else
15741 {
15742 *retrieved_time = 0;
15743 }
15744
15745 if(data->stride_length > 1)
15746 {
15747 i = (i - data->first_frame_with_data) / data->stride_length;
15748 }
15749 else
15750 {
15751 i = (i - frame_set->first_frame);
15752 }
15753
15754 tng_num_particles_get(tng_data, &n_particles);
15755
15756 *data_type = data->datatype;
15757
15758 switch(*data_type)
15759 {
15760 case TNG_CHAR_DATA:
15761 return(TNG_FAILURE);
15762 case TNG_INT_DATA:
15763 size = sizeof(int64_t);
15764 break;
15765 case TNG_FLOAT_DATA:
15766 size = sizeof(float);
15767 break;
15768 case TNG_DOUBLE_DATA:
15769 default:
15770 size = sizeof(double);
15771 }
15772
15773 full_data_len = size * n_particles * data->n_values_per_frame;
15774
15775 // fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n",
15776 // i, full_data_len, size, n_particles, data->n_values_per_frame);
15777
15778 temp = (char *)realloc(*values, full_data_len);
15779 if(!temp)
15780 {
15781 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15782 __FILE__, __LINE__);
15783 free(*values);
15784 *values = 0;
15785 return(TNG_CRITICAL);
15786 }
15787
15788 *values = temp;
15789
15790 memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15791
15792 return(TNG_SUCCESS);
15793 }
15794
tng_util_non_particle_data_next_frame_read(const tng_trajectory_t tng_data,const int64_t block_id,void ** values,char * data_type,int64_t * retrieved_frame_number,double * retrieved_time)15795 tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read
15796 (const tng_trajectory_t tng_data,
15797 const int64_t block_id,
15798 void **values,
15799 char *data_type,
15800 int64_t *retrieved_frame_number,
15801 double *retrieved_time)
15802 {
15803 tng_trajectory_frame_set_t frame_set;
15804 tng_data_t data = 0;
15805 tng_function_status stat;
15806 int size;
15807 int64_t i, full_data_len;
15808 void *temp;
15809 int64_t file_pos;
15810
15811 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15812 TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer");
15813 TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer");
15814 TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer");
15815 TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer");
15816
15817 frame_set = &tng_data->current_trajectory_frame_set;
15818
15819 stat = tng_data_find(tng_data, block_id, &data);
15820 if(stat != TNG_SUCCESS)
15821 {
15822 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15823 file_pos = ftello(tng_data->input_file);
15824 while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len)
15825 {
15826 stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15827 file_pos = ftello(tng_data->input_file);
15828 }
15829 if(stat != TNG_SUCCESS)
15830 {
15831 return(stat);
15832 }
15833 stat = tng_data_find(tng_data, block_id, &data);
15834 if(stat != TNG_SUCCESS)
15835 {
15836 return(stat);
15837 }
15838 }
15839 if(data->last_retrieved_frame < 0)
15840 {
15841 fseeko(tng_data->input_file,
15842 tng_data->first_trajectory_frame_set_input_file_pos,
15843 SEEK_SET);
15844 stat = tng_frame_set_read(tng_data, TNG_USE_HASH);
15845 if(stat != TNG_SUCCESS)
15846 {
15847 return(stat);
15848 }
15849 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15850 if(stat != TNG_SUCCESS)
15851 {
15852 return(stat);
15853 }
15854
15855 i = data->first_frame_with_data;
15856 }
15857 else
15858 {
15859 if(data->n_frames == 1 && frame_set->n_frames == 1)
15860 {
15861 i = data->last_retrieved_frame + 1;
15862 }
15863 else
15864 {
15865 i = data->last_retrieved_frame + data->stride_length;
15866 }
15867 if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
15868 {
15869 stat = tng_frame_set_of_frame_find(tng_data, i);
15870 if(stat != TNG_SUCCESS)
15871 {
15872 /* If the frame set search found the frame set after the starting
15873 * frame set there is a gap in the frame sets. So, even if the frame
15874 * was not found the next frame with data is still in the found
15875 * frame set. */
15876 if(stat == TNG_CRITICAL)
15877 {
15878 return(stat);
15879 }
15880 if(frame_set->first_frame + frame_set->n_frames - 1 < i)
15881 {
15882 return(TNG_FAILURE);
15883 }
15884 i = frame_set->first_frame;
15885 }
15886 }
15887 if(data->last_retrieved_frame < frame_set->first_frame)
15888 {
15889 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
15890 if(stat != TNG_SUCCESS)
15891 {
15892 return(stat);
15893 }
15894 }
15895 }
15896 data->last_retrieved_frame = i;
15897 *retrieved_frame_number = i;
15898 if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0)
15899 {
15900 *retrieved_time = frame_set->first_frame_time +
15901 (i - frame_set->first_frame) *
15902 tng_data->time_per_frame;
15903 }
15904 else
15905 {
15906 *retrieved_time = 0;
15907 }
15908
15909 if(data->stride_length > 1)
15910 {
15911 i = (i - data->first_frame_with_data) / data->stride_length;
15912 }
15913 else
15914 {
15915 i = (i - frame_set->first_frame);
15916 }
15917
15918 *data_type = data->datatype;
15919
15920 switch(*data_type)
15921 {
15922 case TNG_CHAR_DATA:
15923 return(TNG_FAILURE);
15924 case TNG_INT_DATA:
15925 size = sizeof(int64_t);
15926 break;
15927 case TNG_FLOAT_DATA:
15928 size = sizeof(float);
15929 break;
15930 case TNG_DOUBLE_DATA:
15931 default:
15932 size = sizeof(double);
15933 }
15934
15935 full_data_len = size * data->n_values_per_frame;
15936
15937 temp = (char *)realloc(*values, full_data_len);
15938 if(!temp)
15939 {
15940 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
15941 __FILE__, __LINE__);
15942 free(*values);
15943 *values = 0;
15944 return(TNG_CRITICAL);
15945 }
15946
15947 *values = temp;
15948
15949 memcpy(*values, (char *)data->values + i * full_data_len, full_data_len);
15950
15951 return(TNG_SUCCESS);
15952 }
15953
tng_util_pos_read_range(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t last_frame,float ** positions,int64_t * stride_length)15954 tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range
15955 (const tng_trajectory_t tng_data,
15956 const int64_t first_frame,
15957 const int64_t last_frame,
15958 float **positions,
15959 int64_t *stride_length)
15960 {
15961 int64_t n_particles, n_values_per_frame;
15962 char type;
15963 tng_function_status stat;
15964
15965 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15966 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
15967 TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
15968 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
15969
15970 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS,
15971 first_frame, last_frame,
15972 TNG_USE_HASH,
15973 (void **)positions,
15974 &n_particles,
15975 stride_length,
15976 &n_values_per_frame,
15977 &type);
15978
15979 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
15980 {
15981 return(TNG_FAILURE);
15982 }
15983
15984 return(stat);
15985 }
15986
tng_util_vel_read_range(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t last_frame,float ** velocities,int64_t * stride_length)15987 tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range
15988 (const tng_trajectory_t tng_data,
15989 const int64_t first_frame,
15990 const int64_t last_frame,
15991 float **velocities,
15992 int64_t *stride_length)
15993 {
15994 int64_t n_particles, n_values_per_frame;
15995 char type;
15996 tng_function_status stat;
15997
15998 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
15999 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
16000 TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16001 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16002
16003 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES,
16004 first_frame, last_frame,
16005 TNG_USE_HASH,
16006 (void **)velocities,
16007 &n_particles,
16008 stride_length,
16009 &n_values_per_frame,
16010 &type);
16011
16012 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16013 {
16014 return(TNG_FAILURE);
16015 }
16016
16017 return(stat);
16018 }
16019
tng_util_force_read_range(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t last_frame,float ** forces,int64_t * stride_length)16020 tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range
16021 (const tng_trajectory_t tng_data,
16022 const int64_t first_frame,
16023 const int64_t last_frame,
16024 float **forces,
16025 int64_t *stride_length)
16026 {
16027 int64_t n_particles, n_values_per_frame;
16028 char type;
16029 tng_function_status stat;
16030
16031 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16032 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
16033 TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16034 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16035
16036 stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES,
16037 first_frame, last_frame,
16038 TNG_USE_HASH,
16039 (void **)forces,
16040 &n_particles,
16041 stride_length,
16042 &n_values_per_frame,
16043 &type);
16044
16045 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16046 {
16047 return(TNG_FAILURE);
16048 }
16049
16050 return(stat);
16051 }
16052
tng_util_box_shape_read_range(const tng_trajectory_t tng_data,const int64_t first_frame,const int64_t last_frame,float ** box_shape,int64_t * stride_length)16053 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range
16054 (const tng_trajectory_t tng_data,
16055 const int64_t first_frame,
16056 const int64_t last_frame,
16057 float **box_shape,
16058 int64_t *stride_length)
16059 {
16060 int64_t n_values_per_frame;
16061 char type;
16062 tng_function_status stat;
16063
16064 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16065 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
16066 TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame.");
16067 TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer");
16068
16069 stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE,
16070 first_frame, last_frame,
16071 TNG_USE_HASH,
16072 (void **)box_shape,
16073 stride_length,
16074 &n_values_per_frame,
16075 &type);
16076
16077 if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
16078 {
16079 return(TNG_FAILURE);
16080 }
16081
16082 return(stat);
16083 }
16084
tng_util_generic_write_interval_set(const tng_trajectory_t tng_data,const int64_t i,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)16085 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set
16086 (const tng_trajectory_t tng_data,
16087 const int64_t i,
16088 const int64_t n_values_per_frame,
16089 const int64_t block_id,
16090 const char *block_name,
16091 const char particle_dependency,
16092 const char compression)
16093 {
16094 tng_trajectory_frame_set_t frame_set;
16095 tng_data_t data;
16096 int64_t n_particles, n_frames;
16097 tng_function_status stat;
16098
16099 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16100 TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16101
16102 if(i <= 0)
16103 {
16104 fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16105 i, __FILE__, __LINE__);
16106 return(TNG_FAILURE);
16107 }
16108
16109 frame_set = &tng_data->current_trajectory_frame_set;
16110
16111 if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16112 {
16113 n_frames = tng_data->frame_set_n_frames;
16114
16115 stat = tng_frame_set_new(tng_data, 0, n_frames);
16116 if(stat != TNG_SUCCESS)
16117 {
16118 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16119 __LINE__);
16120 return(stat);
16121 }
16122 }
16123 else
16124 {
16125 n_frames = frame_set->n_frames;
16126 }
16127
16128 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16129 {
16130 tng_num_particles_get(tng_data, &n_particles);
16131 if(n_particles <= 0)
16132 {
16133 return(TNG_FAILURE);
16134 }
16135
16136 if(tng_particle_data_find(tng_data, block_id, &data)
16137 != TNG_SUCCESS)
16138 {
16139 stat = tng_particle_data_block_add(tng_data, block_id,
16140 block_name,
16141 TNG_FLOAT_DATA,
16142 TNG_TRAJECTORY_BLOCK,
16143 n_frames, n_values_per_frame, i,
16144 0, n_particles,
16145 compression, 0);
16146 if(stat != TNG_SUCCESS)
16147 {
16148 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16149 __FILE__, __LINE__);
16150 return(stat);
16151 }
16152 data = &frame_set->tr_particle_data[frame_set->
16153 n_particle_data_blocks - 1];
16154 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16155 i, n_particles,
16156 n_values_per_frame);
16157 if(stat != TNG_SUCCESS)
16158 {
16159 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16160 __FILE__, __LINE__);
16161 return(stat);
16162 }
16163 }
16164 else
16165 {
16166 if(data->stride_length != i)
16167 {
16168 data->stride_length = i;
16169 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16170 i, n_particles,
16171 n_values_per_frame);
16172 if(stat != TNG_SUCCESS)
16173 {
16174 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16175 __FILE__, __LINE__);
16176 return(stat);
16177 }
16178 }
16179 }
16180 }
16181 else
16182 {
16183 if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16184 {
16185 stat = tng_data_block_add(tng_data, block_id, block_name,
16186 TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK,
16187 n_frames, n_values_per_frame,
16188 i, compression, 0);
16189 if(stat != TNG_SUCCESS)
16190 {
16191 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16192 __FILE__, __LINE__);
16193 return(stat);
16194 }
16195 data = &frame_set->tr_data[frame_set->
16196 n_data_blocks - 1];
16197 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16198 i, n_values_per_frame);
16199 if(stat != TNG_SUCCESS)
16200 {
16201 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16202 __FILE__, __LINE__);
16203 return(stat);
16204 }
16205 }
16206 else
16207 {
16208 if(data->stride_length != i)
16209 {
16210 data->stride_length = i;
16211 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16212 i, n_values_per_frame);
16213 if(stat != TNG_SUCCESS)
16214 {
16215 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16216 __FILE__, __LINE__);
16217 return(stat);
16218 }
16219 }
16220 }
16221 }
16222
16223 return(TNG_SUCCESS);
16224 }
16225
tng_util_generic_write_interval_double_set(const tng_trajectory_t tng_data,const int64_t i,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)16226 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set
16227 (const tng_trajectory_t tng_data,
16228 const int64_t i,
16229 const int64_t n_values_per_frame,
16230 const int64_t block_id,
16231 const char *block_name,
16232 const char particle_dependency,
16233 const char compression)
16234 {
16235 tng_trajectory_frame_set_t frame_set;
16236 tng_data_t data;
16237 int64_t n_particles, n_frames;
16238 tng_function_status stat;
16239
16240 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16241 TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0.");
16242
16243 if(i <= 0)
16244 {
16245 fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
16246 i, __FILE__, __LINE__);
16247 return(TNG_FAILURE);
16248 }
16249
16250 frame_set = &tng_data->current_trajectory_frame_set;
16251
16252 if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16253 {
16254 n_frames = tng_data->frame_set_n_frames;
16255
16256 stat = tng_frame_set_new(tng_data, 0, n_frames);
16257 if(stat != TNG_SUCCESS)
16258 {
16259 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16260 __LINE__);
16261 return(stat);
16262 }
16263 }
16264 else
16265 {
16266 n_frames = frame_set->n_frames;
16267 }
16268
16269 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16270 {
16271 tng_num_particles_get(tng_data, &n_particles);
16272
16273 if(n_particles <= 0)
16274 {
16275 return(TNG_FAILURE);
16276 }
16277
16278 if(tng_particle_data_find(tng_data, block_id, &data)
16279 != TNG_SUCCESS)
16280 {
16281 stat = tng_particle_data_block_add(tng_data, block_id,
16282 block_name,
16283 TNG_DOUBLE_DATA,
16284 TNG_TRAJECTORY_BLOCK,
16285 n_frames, n_values_per_frame, i,
16286 0, n_particles,
16287 compression, 0);
16288 if(stat != TNG_SUCCESS)
16289 {
16290 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16291 __FILE__, __LINE__);
16292 return(stat);
16293 }
16294 data = &frame_set->tr_particle_data[frame_set->
16295 n_particle_data_blocks - 1];
16296 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16297 i, n_particles,
16298 n_values_per_frame);
16299 if(stat != TNG_SUCCESS)
16300 {
16301 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16302 __FILE__, __LINE__);
16303 return(stat);
16304 }
16305 }
16306 else
16307 {
16308 data->stride_length = i;
16309 }
16310 }
16311 else
16312 {
16313 if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16314 {
16315 stat = tng_data_block_add(tng_data, block_id, block_name,
16316 TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
16317 n_frames, n_values_per_frame,
16318 i, compression, 0);
16319 if(stat != TNG_SUCCESS)
16320 {
16321 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16322 __FILE__, __LINE__);
16323 return(stat);
16324 }
16325 data = &frame_set->tr_data[frame_set->
16326 n_data_blocks - 1];
16327 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16328 i, n_values_per_frame);
16329 if(stat != TNG_SUCCESS)
16330 {
16331 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16332 __FILE__, __LINE__);
16333 return(stat);
16334 }
16335 }
16336 else
16337 {
16338 data->stride_length = i;
16339 }
16340 }
16341
16342 return(TNG_SUCCESS);
16343 }
16344
tng_util_generic_write_frequency_set(const tng_trajectory_t tng_data,const int64_t i,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)16345 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set
16346 (const tng_trajectory_t tng_data,
16347 const int64_t i,
16348 const int64_t n_values_per_frame,
16349 const int64_t block_id,
16350 const char *block_name,
16351 const char particle_dependency,
16352 const char compression)
16353 {
16354 fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). "
16355 "See documentation. %s: %d", __FILE__, __LINE__);
16356 return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame,
16357 block_id, block_name,
16358 particle_dependency,
16359 compression));
16360 }
tng_util_pos_write_interval_set(const tng_trajectory_t tng_data,const int64_t i)16361 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set
16362 (const tng_trajectory_t tng_data,
16363 const int64_t i)
16364 {
16365 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16366 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16367
16368 return(tng_util_generic_write_interval_set(tng_data, i, 3,
16369 TNG_TRAJ_POSITIONS,
16370 "POSITIONS",
16371 TNG_PARTICLE_BLOCK_DATA,
16372 TNG_TNG_COMPRESSION));
16373 }
16374
tng_util_pos_write_interval_double_set(const tng_trajectory_t tng_data,const int64_t i)16375 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set
16376 (const tng_trajectory_t tng_data,
16377 const int64_t i)
16378 {
16379 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16380 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16381
16382 return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16383 TNG_TRAJ_POSITIONS,
16384 "POSITIONS",
16385 TNG_PARTICLE_BLOCK_DATA,
16386 TNG_TNG_COMPRESSION));
16387 }
16388
tng_util_pos_write_frequency_set(const tng_trajectory_t tng_data,const int64_t i)16389 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set
16390 (const tng_trajectory_t tng_data,
16391 const int64_t i)
16392 {
16393 fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). "
16394 "See documentation. %s: %d", __FILE__, __LINE__);
16395 return(tng_util_pos_write_interval_set(tng_data, i));
16396 }
16397
tng_util_vel_write_interval_set(const tng_trajectory_t tng_data,const int64_t i)16398 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set
16399 (const tng_trajectory_t tng_data,
16400 const int64_t i)
16401 {
16402 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16403 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16404
16405 return(tng_util_generic_write_interval_set(tng_data, i, 3,
16406 TNG_TRAJ_VELOCITIES,
16407 "VELOCITIES",
16408 TNG_PARTICLE_BLOCK_DATA,
16409 TNG_TNG_COMPRESSION));
16410 }
16411
tng_util_vel_write_interval_double_set(const tng_trajectory_t tng_data,const int64_t i)16412 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set
16413 (const tng_trajectory_t tng_data,
16414 const int64_t i)
16415 {
16416 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16417 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16418
16419 return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16420 TNG_TRAJ_VELOCITIES,
16421 "VELOCITIES",
16422 TNG_PARTICLE_BLOCK_DATA,
16423 TNG_TNG_COMPRESSION));
16424 }
16425
tng_util_vel_write_frequency_set(const tng_trajectory_t tng_data,const int64_t i)16426 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set
16427 (const tng_trajectory_t tng_data,
16428 const int64_t i)
16429 {
16430 fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). "
16431 "See documentation. %s: %d", __FILE__, __LINE__);
16432 return(tng_util_vel_write_interval_set(tng_data, i));
16433 }
16434
tng_util_force_write_interval_set(const tng_trajectory_t tng_data,const int64_t i)16435 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set
16436 (const tng_trajectory_t tng_data,
16437 const int64_t i)
16438 {
16439 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16440 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16441
16442 return(tng_util_generic_write_interval_set(tng_data, i, 3,
16443 TNG_TRAJ_FORCES,
16444 "FORCES",
16445 TNG_PARTICLE_BLOCK_DATA,
16446 TNG_GZIP_COMPRESSION));
16447 }
16448
tng_util_force_write_interval_double_set(const tng_trajectory_t tng_data,const int64_t i)16449 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set
16450 (const tng_trajectory_t tng_data,
16451 const int64_t i)
16452 {
16453 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16454 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16455
16456 return(tng_util_generic_write_interval_double_set(tng_data, i, 3,
16457 TNG_TRAJ_FORCES,
16458 "FORCES",
16459 TNG_PARTICLE_BLOCK_DATA,
16460 TNG_GZIP_COMPRESSION));
16461 }
16462
tng_util_force_write_frequency_set(const tng_trajectory_t tng_data,const int64_t i)16463 tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set
16464 (const tng_trajectory_t tng_data,
16465 const int64_t i)
16466 {
16467 fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). "
16468 "See documentation. %s: %d", __FILE__, __LINE__);
16469 return(tng_util_force_write_interval_set(tng_data, i));
16470 }
16471
tng_util_box_shape_write_interval_set(const tng_trajectory_t tng_data,const int64_t i)16472 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set
16473 (const tng_trajectory_t tng_data,
16474 const int64_t i)
16475 {
16476 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16477 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16478
16479 return(tng_util_generic_write_interval_set(tng_data, i, 9,
16480 TNG_TRAJ_BOX_SHAPE,
16481 "BOX SHAPE",
16482 TNG_NON_PARTICLE_BLOCK_DATA,
16483 TNG_GZIP_COMPRESSION));
16484 }
16485
tng_util_box_shape_write_interval_double_set(const tng_trajectory_t tng_data,const int64_t i)16486 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set
16487 (const tng_trajectory_t tng_data,
16488 const int64_t i)
16489 {
16490 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16491 TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0.");
16492
16493 return(tng_util_generic_write_interval_double_set(tng_data, i, 9,
16494 TNG_TRAJ_BOX_SHAPE,
16495 "BOX SHAPE",
16496 TNG_NON_PARTICLE_BLOCK_DATA,
16497 TNG_GZIP_COMPRESSION));
16498 }
16499
tng_util_box_shape_write_frequency_set(const tng_trajectory_t tng_data,const int64_t i)16500 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set
16501 (const tng_trajectory_t tng_data,
16502 const int64_t i)
16503 {
16504 fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). "
16505 "See documentation. %s: %d", __FILE__, __LINE__);
16506 return(tng_util_box_shape_write_interval_set(tng_data, i));
16507 }
16508
tng_util_generic_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const float * values,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)16509 tng_function_status DECLSPECDLLEXPORT tng_util_generic_write
16510 (const tng_trajectory_t tng_data,
16511 const int64_t frame_nr,
16512 const float *values,
16513 const int64_t n_values_per_frame,
16514 const int64_t block_id,
16515 const char *block_name,
16516 const char particle_dependency,
16517 const char compression)
16518 {
16519 tng_trajectory_frame_set_t frame_set;
16520 tng_data_t data;
16521 int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16522 int64_t last_frame;
16523 int is_first_frame_flag = 0;
16524 char block_type_flag;
16525 tng_function_status stat;
16526
16527 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16528 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16529
16530 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16531 {
16532 tng_num_particles_get(tng_data, &n_particles);
16533 TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16534 }
16535
16536 if(values == 0)
16537 {
16538 return(TNG_FAILURE);
16539 }
16540
16541 frame_set = &tng_data->current_trajectory_frame_set;
16542
16543 if(frame_nr < 0)
16544 {
16545 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16546 n_frames = stride_length = 1;
16547 }
16548 else
16549 {
16550 block_type_flag = TNG_TRAJECTORY_BLOCK;
16551
16552 if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16553 {
16554 stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16555 if(stat != TNG_SUCCESS)
16556 {
16557 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16558 __LINE__);
16559 return(stat);
16560 }
16561 }
16562 last_frame = frame_set->first_frame +
16563 frame_set->n_frames - 1;
16564 if(frame_nr > last_frame)
16565 {
16566 stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16567 if(stat != TNG_SUCCESS)
16568 {
16569 fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__,
16570 __LINE__);
16571 return(stat);
16572 }
16573 if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16574 {
16575 last_frame = frame_nr - 1;
16576 }
16577 stat = tng_frame_set_new(tng_data, last_frame + 1,
16578 tng_data->frame_set_n_frames);
16579 if(stat != TNG_SUCCESS)
16580 {
16581 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16582 __LINE__);
16583 return(stat);
16584 }
16585 }
16586 if(frame_set->n_unwritten_frames == 0)
16587 {
16588 is_first_frame_flag = 1;
16589 }
16590 frame_set->n_unwritten_frames = frame_nr -
16591 frame_set->first_frame + 1;
16592
16593 n_frames = frame_set->n_frames;
16594 }
16595
16596 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16597 {
16598 if(tng_particle_data_find(tng_data, block_id, &data)
16599 != TNG_SUCCESS)
16600 {
16601 stat = tng_particle_data_block_add(tng_data, block_id,
16602 block_name,
16603 TNG_FLOAT_DATA,
16604 block_type_flag,
16605 n_frames, n_values_per_frame,
16606 stride_length,
16607 0, n_particles,
16608 compression, 0);
16609 if(stat != TNG_SUCCESS)
16610 {
16611 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16612 __FILE__, __LINE__);
16613 return(stat);
16614 }
16615 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16616 {
16617 data = &frame_set->tr_particle_data[frame_set->
16618 n_particle_data_blocks - 1];
16619 }
16620 else
16621 {
16622 data = &tng_data->non_tr_particle_data[tng_data->
16623 n_particle_data_blocks - 1];
16624 }
16625 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16626 stride_length, n_particles,
16627 n_values_per_frame);
16628 if(stat != TNG_SUCCESS)
16629 {
16630 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16631 __FILE__, __LINE__);
16632 return(stat);
16633 }
16634 }
16635 /* FIXME: Here we must be able to handle modified n_particles as well. */
16636 else if(n_frames > data->n_frames)
16637 {
16638 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16639 data->stride_length, n_particles,
16640 n_values_per_frame);
16641 if(stat != TNG_SUCCESS)
16642 {
16643 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16644 __FILE__, __LINE__);
16645 return(stat);
16646 }
16647 }
16648
16649 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16650 {
16651 stride_length = data->stride_length;
16652
16653 if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16654 {
16655 data->first_frame_with_data = frame_nr;
16656 frame_pos = 0;
16657 }
16658 else
16659 {
16660 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16661 }
16662
16663 memcpy((char *)data->values + sizeof(float) * frame_pos * n_particles *
16664 n_values_per_frame, values, sizeof(float) *
16665 n_particles * n_values_per_frame);
16666 }
16667 else
16668 {
16669 memcpy(data->values, values, sizeof(float) * n_particles *
16670 n_values_per_frame);
16671 }
16672 }
16673 else
16674 {
16675 if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16676 {
16677 stat = tng_data_block_add(tng_data, block_id, block_name,
16678 TNG_FLOAT_DATA, block_type_flag,
16679 n_frames, n_values_per_frame,
16680 stride_length, compression, 0);
16681 if(stat != TNG_SUCCESS)
16682 {
16683 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16684 __FILE__, __LINE__);
16685 return(stat);
16686 }
16687 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16688 {
16689 data = &frame_set->tr_data[frame_set->
16690 n_data_blocks - 1];
16691 }
16692 else
16693 {
16694 data = &tng_data->non_tr_data[tng_data->
16695 n_data_blocks - 1];
16696 }
16697 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16698 stride_length, n_values_per_frame);
16699 if(stat != TNG_SUCCESS)
16700 {
16701 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16702 __FILE__, __LINE__);
16703 return(stat);
16704 }
16705 }
16706 /* FIXME: Here we must be able to handle modified n_particles as well. */
16707 else if(n_frames > data->n_frames)
16708 {
16709 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16710 data->stride_length, n_values_per_frame);
16711 if(stat != TNG_SUCCESS)
16712 {
16713 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16714 __FILE__, __LINE__);
16715 return(stat);
16716 }
16717 }
16718
16719 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16720 {
16721 stride_length = data->stride_length;
16722
16723 if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16724 {
16725 data->first_frame_with_data = frame_nr;
16726 frame_pos = 0;
16727 }
16728 else
16729 {
16730 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16731 }
16732
16733 memcpy((char *)data->values + sizeof(float) * frame_pos *
16734 n_values_per_frame, values, sizeof(float) *
16735 n_values_per_frame);
16736 }
16737 else
16738 {
16739 memcpy(data->values, values, sizeof(float) * n_values_per_frame);
16740 }
16741 }
16742
16743 return(TNG_SUCCESS);
16744 }
16745
tng_util_generic_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double * values,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)16746 tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write
16747 (const tng_trajectory_t tng_data,
16748 const int64_t frame_nr,
16749 const double *values,
16750 const int64_t n_values_per_frame,
16751 const int64_t block_id,
16752 const char *block_name,
16753 const char particle_dependency,
16754 const char compression)
16755 {
16756 tng_trajectory_frame_set_t frame_set;
16757 tng_data_t data;
16758 int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos;
16759 int64_t last_frame;
16760 int is_first_frame_flag = 0;
16761 char block_type_flag;
16762 tng_function_status stat;
16763
16764 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16765 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
16766
16767 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16768 {
16769 tng_num_particles_get(tng_data, &n_particles);
16770 TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data.");
16771 }
16772
16773 if(values == 0)
16774 {
16775 return(TNG_FAILURE);
16776 }
16777
16778 frame_set = &tng_data->current_trajectory_frame_set;
16779
16780 if(frame_nr < 0)
16781 {
16782 block_type_flag = TNG_NON_TRAJECTORY_BLOCK;
16783 n_frames = stride_length = 1;
16784 }
16785 else
16786 {
16787 block_type_flag = TNG_TRAJECTORY_BLOCK;
16788
16789 if(!frame_set || tng_data->n_trajectory_frame_sets <= 0)
16790 {
16791 stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames);
16792 if(stat != TNG_SUCCESS)
16793 {
16794 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16795 __LINE__);
16796 return(stat);
16797 }
16798 }
16799 last_frame = frame_set->first_frame +
16800 frame_set->n_frames - 1;
16801 if(frame_nr > last_frame)
16802 {
16803 stat = tng_frame_set_write(tng_data, TNG_USE_HASH);
16804 if(stat != TNG_SUCCESS)
16805 {
16806 fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__,
16807 __LINE__);
16808 return(stat);
16809 }
16810 if(last_frame + tng_data->frame_set_n_frames < frame_nr)
16811 {
16812 last_frame = frame_nr - 1;
16813 }
16814 stat = tng_frame_set_new(tng_data, last_frame + 1,
16815 tng_data->frame_set_n_frames);
16816 if(stat != TNG_SUCCESS)
16817 {
16818 fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__,
16819 __LINE__);
16820 return(stat);
16821 }
16822 }
16823 if(frame_set->n_unwritten_frames == 0)
16824 {
16825 is_first_frame_flag = 1;
16826 }
16827 frame_set->n_unwritten_frames = frame_nr -
16828 frame_set->first_frame + 1;
16829
16830 n_frames = frame_set->n_frames;
16831 }
16832
16833
16834 if(particle_dependency == TNG_PARTICLE_BLOCK_DATA)
16835 {
16836 if(tng_particle_data_find(tng_data, block_id, &data)
16837 != TNG_SUCCESS)
16838 {
16839 stat = tng_particle_data_block_add(tng_data, block_id,
16840 block_name,
16841 TNG_DOUBLE_DATA,
16842 block_type_flag,
16843 n_frames, n_values_per_frame,
16844 stride_length,
16845 0, n_particles,
16846 compression, 0);
16847 if(stat != TNG_SUCCESS)
16848 {
16849 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16850 __FILE__, __LINE__);
16851 return(stat);
16852 }
16853 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16854 {
16855 data = &frame_set->tr_particle_data[frame_set->
16856 n_particle_data_blocks - 1];
16857 }
16858 else
16859 {
16860 data = &tng_data->non_tr_particle_data[tng_data->
16861 n_particle_data_blocks - 1];
16862 }
16863 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16864 stride_length, n_particles,
16865 n_values_per_frame);
16866 if(stat != TNG_SUCCESS)
16867 {
16868 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16869 __FILE__, __LINE__);
16870 return(stat);
16871 }
16872 }
16873 /* FIXME: Here we must be able to handle modified n_particles as well. */
16874 else if(n_frames > data->n_frames)
16875 {
16876 stat = tng_allocate_particle_data_mem(tng_data, data, n_frames,
16877 data->stride_length, n_particles,
16878 n_values_per_frame);
16879 if(stat != TNG_SUCCESS)
16880 {
16881 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16882 __FILE__, __LINE__);
16883 return(stat);
16884 }
16885 }
16886
16887 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16888 {
16889 stride_length = data->stride_length;
16890
16891 if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16892 {
16893 data->first_frame_with_data = frame_nr;
16894 frame_pos = 0;
16895 }
16896 else
16897 {
16898 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16899 }
16900
16901 memcpy((char *)data->values + sizeof(double) * frame_pos * n_particles *
16902 n_values_per_frame, values, sizeof(double) *
16903 n_particles * n_values_per_frame);
16904 }
16905 else
16906 {
16907 memcpy(data->values, values, sizeof(double) * n_particles *
16908 n_values_per_frame);
16909 }
16910 }
16911 else
16912 {
16913 if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS)
16914 {
16915 stat = tng_data_block_add(tng_data, block_id, block_name,
16916 TNG_DOUBLE_DATA, block_type_flag,
16917 n_frames, n_values_per_frame,
16918 stride_length, compression, 0);
16919 if(stat != TNG_SUCCESS)
16920 {
16921 fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name,
16922 __FILE__, __LINE__);
16923 return(stat);
16924 }
16925 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16926 {
16927 data = &frame_set->tr_data[frame_set->
16928 n_data_blocks - 1];
16929 }
16930 else
16931 {
16932 data = &tng_data->non_tr_data[tng_data->
16933 n_data_blocks - 1];
16934 }
16935 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16936 stride_length, n_values_per_frame);
16937 if(stat != TNG_SUCCESS)
16938 {
16939 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16940 __FILE__, __LINE__);
16941 return(stat);
16942 }
16943 }
16944 /* FIXME: Here we must be able to handle modified n_particles as well. */
16945 else if(n_frames > data->n_frames)
16946 {
16947 stat = tng_allocate_data_mem(tng_data, data, n_frames,
16948 data->stride_length, n_values_per_frame);
16949 if(stat != TNG_SUCCESS)
16950 {
16951 fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n",
16952 __FILE__, __LINE__);
16953 return(stat);
16954 }
16955 }
16956
16957 if(block_type_flag == TNG_TRAJECTORY_BLOCK)
16958 {
16959 stride_length = data->stride_length;
16960
16961 if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame)
16962 {
16963 data->first_frame_with_data = frame_nr;
16964 frame_pos = 0;
16965 }
16966 else
16967 {
16968 frame_pos = (frame_nr - frame_set->first_frame) / stride_length;
16969 }
16970
16971 memcpy((char *)data->values + sizeof(double) * frame_pos *
16972 n_values_per_frame, values, sizeof(double) *
16973 n_values_per_frame);
16974 }
16975 else
16976 {
16977 memcpy(data->values, values, sizeof(double) * n_values_per_frame);
16978 }
16979 }
16980
16981 return(TNG_SUCCESS);
16982 }
16983
tng_util_pos_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const float * positions)16984 tng_function_status DECLSPECDLLEXPORT tng_util_pos_write
16985 (const tng_trajectory_t tng_data,
16986 const int64_t frame_nr,
16987 const float *positions)
16988 {
16989 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
16990 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
16991
16992 return(tng_util_generic_write(tng_data, frame_nr, positions, 3,
16993 TNG_TRAJ_POSITIONS, "POSITIONS",
16994 TNG_PARTICLE_BLOCK_DATA,
16995 TNG_TNG_COMPRESSION));
16996 }
16997
tng_util_pos_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double * positions)16998 tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write
16999 (const tng_trajectory_t tng_data,
17000 const int64_t frame_nr,
17001 const double *positions)
17002 {
17003 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17004 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17005
17006 return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3,
17007 TNG_TRAJ_POSITIONS, "POSITIONS",
17008 TNG_PARTICLE_BLOCK_DATA,
17009 TNG_TNG_COMPRESSION));
17010 }
17011
tng_util_vel_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const float * velocities)17012 tng_function_status DECLSPECDLLEXPORT tng_util_vel_write
17013 (const tng_trajectory_t tng_data,
17014 const int64_t frame_nr,
17015 const float *velocities)
17016 {
17017 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17018 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17019
17020 return(tng_util_generic_write(tng_data, frame_nr, velocities, 3,
17021 TNG_TRAJ_VELOCITIES, "VELOCITIES",
17022 TNG_PARTICLE_BLOCK_DATA,
17023 TNG_TNG_COMPRESSION));
17024 }
17025
tng_util_vel_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double * velocities)17026 tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write
17027 (const tng_trajectory_t tng_data,
17028 const int64_t frame_nr,
17029 const double *velocities)
17030 {
17031 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17032 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17033
17034 return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3,
17035 TNG_TRAJ_VELOCITIES, "VELOCITIES",
17036 TNG_PARTICLE_BLOCK_DATA,
17037 TNG_TNG_COMPRESSION));
17038 }
17039
tng_util_force_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const float * forces)17040 tng_function_status DECLSPECDLLEXPORT tng_util_force_write
17041 (const tng_trajectory_t tng_data,
17042 const int64_t frame_nr,
17043 const float *forces)
17044 {
17045 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17046 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17047
17048 return(tng_util_generic_write(tng_data, frame_nr, forces, 3,
17049 TNG_TRAJ_FORCES, "FORCES",
17050 TNG_PARTICLE_BLOCK_DATA,
17051 TNG_GZIP_COMPRESSION));
17052 }
17053
tng_util_force_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double * forces)17054 tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write
17055 (const tng_trajectory_t tng_data,
17056 const int64_t frame_nr,
17057 const double *forces)
17058 {
17059 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17060 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17061
17062 return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3,
17063 TNG_TRAJ_FORCES, "FORCES",
17064 TNG_PARTICLE_BLOCK_DATA,
17065 TNG_GZIP_COMPRESSION));
17066 }
17067
tng_util_box_shape_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const float * box_shape)17068 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write
17069 (const tng_trajectory_t tng_data,
17070 const int64_t frame_nr,
17071 const float *box_shape)
17072 {
17073 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17074 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17075
17076 return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9,
17077 TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17078 TNG_NON_PARTICLE_BLOCK_DATA,
17079 TNG_GZIP_COMPRESSION));
17080 }
17081
tng_util_box_shape_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double * box_shape)17082 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write
17083 (const tng_trajectory_t tng_data,
17084 const int64_t frame_nr,
17085 const double *box_shape)
17086 {
17087 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17088 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17089
17090 return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9,
17091 TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17092 TNG_NON_PARTICLE_BLOCK_DATA,
17093 TNG_GZIP_COMPRESSION));
17094 }
17095
tng_util_generic_with_time_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const float * values,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)17096 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write
17097 (const tng_trajectory_t tng_data,
17098 const int64_t frame_nr,
17099 const double time,
17100 const float *values,
17101 const int64_t n_values_per_frame,
17102 const int64_t block_id,
17103 const char *block_name,
17104 const char particle_dependency,
17105 const char compression)
17106 {
17107 tng_trajectory_frame_set_t frame_set;
17108 tng_function_status stat;
17109
17110 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17111 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17112 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17113 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17114
17115 stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame,
17116 block_id, block_name,
17117 particle_dependency,
17118 compression);
17119
17120 if(stat != TNG_SUCCESS)
17121 {
17122 return(stat);
17123 }
17124
17125 frame_set = &tng_data->current_trajectory_frame_set;
17126
17127 /* first_frame_time is -1 when it is not yet set. */
17128 if(frame_set->first_frame_time < -0.1)
17129 {
17130 if(frame_nr > frame_set->first_frame)
17131 {
17132 stat = tng_frame_set_first_frame_time_set(tng_data,
17133 time -
17134 (frame_nr -
17135 frame_set->first_frame) *
17136 tng_data->time_per_frame);
17137 }
17138 else
17139 {
17140 stat = tng_frame_set_first_frame_time_set(tng_data, time);
17141 }
17142 }
17143 return(stat);
17144 }
17145
tng_util_generic_with_time_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const double * values,const int64_t n_values_per_frame,const int64_t block_id,const char * block_name,const char particle_dependency,const char compression)17146 tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write
17147 (const tng_trajectory_t tng_data,
17148 const int64_t frame_nr,
17149 const double time,
17150 const double *values,
17151 const int64_t n_values_per_frame,
17152 const int64_t block_id,
17153 const char *block_name,
17154 const char particle_dependency,
17155 const char compression)
17156 {
17157 tng_trajectory_frame_set_t frame_set;
17158 tng_function_status stat;
17159
17160 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17161 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17162 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17163 TNG_ASSERT(values, "TNG library: values must not be a NULL pointer");
17164
17165 stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame,
17166 block_id, block_name,
17167 particle_dependency,
17168 compression);
17169
17170 if(stat != TNG_SUCCESS)
17171 {
17172 return(stat);
17173 }
17174
17175 frame_set = &tng_data->current_trajectory_frame_set;
17176
17177 /* first_frame_time is -1 when it is not yet set. */
17178 if(frame_set->first_frame_time < -0.1)
17179 {
17180 if(frame_nr > frame_set->first_frame)
17181 {
17182 stat = tng_frame_set_first_frame_time_set(tng_data,
17183 time -
17184 (frame_nr -
17185 frame_set->first_frame) *
17186 tng_data->time_per_frame);
17187 }
17188 else
17189 {
17190 stat = tng_frame_set_first_frame_time_set(tng_data, time);
17191 }
17192 }
17193 return(stat);
17194 }
17195
tng_util_pos_with_time_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const float * positions)17196 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write
17197 (const tng_trajectory_t tng_data,
17198 const int64_t frame_nr,
17199 const double time,
17200 const float *positions)
17201 {
17202 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17203 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17204 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17205 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17206
17207 return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions,
17208 3, TNG_TRAJ_POSITIONS, "POSITIONS",
17209 TNG_PARTICLE_BLOCK_DATA,
17210 TNG_TNG_COMPRESSION));
17211 }
17212
tng_util_pos_with_time_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const double * positions)17213 tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write
17214 (const tng_trajectory_t tng_data,
17215 const int64_t frame_nr,
17216 const double time,
17217 const double *positions)
17218 {
17219 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17220 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17221 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17222 TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer");
17223
17224 return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17225 positions, 3,
17226 TNG_TRAJ_POSITIONS,
17227 "POSITIONS",
17228 TNG_PARTICLE_BLOCK_DATA,
17229 TNG_TNG_COMPRESSION));
17230 }
17231
tng_util_vel_with_time_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const float * velocities)17232 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write
17233 (const tng_trajectory_t tng_data,
17234 const int64_t frame_nr,
17235 const double time,
17236 const float *velocities)
17237 {
17238 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17239 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17240 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17241 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17242
17243 return(tng_util_generic_with_time_write(tng_data, frame_nr, time,
17244 velocities, 3,
17245 TNG_TRAJ_VELOCITIES,
17246 "VELOCITIES",
17247 TNG_PARTICLE_BLOCK_DATA,
17248 TNG_TNG_COMPRESSION));
17249 }
17250
tng_util_vel_with_time_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const double * velocities)17251 tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write
17252 (const tng_trajectory_t tng_data,
17253 const int64_t frame_nr,
17254 const double time,
17255 const double *velocities)
17256 {
17257 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17258 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17259 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17260 TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer");
17261
17262 return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17263 velocities, 3,
17264 TNG_TRAJ_VELOCITIES,
17265 "VELOCITIES",
17266 TNG_PARTICLE_BLOCK_DATA,
17267 TNG_TNG_COMPRESSION));
17268 }
17269
tng_util_force_with_time_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const float * forces)17270 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write
17271 (const tng_trajectory_t tng_data,
17272 const int64_t frame_nr,
17273 const double time,
17274 const float *forces)
17275 {
17276 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17277 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17278 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17279 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17280
17281 return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces,
17282 3, TNG_TRAJ_FORCES, "FORCES",
17283 TNG_PARTICLE_BLOCK_DATA,
17284 TNG_GZIP_COMPRESSION));
17285 }
17286
tng_util_force_with_time_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const double * forces)17287 tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write
17288 (const tng_trajectory_t tng_data,
17289 const int64_t frame_nr,
17290 const double time,
17291 const double *forces)
17292 {
17293 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17294 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17295 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17296 TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer");
17297
17298 return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time,
17299 forces, 3,
17300 TNG_TRAJ_FORCES, "FORCES",
17301 TNG_PARTICLE_BLOCK_DATA,
17302 TNG_GZIP_COMPRESSION));
17303 }
17304
tng_util_box_shape_with_time_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const float * box_shape)17305 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write
17306 (const tng_trajectory_t tng_data,
17307 const int64_t frame_nr,
17308 const double time,
17309 const float *box_shape)
17310 {
17311 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17312 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17313 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17314 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17315
17316 return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape,
17317 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
17318 TNG_NON_PARTICLE_BLOCK_DATA,
17319 TNG_GZIP_COMPRESSION));
17320 }
17321
tng_util_box_shape_with_time_double_write(const tng_trajectory_t tng_data,const int64_t frame_nr,const double time,const double * box_shape)17322 tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write
17323 (const tng_trajectory_t tng_data,
17324 const int64_t frame_nr,
17325 const double time,
17326 const double *box_shape)
17327 {
17328 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17329 TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0.");
17330 TNG_ASSERT(time >= 0, "TNG library: time must be >= 0.");
17331 TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer");
17332
17333 return(tng_util_generic_with_time_double_write(tng_data, frame_nr,
17334 time, box_shape, 9,
17335 TNG_TRAJ_BOX_SHAPE,
17336 "BOX SHAPE",
17337 TNG_NON_PARTICLE_BLOCK_DATA,
17338 TNG_GZIP_COMPRESSION));
17339 }
17340
tng_util_frame_current_compression_get(const tng_trajectory_t tng_data,const int64_t block_id,int64_t * codec_id,double * factor)17341 tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get
17342 (const tng_trajectory_t tng_data,
17343 const int64_t block_id,
17344 int64_t *codec_id,
17345 double *factor)
17346 {
17347 tng_trajectory_frame_set_t frame_set;
17348 tng_data_t data = 0;
17349 tng_function_status stat;
17350 int64_t i;
17351 int block_type = -1;
17352
17353 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17354 TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer.");
17355 TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer.");
17356
17357 frame_set = &tng_data->current_trajectory_frame_set;
17358
17359 stat = tng_particle_data_find(tng_data, block_id, &data);
17360 if(stat == TNG_SUCCESS)
17361 {
17362 block_type = TNG_PARTICLE_BLOCK_DATA;
17363 }
17364 else
17365 {
17366 stat = tng_data_find(tng_data, block_id, &data);
17367 if(stat == TNG_SUCCESS)
17368 {
17369 block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17370 }
17371 else
17372 {
17373 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17374 if(stat != TNG_SUCCESS)
17375 {
17376 return(stat);
17377 }
17378 stat = tng_particle_data_find(tng_data, block_id, &data);
17379 if(stat == TNG_SUCCESS)
17380 {
17381 block_type = TNG_PARTICLE_BLOCK_DATA;
17382 }
17383 else
17384 {
17385 stat = tng_data_find(tng_data, block_id, &data);
17386 if(stat == TNG_SUCCESS)
17387 {
17388 block_type = TNG_NON_PARTICLE_BLOCK_DATA;
17389 }
17390 else
17391 {
17392 return(stat);
17393 }
17394 }
17395 }
17396 }
17397 if(block_type == TNG_PARTICLE_BLOCK_DATA)
17398 {
17399 if(data->last_retrieved_frame < 0)
17400 {
17401 i = data->first_frame_with_data;
17402 }
17403 else
17404 {
17405 i = data->last_retrieved_frame;
17406 }
17407 }
17408 else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17409 {
17410 if(data->last_retrieved_frame < 0)
17411 {
17412 i = data->first_frame_with_data;
17413 }
17414 else
17415 {
17416 i = data->last_retrieved_frame;
17417 }
17418 }
17419 else
17420 {
17421 return(TNG_FAILURE);
17422 }
17423 if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames)
17424 {
17425 stat = tng_frame_set_of_frame_find(tng_data, i);
17426 if(stat != TNG_SUCCESS)
17427 {
17428 return(stat);
17429 }
17430 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id);
17431 if(stat != TNG_SUCCESS)
17432 {
17433 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17434 __FILE__, __LINE__);
17435 return(stat);
17436 }
17437 }
17438 if(block_type == TNG_PARTICLE_BLOCK_DATA)
17439 {
17440 *codec_id = data->codec_id;
17441 *factor = data->compression_multiplier;
17442 }
17443 else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA)
17444 {
17445 *codec_id = data->codec_id;
17446 *factor = data->compression_multiplier;
17447 }
17448 return(TNG_SUCCESS);
17449 }
17450
tng_util_trajectory_next_frame_present_data_blocks_find(const tng_trajectory_t tng_data,int64_t current_frame,const int64_t n_requested_data_block_ids,const int64_t * requested_data_block_ids,int64_t * next_frame,int64_t * n_data_blocks_in_next_frame,int64_t ** data_block_ids_in_next_frame)17451 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find
17452 (const tng_trajectory_t tng_data,
17453 int64_t current_frame,
17454 const int64_t n_requested_data_block_ids,
17455 const int64_t *requested_data_block_ids,
17456 int64_t *next_frame,
17457 int64_t *n_data_blocks_in_next_frame,
17458 int64_t **data_block_ids_in_next_frame)
17459 {
17460 tng_trajectory_frame_set_t frame_set;
17461 tng_function_status stat;
17462 tng_data_t data;
17463 tng_gen_block_t block;
17464 int64_t i, j, block_id, *temp;
17465 int64_t data_frame, frame_diff, min_diff;
17466 int64_t size, frame_set_file_pos;
17467 int found, read_all = 0;
17468 int64_t file_pos;
17469
17470 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17471 TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL.");
17472 TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL.");
17473 TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17474
17475 if(n_requested_data_block_ids)
17476 {
17477 TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
17478 size = sizeof(int64_t) * n_requested_data_block_ids;
17479 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17480 if(!temp)
17481 {
17482 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17483 __FILE__, __LINE__);
17484 free(*data_block_ids_in_next_frame);
17485 *data_block_ids_in_next_frame = 0;
17486 return(TNG_CRITICAL);
17487 }
17488 *data_block_ids_in_next_frame = temp;
17489 }
17490
17491 frame_set = &tng_data->current_trajectory_frame_set;
17492
17493 current_frame += 1;
17494
17495 if(current_frame < frame_set->first_frame ||
17496 current_frame >= frame_set->first_frame + frame_set->n_frames)
17497 {
17498 frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos;
17499 stat = tng_frame_set_of_frame_find(tng_data, current_frame);
17500 if(stat != TNG_SUCCESS)
17501 {
17502 /* If the frame set search found the frame set after the starting
17503 * frame set there is a gap in the frame sets. So, even if the frame
17504 * was not found the next frame with data is still in the found
17505 * frame set. */
17506 if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos !=
17507 frame_set_file_pos)
17508 {
17509 return(stat);
17510 }
17511 current_frame = frame_set->first_frame;
17512 }
17513 }
17514
17515 /* Check for data blocks only if they have not already been found. */
17516 if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0)
17517 {
17518 file_pos = ftello(tng_data->input_file);
17519 if(file_pos < tng_data->input_file_len)
17520 {
17521 tng_block_init(&block);
17522 stat = tng_block_header_read(tng_data, block);
17523 while(file_pos < tng_data->input_file_len &&
17524 stat != TNG_CRITICAL &&
17525 block->id != TNG_TRAJECTORY_FRAME_SET &&
17526 block->id != -1)
17527 {
17528 stat = tng_block_read_next(tng_data, block,
17529 TNG_USE_HASH);
17530 if(stat != TNG_CRITICAL)
17531 {
17532 file_pos = ftello(tng_data->input_file);
17533 if(file_pos < tng_data->input_file_len)
17534 {
17535 stat = tng_block_header_read(tng_data, block);
17536 }
17537 }
17538 }
17539 tng_block_destroy(&block);
17540 if(stat == TNG_CRITICAL)
17541 {
17542 fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
17543 file_pos, __FILE__, __LINE__);
17544 return(stat);
17545 }
17546 }
17547 read_all = 1;
17548 }
17549
17550 min_diff = -1;
17551
17552 *n_data_blocks_in_next_frame = 0;
17553
17554 for(i = 0; i < frame_set->n_particle_data_blocks; i++)
17555 {
17556 data = &frame_set->tr_particle_data[i];
17557 block_id = data->block_id;
17558
17559 if(n_requested_data_block_ids > 0)
17560 {
17561 found = 0;
17562 for(j = 0; j < n_requested_data_block_ids; j++)
17563 {
17564 if(block_id == requested_data_block_ids[j])
17565 {
17566 found = 1;
17567 break;
17568 }
17569 }
17570 if(!found)
17571 {
17572 continue;
17573 }
17574 }
17575
17576 if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17577 data->last_retrieved_frame >=
17578 frame_set->first_frame + frame_set->n_frames))
17579 {
17580 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17581 TNG_USE_HASH, block_id);
17582 if(stat == TNG_CRITICAL)
17583 {
17584 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17585 __FILE__, __LINE__);
17586 return(stat);
17587 }
17588 if(stat == TNG_FAILURE)
17589 {
17590 continue;
17591 }
17592 }
17593 if(frame_set->first_frame != current_frame &&
17594 data->last_retrieved_frame >= 0)
17595 {
17596 data_frame = data->last_retrieved_frame + data->stride_length;
17597 }
17598 else
17599 {
17600 data_frame = data->first_frame_with_data;
17601 }
17602 frame_diff = data_frame - current_frame;
17603 if(frame_diff < 0)
17604 {
17605 continue;
17606 }
17607 if(min_diff == -1 || frame_diff <= min_diff)
17608 {
17609 if(frame_diff < min_diff)
17610 {
17611 *n_data_blocks_in_next_frame = 1;
17612 }
17613 else
17614 {
17615 *n_data_blocks_in_next_frame += 1;
17616 }
17617 if(n_requested_data_block_ids <= 0)
17618 {
17619 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17620 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17621 if(!temp)
17622 {
17623 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17624 __FILE__, __LINE__);
17625 free(*data_block_ids_in_next_frame);
17626 *data_block_ids_in_next_frame = 0;
17627 return(TNG_CRITICAL);
17628 }
17629 *data_block_ids_in_next_frame = temp;
17630 }
17631 else
17632 {
17633 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17634 }
17635 (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17636
17637 min_diff = frame_diff;
17638 }
17639 }
17640 for(i = 0; i < frame_set->n_data_blocks; i++)
17641 {
17642 data = &frame_set->tr_data[i];
17643 block_id = data->block_id;
17644
17645 if(n_requested_data_block_ids > 0)
17646 {
17647 found = 0;
17648 for(j = 0; j < n_requested_data_block_ids; j++)
17649 {
17650 if(block_id == requested_data_block_ids[j])
17651 {
17652 found = 1;
17653 break;
17654 }
17655 }
17656 if(!found)
17657 {
17658 continue;
17659 }
17660 }
17661
17662 if(!read_all && (data->last_retrieved_frame < frame_set->first_frame ||
17663 data->last_retrieved_frame >=
17664 frame_set->first_frame + frame_set->n_frames))
17665 {
17666 stat = tng_frame_set_read_current_only_data_from_block_id(tng_data,
17667 TNG_USE_HASH, block_id);
17668 if(stat == TNG_CRITICAL)
17669 {
17670 fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n",
17671 __FILE__, __LINE__);
17672 return(stat);
17673 }
17674 if(stat == TNG_FAILURE)
17675 {
17676 continue;
17677 }
17678 }
17679 if(frame_set->first_frame != current_frame &&
17680 data->last_retrieved_frame >= 0)
17681 {
17682 data_frame = data->last_retrieved_frame + data->stride_length;
17683 }
17684 else
17685 {
17686 data_frame = data->first_frame_with_data;
17687 }
17688 frame_diff = data_frame - current_frame;
17689 if(frame_diff < 0)
17690 {
17691 continue;
17692 }
17693 if(min_diff == -1 || frame_diff <= min_diff)
17694 {
17695 if(frame_diff < min_diff)
17696 {
17697 *n_data_blocks_in_next_frame = 1;
17698 }
17699 else
17700 {
17701 *n_data_blocks_in_next_frame += 1;
17702 }
17703 if(n_requested_data_block_ids <= 0)
17704 {
17705 size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
17706 temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
17707 if(!temp)
17708 {
17709 fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
17710 __FILE__, __LINE__);
17711 free(*data_block_ids_in_next_frame);
17712 *data_block_ids_in_next_frame = 0;
17713 return(TNG_CRITICAL);
17714 }
17715 *data_block_ids_in_next_frame = temp;
17716 }
17717 else
17718 {
17719 TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds");
17720 }
17721 (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id;
17722
17723 min_diff = frame_diff;
17724 }
17725 }
17726 if(min_diff < 0)
17727 {
17728 return(TNG_FAILURE);
17729 }
17730 *next_frame = current_frame + min_diff;
17731
17732 return(TNG_SUCCESS);
17733 }
17734
17735 /*
17736 tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get
17737 (const tng_trajectory_t tng_data,
17738 int64_t *n_data_blocks,
17739 int64_t **data_block_ids,
17740 char ***data_block_names,
17741 int64_t **stride_lengths,
17742 int64_t **n_values_per_frame,
17743 char **block_types,
17744 char **dependencies,
17745 char **compressions)
17746 {
17747 tng_gen_block_t block;
17748 int64_t orig_file_pos, file_pos;
17749
17750 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17751 TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL.");
17752 TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL.");
17753 TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL.");
17754 TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL.");
17755
17756 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17757 {
17758 return(TNG_CRITICAL);
17759 }
17760
17761 orig_file_pos = ftello(tng_data->input_file);
17762
17763 fseeko(tng_data->input_file, 0, SEEK_SET);
17764 file_pos = 0;
17765
17766 *n_data_blocks = 0;
17767
17768 tng_block_init(&block);
17769
17770 while(file_pos < tng_data->input_file_len &&
17771 tng_block_header_read(tng_data, block) != TNG_CRITICAL)
17772 {
17773 if(block->id > TNG_TRAJECTORY_FRAME_SET)
17774 {
17775
17776 }
17777 file_pos += (block->block_contents_size + block->header_contents_size);
17778 fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR);
17779 }
17780
17781 fseeko(tng_data->input_file, orig_file_pos, SEEK_SET);
17782
17783 return(TNG_SUCCESS);
17784 }
17785 */
tng_util_prepare_append_after_frame(const tng_trajectory_t tng_data,const int64_t prev_frame)17786 tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame
17787 (const tng_trajectory_t tng_data,
17788 const int64_t prev_frame)
17789 {
17790 tng_function_status stat;
17791 FILE *temp = tng_data->input_file;
17792
17793 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17794 TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative.");
17795
17796 tng_data->input_file = tng_data->output_file;
17797
17798 stat = tng_frame_set_of_frame_find(tng_data, prev_frame);
17799 if(stat != TNG_SUCCESS)
17800 {
17801 return(stat);
17802 }
17803
17804 tng_data->current_trajectory_frame_set_output_file_pos =
17805 tng_data->current_trajectory_frame_set_input_file_pos;
17806
17807 tng_data->input_file = temp;
17808
17809 return(TNG_SUCCESS);
17810 }
17811
tng_util_num_frames_with_data_of_block_id_get(const tng_trajectory_t tng_data,const int64_t block_id,int64_t * n_frames)17812 tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get
17813 (const tng_trajectory_t tng_data,
17814 const int64_t block_id,
17815 int64_t *n_frames)
17816 {
17817 int64_t curr_file_pos, first_frame_set_file_pos, curr_n_frames;
17818 tng_function_status stat;
17819
17820 TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
17821
17822 *n_frames = 0;
17823
17824 if(tng_input_file_init(tng_data) != TNG_SUCCESS)
17825 {
17826 return(TNG_CRITICAL);
17827 }
17828
17829 first_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos;
17830 curr_file_pos = ftello(tng_data->input_file);
17831 fseeko(tng_data->input_file, first_frame_set_file_pos, SEEK_SET);
17832
17833 stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17834
17835 while(stat == TNG_SUCCESS && tng_data->current_trajectory_frame_set.next_frame_set_file_pos != -1)
17836 {
17837 *n_frames += curr_n_frames;
17838 fseeko(tng_data->input_file,
17839 tng_data->current_trajectory_frame_set.next_frame_set_file_pos,
17840 SEEK_SET);
17841 stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames);
17842 }
17843 if(stat == TNG_SUCCESS)
17844 {
17845 *n_frames += curr_n_frames;
17846 }
17847 fseeko(tng_data->input_file, curr_file_pos, SEEK_SET);
17848 if(stat == TNG_CRITICAL)
17849 {
17850 return(TNG_CRITICAL);
17851 }
17852 return(TNG_SUCCESS);
17853 }
17854