Merge branch release-4-6 into release-5-0
[alexxy/gromacs.git] / src / gromacs / fileio / tngio_for_tools.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "tngio_for_tools.h"
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include <math.h>
42
43 #include "tngio.h"
44 #include "trx.h"
45
46 #ifdef GMX_USE_TNG
47 #include "tng/tng_io.h"
48 #endif
49
50 #include "gromacs/legacyheaders/types/atoms.h"
51 #include "gromacs/legacyheaders/physics.h"
52 #include "gromacs/legacyheaders/gmx_fatal.h"
53
54 #include "gromacs/utility/common.h"
55 #include "gromacs/utility/smalloc.h"
56
57 void gmx_prepare_tng_writing(const char              *filename,
58                              char                     mode,
59                              tng_trajectory_t        *input,
60                              tng_trajectory_t        *output,
61                              int                      nAtoms,
62                              const gmx_mtop_t        *mtop,
63                              const atom_id           *index,
64                              const char              *indexGroupName)
65 {
66 #ifdef GMX_USE_TNG
67     /* FIXME after 5.0: Currently only standard block types are read */
68     const int           defaultNumIds              = 5;
69     static gmx_int64_t  fallbackIds[defaultNumIds] =
70     {
71         TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
72         TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
73         TNG_GMX_LAMBDA
74     };
75     static char         fallbackNames[defaultNumIds][32] =
76     {
77         "BOX SHAPE", "POSITIONS", "VELOCITIES",
78         "FORCES", "LAMBDAS"
79     };
80
81
82     gmx_tng_open(filename, mode, output);
83
84     /* Do we have an input file in TNG format? If so, then there's
85        more data we can copy over, rather than having to improvise. */
86     if (*input)
87     {
88         /* Set parameters (compression, time per frame, molecule
89          * information, number of frames per frame set and writing
90          * intervals of positions, box shape and lambdas) of the
91          * output tng container based on their respective values int
92          * the input tng container */
93         double      time, compression_precision;
94         gmx_int64_t n_frames_per_frame_set, interval = -1;
95
96         tng_compression_precision_get(*input, &compression_precision);
97         tng_compression_precision_set(*output, compression_precision);
98         // TODO make this configurable in a future version
99         char compression_type = TNG_TNG_COMPRESSION;
100
101         tng_molecule_system_copy(*input, *output);
102
103         tng_time_per_frame_get(*input, &time);
104         tng_time_per_frame_set(*output, time);
105
106         tng_num_frames_per_frame_set_get(*input, &n_frames_per_frame_set);
107         tng_num_frames_per_frame_set_set(*output, n_frames_per_frame_set);
108
109         for (int i = 0; i < defaultNumIds; i++)
110         {
111             if (tng_data_get_stride_length(*input, fallbackIds[i], -1, &interval)
112                 == TNG_SUCCESS)
113             {
114                 switch (fallbackIds[i])
115                 {
116                     case TNG_TRAJ_POSITIONS:
117                     case TNG_TRAJ_VELOCITIES:
118                         tng_util_generic_write_interval_set(*output, interval, 3, fallbackIds[i],
119                                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
120                                                             compression_type);
121                         break;
122                     case TNG_TRAJ_FORCES:
123                         tng_util_generic_write_interval_set(*output, interval, 3, fallbackIds[i],
124                                                             fallbackNames[i], TNG_PARTICLE_BLOCK_DATA,
125                                                             TNG_GZIP_COMPRESSION);
126                         break;
127                     case TNG_TRAJ_BOX_SHAPE:
128                         tng_util_generic_write_interval_set(*output, interval, 9, fallbackIds[i],
129                                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
130                                                             TNG_GZIP_COMPRESSION);
131                         break;
132                     case TNG_GMX_LAMBDA:
133                         tng_util_generic_write_interval_set(*output, interval, 1, fallbackIds[i],
134                                                             fallbackNames[i], TNG_NON_PARTICLE_BLOCK_DATA,
135                                                             TNG_GZIP_COMPRESSION);
136                     default:
137                         continue;
138                 }
139             }
140         }
141
142     }
143     else
144     {
145         /* TODO after trjconv is modularized: fix this so the user can
146            change precision when they are doing an operation where
147            this makes sense, and not otherwise.
148
149            char compression = bUseLossyCompression ? TNG_TNG_COMPRESSION : TNG_GZIP_COMPRESSION;
150            gmx_tng_set_compression_precision(*output, ndec2prec(nDecimalsOfPrecision));
151          */
152         gmx_tng_add_mtop(*output, mtop);
153         tng_num_frames_per_frame_set_set(*output, 1);
154     }
155
156     if (index && nAtoms > 0)
157     {
158         gmx_tng_setup_atom_subgroup(*output, nAtoms, index, indexGroupName);
159     }
160
161     /* If for some reason there are more requested atoms than there are atoms in the
162      * molecular system create a number of implicit atoms (without atom data) to
163      * compensate for that. */
164     if (nAtoms >= 0)
165     {
166         tng_implicit_num_particles_set(*output, nAtoms);
167     }
168 #else
169     GMX_UNUSED_VALUE(filename);
170     GMX_UNUSED_VALUE(mode);
171     GMX_UNUSED_VALUE(input);
172     GMX_UNUSED_VALUE(output);
173     GMX_UNUSED_VALUE(nAtoms);
174     GMX_UNUSED_VALUE(mtop);
175     GMX_UNUSED_VALUE(index);
176     GMX_UNUSED_VALUE(indexGroupName);
177 #endif
178 }
179
180 void gmx_write_tng_from_trxframe(tng_trajectory_t        output,
181                                  t_trxframe             *frame,
182                                  int                     natoms)
183 {
184 #ifdef GMX_USE_TNG
185     if (frame->step > 0)
186     {
187         double timePerFrame = frame->time * PICO / frame->step;
188         tng_time_per_frame_set(output, timePerFrame);
189     }
190     if (natoms < 0)
191     {
192         natoms = frame->natoms;
193     }
194     gmx_fwrite_tng(output,
195                    TRUE,
196                    frame->step,
197                    frame->time,
198                    0,
199                    (const rvec *) frame->box,
200                    natoms,
201                    (const rvec *) frame->x,
202                    (const rvec *) frame->v,
203                    (const rvec *) frame->f);
204 #else
205     GMX_UNUSED_VALUE(output);
206     GMX_UNUSED_VALUE(frame);
207     GMX_UNUSED_VALUE(natoms);
208 #endif
209 }
210
211 #ifdef GMX_USE_TNG
212 static void
213 convert_array_to_real_array(void       *from,
214                             real       *to,
215                             const float fact,
216                             const int   nAtoms,
217                             const int   nValues,
218                             const char  datatype)
219 {
220     int i, j;
221
222     switch (datatype)
223     {
224         case TNG_FLOAT_DATA:
225             if (sizeof(real) == sizeof(float))
226             {
227                 if (fact == 1)
228                 {
229                     memcpy(to, from, nValues * sizeof(real) * nAtoms);
230                 }
231                 else
232                 {
233                     for (i = 0; i < nAtoms; i++)
234                     {
235                         for (j = 0; j < nValues; j++)
236                         {
237                             to[i*nValues+j] = (real)((float *)from)[i*nValues+j] * fact;
238                         }
239                     }
240                 }
241             }
242             else
243             {
244                 for (i = 0; i < nAtoms; i++)
245                 {
246                     for (j = 0; j < nValues; j++)
247                     {
248                         to[i*nValues+j] = (real)((float *)from)[i*nValues+j] * fact;
249                     }
250                 }
251             }
252             break;
253         case TNG_INT_DATA:
254             for (i = 0; i < nAtoms; i++)
255             {
256                 for (j = 0; j < nValues; j++)
257                 {
258                     to[i*nValues+j] = (real)((gmx_int64_t *)from)[i*nValues+j] * fact;
259                 }
260             }
261             break;
262         case TNG_DOUBLE_DATA:
263             if (sizeof(real) == sizeof(double))
264             {
265                 if (fact == 1)
266                 {
267                     memcpy(to, from, nValues * sizeof(real) * nAtoms);
268                 }
269                 else
270                 {
271                     for (i = 0; i < nAtoms; i++)
272                     {
273                         for (j = 0; j < nValues; j++)
274                         {
275                             to[i*nValues+j] = (real)((double *)from)[i*nValues+j] * fact;
276                         }
277                     }
278                 }
279             }
280             else
281             {
282                 for (i = 0; i < nAtoms; i++)
283                 {
284                     for (j = 0; j < nValues; j++)
285                     {
286                         to[i*nValues+j] = (real)((double *)from)[i*nValues+j] * fact;
287                     }
288                 }
289             }
290             break;
291         default:
292             gmx_incons("Illegal datatype when converting values to a real array!");
293             return;
294     }
295     return;
296 }
297
298 static real getDistanceScaleFactor(tng_trajectory_t in)
299 {
300     gmx_int64_t exp = -1;
301     real        distanceScaleFactor;
302
303     // TODO Hopefully, TNG 2.0 will do this kind of thing for us
304     tng_distance_unit_exponential_get(in, &exp);
305
306     // GROMACS expects distances in nm
307     switch (exp)
308     {
309         case 9:
310             distanceScaleFactor = NANO/NANO;
311             break;
312         case 10:
313             distanceScaleFactor = NANO/ANGSTROM;
314             break;
315         default:
316             distanceScaleFactor = pow(10.0, exp + 9.0);
317     }
318
319     return distanceScaleFactor;
320 }
321 #endif
322
323 void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng,
324                                  const int        nind,
325                                  const atom_id   *ind,
326                                  const char      *name)
327 {
328 #ifdef GMX_USE_TNG
329     gmx_int64_t              nAtoms, cnt, nMols;
330     tng_molecule_t           mol, iterMol;
331     tng_chain_t              chain;
332     tng_residue_t            res;
333     tng_atom_t               atom;
334     tng_function_status      stat;
335
336     tng_num_particles_get(tng, &nAtoms);
337
338     if (nAtoms == nind)
339     {
340         return;
341     }
342
343     stat = tng_molecule_find(tng, name, -1, &mol);
344     if (stat == TNG_SUCCESS)
345     {
346         tng_molecule_num_atoms_get(tng, mol, &nAtoms);
347         tng_molecule_cnt_get(tng, mol, &cnt);
348         if (nAtoms == nind)
349         {
350             stat = TNG_SUCCESS;
351         }
352         else
353         {
354             stat = TNG_FAILURE;
355         }
356     }
357     if (stat == TNG_FAILURE)
358     {
359         /* The indexed atoms are added to one separate molecule. */
360         tng_molecule_alloc(tng, &mol);
361         tng_molecule_name_set(tng, mol, name);
362         tng_molecule_chain_add(tng, mol, "", &chain);
363
364         for (int i = 0; i < nind; i++)
365         {
366             char        temp_name[256], temp_type[256];
367
368             /* Try to retrieve the residue name of the atom */
369             stat = tng_residue_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
370             if (stat != TNG_SUCCESS)
371             {
372                 temp_name[0] = '\0';
373             }
374             /* Check if the molecule of the selection already contains this residue */
375             if (tng_chain_residue_find(tng, chain, temp_name, -1, &res)
376                 != TNG_SUCCESS)
377             {
378                 tng_chain_residue_add(tng, chain, temp_name, &res);
379             }
380             /* Try to find the original name and type of the atom */
381             stat = tng_atom_name_of_particle_nr_get(tng, ind[i], temp_name, 256);
382             if (stat != TNG_SUCCESS)
383             {
384                 temp_name[0] = '\0';
385             }
386             stat = tng_atom_type_of_particle_nr_get(tng, ind[i], temp_type, 256);
387             if (stat != TNG_SUCCESS)
388             {
389                 temp_type[0] = '\0';
390             }
391             tng_residue_atom_w_id_add(tng, res, temp_name, temp_type, ind[i], &atom);
392         }
393         tng_molecule_existing_add(tng, &mol);
394     }
395     /* Set the count of the molecule containing the selected atoms to 1 and all
396      * other molecules to 0 */
397     tng_molecule_cnt_set(tng, mol, 1);
398     tng_num_molecule_types_get(tng, &nMols);
399     for (gmx_int64_t k = 0; k < nMols; k++)
400     {
401         tng_molecule_of_index_get(tng, k, &iterMol);
402         if (iterMol == mol)
403         {
404             continue;
405         }
406         tng_molecule_cnt_set(tng, iterMol, 0);
407     }
408 #else
409     GMX_UNUSED_VALUE(tng);
410     GMX_UNUSED_VALUE(nind);
411     GMX_UNUSED_VALUE(ind);
412     GMX_UNUSED_VALUE(name);
413 #endif
414 }
415
416 /* TODO: If/when TNG acquires the ability to copy data blocks without
417  * uncompressing them, then this implemenation should be reconsidered.
418  * Ideally, gmx trjconv -f a.tng -o b.tng -b 10 -e 20 would be fast
419  * and lose no information. */
420 gmx_bool gmx_read_next_tng_frame(tng_trajectory_t            input,
421                                  t_trxframe                 *fr,
422                                  gmx_int64_t                *requestedIds,
423                                  int                         numRequestedIds)
424 {
425 #ifdef GMX_USE_TNG
426     gmx_bool                bOK = TRUE;
427     tng_function_status     stat;
428     gmx_int64_t             numberOfAtoms = -1, frameNumber = -1;
429     gmx_int64_t             nBlocks, blockId, *blockIds = NULL, codecId;
430     char                    datatype      = -1;
431     void                   *values        = NULL;
432     double                  frameTime     = -1.0;
433     int                     size, blockDependency;
434     double                  prec;
435     const int               defaultNumIds = 5;
436     static gmx_int64_t      fallbackRequestedIds[defaultNumIds] =
437     {
438         TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS,
439         TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES,
440         TNG_GMX_LAMBDA
441     };
442
443
444     fr->bStep     = FALSE;
445     fr->bTime     = FALSE;
446     fr->bLambda   = FALSE;
447     fr->bAtoms    = FALSE;
448     fr->bPrec     = FALSE;
449     fr->bX        = FALSE;
450     fr->bV        = FALSE;
451     fr->bF        = FALSE;
452     fr->bBox      = FALSE;
453
454     /* If no specific IDs were requested read all block types that can
455      * currently be interpreted */
456     if (!requestedIds || numRequestedIds == 0)
457     {
458         numRequestedIds = defaultNumIds;
459         requestedIds    = fallbackRequestedIds;
460     }
461
462     stat = tng_num_particles_get(input, &numberOfAtoms);
463     if (stat != TNG_SUCCESS)
464     {
465         gmx_file("Cannot determine number of atoms from TNG file.");
466     }
467     fr->natoms = numberOfAtoms;
468
469     if (!gmx_get_tng_data_block_types_of_next_frame(input,
470                                                     fr->step,
471                                                     numRequestedIds,
472                                                     requestedIds,
473                                                     &frameNumber,
474                                                     &nBlocks,
475                                                     &blockIds))
476     {
477         return FALSE;
478     }
479
480     if (nBlocks == 0)
481     {
482         return FALSE;
483     }
484
485     for (gmx_int64_t i = 0; i < nBlocks; i++)
486     {
487         blockId = blockIds[i];
488         tng_data_block_dependency_get(input, blockId, &blockDependency);
489         if (blockDependency & TNG_PARTICLE_DEPENDENT)
490         {
491             stat = tng_util_particle_data_next_frame_read(input,
492                                                           blockId,
493                                                           &values,
494                                                           &datatype,
495                                                           &frameNumber,
496                                                           &frameTime);
497         }
498         else
499         {
500             stat = tng_util_non_particle_data_next_frame_read(input,
501                                                               blockId,
502                                                               &values,
503                                                               &datatype,
504                                                               &frameNumber,
505                                                               &frameTime);
506         }
507         if (stat == TNG_CRITICAL)
508         {
509             gmx_file("Cannot read positions from TNG file.");
510             return FALSE;
511         }
512         else if (stat == TNG_FAILURE)
513         {
514             continue;
515         }
516         switch (blockId)
517         {
518             case TNG_TRAJ_BOX_SHAPE:
519                 switch (datatype)
520                 {
521                     case TNG_INT_DATA:
522                         size = sizeof(gmx_int64_t);
523                         break;
524                     case TNG_FLOAT_DATA:
525                         size = sizeof(float);
526                         break;
527                     case TNG_DOUBLE_DATA:
528                         size = sizeof(double);
529                         break;
530                     default:
531                         size = 0; /* Just to make the compiler happy. */
532                         gmx_incons("Illegal datatype of box shape values!");
533                 }
534                 for (int i = 0; i < DIM; i++)
535                 {
536                     convert_array_to_real_array((char *)(values) + size * i * DIM,
537                                                 (real *) fr->box[i],
538                                                 getDistanceScaleFactor(input),
539                                                 1,
540                                                 DIM,
541                                                 datatype);
542                 }
543                 fr->bBox = TRUE;
544                 break;
545             case TNG_TRAJ_POSITIONS:
546                 srenew(fr->x, fr->natoms);
547                 convert_array_to_real_array(values,
548                                             (real *) fr->x,
549                                             getDistanceScaleFactor(input),
550                                             fr->natoms,
551                                             DIM,
552                                             datatype);
553                 fr->bX = TRUE;
554                 tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
555                 /* This must be updated if/when more lossy compression methods are added */
556                 if (codecId == TNG_TNG_COMPRESSION)
557                 {
558                     fr->prec  = prec;
559                     fr->bPrec = TRUE;
560                 }
561                 break;
562             case TNG_TRAJ_VELOCITIES:
563                 srenew(fr->v, fr->natoms);
564                 convert_array_to_real_array(values,
565                                             (real *) fr->v,
566                                             getDistanceScaleFactor(input),
567                                             fr->natoms,
568                                             DIM,
569                                             datatype);
570                 fr->bV = TRUE;
571                 tng_util_frame_current_compression_get(input, blockId, &codecId, &prec);
572                 /* This must be updated if/when more lossy compression methods are added */
573                 if (codecId == TNG_TNG_COMPRESSION)
574                 {
575                     fr->prec  = prec;
576                     fr->bPrec = TRUE;
577                 }
578                 break;
579             case TNG_TRAJ_FORCES:
580                 srenew(fr->f, fr->natoms);
581                 convert_array_to_real_array(values,
582                                             (real *) fr->f,
583                                             getDistanceScaleFactor(input),
584                                             fr->natoms,
585                                             DIM,
586                                             datatype);
587                 fr->bF = TRUE;
588                 break;
589             case TNG_GMX_LAMBDA:
590                 switch (datatype)
591                 {
592                     case TNG_FLOAT_DATA:
593                         fr->lambda = (*(float *)values);
594                         break;
595                     case TNG_DOUBLE_DATA:
596                         fr->lambda = (*(double *)values);
597                         break;
598                     default:
599                         gmx_incons("Illegal datatype lambda value!");
600                 }
601                 fr->bLambda = TRUE;
602                 break;
603             default:
604                 gmx_warning("Illegal block type! Currently GROMACS tools can only handle certain data types. Skipping block.");
605         }
606         /* values does not have to be freed before reading next frame. It will
607          * be reallocated if it is not NULL. */
608     }
609
610     fr->step  = (int) frameNumber;
611     fr->bStep = TRUE;
612     // Convert the time to ps
613     fr->time  = frameTime / PICO;
614     fr->bTime = TRUE;
615
616     /* values must be freed before leaving this function */
617     sfree(values);
618
619     return bOK;
620 #else
621     GMX_UNUSED_VALUE(input);
622     GMX_UNUSED_VALUE(fr);
623     GMX_UNUSED_VALUE(requestedIds);
624     GMX_UNUSED_VALUE(numRequestedIds);
625     return FALSE;
626 #endif
627 }
628
629 void gmx_print_tng_molecule_system(tng_trajectory_t input,
630                                    FILE            *stream)
631 {
632 #ifdef GMX_USE_TNG
633     gmx_int64_t        nMolecules, nChains, nResidues, nAtoms, *molCntList;
634     tng_molecule_t     molecule;
635     tng_chain_t        chain;
636     tng_residue_t      residue;
637     tng_atom_t         atom;
638     char               str[256], varNAtoms;
639
640     tng_num_molecule_types_get(input, &nMolecules);
641     tng_molecule_cnt_list_get(input, &molCntList);
642     /* Can the number of particles change in the trajectory or is it constant? */
643     tng_num_particles_variable_get(input, &varNAtoms);
644
645     for (gmx_int64_t i = 0; i < nMolecules; i++)
646     {
647         tng_molecule_of_index_get(input, i, &molecule);
648         tng_molecule_name_get(input, molecule, str, 256);
649         if (varNAtoms == TNG_CONSTANT_N_ATOMS)
650         {
651             if ((int)molCntList[i] == 0)
652             {
653                 continue;
654             }
655             fprintf(stream, "Molecule: %s, count: %d\n", str, (int)molCntList[i]);
656         }
657         else
658         {
659             fprintf(stream, "Molecule: %s\n", str);
660         }
661         tng_molecule_num_chains_get(input, molecule, &nChains);
662         if (nChains > 0)
663         {
664             for (gmx_int64_t j = 0; j < nChains; j++)
665             {
666                 tng_molecule_chain_of_index_get(input, molecule, j, &chain);
667                 tng_chain_name_get(input, chain, str, 256);
668                 fprintf(stream, "\tChain: %s\n", str);
669                 tng_chain_num_residues_get(input, chain, &nResidues);
670                 for (gmx_int64_t k = 0; k < nResidues; k++)
671                 {
672                     tng_chain_residue_of_index_get(input, chain, k, &residue);
673                     tng_residue_name_get(input, residue, str, 256);
674                     fprintf(stream, "\t\tResidue: %s\n", str);
675                     tng_residue_num_atoms_get(input, residue, &nAtoms);
676                     for (gmx_int64_t l = 0; l < nAtoms; l++)
677                     {
678                         tng_residue_atom_of_index_get(input, residue, l, &atom);
679                         tng_atom_name_get(input, atom, str, 256);
680                         fprintf(stream, "\t\t\tAtom: %s", str);
681                         tng_atom_type_get(input, atom, str, 256);
682                         fprintf(stream, " (%s)\n", str);
683                     }
684                 }
685             }
686         }
687         /* It is possible to have a molecule without chains, in which case
688          * residues in the molecule can be iterated through without going
689          * through chains. */
690         else
691         {
692             tng_molecule_num_residues_get(input, molecule, &nResidues);
693             if (nResidues > 0)
694             {
695                 for (gmx_int64_t k = 0; k < nResidues; k++)
696                 {
697                     tng_molecule_residue_of_index_get(input, molecule, k, &residue);
698                     tng_residue_name_get(input, residue, str, 256);
699                     fprintf(stream, "\t\tResidue: %s\n", str);
700                     tng_residue_num_atoms_get(input, residue, &nAtoms);
701                     for (gmx_int64_t l = 0; l < nAtoms; l++)
702                     {
703                         tng_residue_atom_of_index_get(input, residue, l, &atom);
704                         tng_atom_name_get(input, atom, str, 256);
705                         fprintf(stream, "\t\t\tAtom: %s", str);
706                         tng_atom_type_get(input, atom, str, 256);
707                         fprintf(stream, " (%s)\n", str);
708                     }
709                 }
710             }
711             else
712             {
713                 tng_molecule_num_atoms_get(input, molecule, &nAtoms);
714                 for (gmx_int64_t l = 0; l < nAtoms; l++)
715                 {
716                     tng_molecule_atom_of_index_get(input, molecule, l, &atom);
717                     tng_atom_name_get(input, atom, str, 256);
718                     fprintf(stream, "\t\t\tAtom: %s", str);
719                     tng_atom_type_get(input, atom, str, 256);
720                     fprintf(stream, " (%s)\n", str);
721                 }
722             }
723         }
724     }
725 #else
726     GMX_UNUSED_VALUE(input);
727     GMX_UNUSED_VALUE(stream);
728 #endif
729 }
730
731 gmx_bool gmx_get_tng_data_block_types_of_next_frame(tng_trajectory_t     input,
732                                                     int                  frame,
733                                                     int                  nRequestedIds,
734                                                     gmx_int64_t         *requestedIds,
735                                                     gmx_int64_t         *nextFrame,
736                                                     gmx_int64_t         *nBlocks,
737                                                     gmx_int64_t        **blockIds)
738 {
739 #ifdef GMX_USE_TNG
740     tng_function_status stat;
741
742     stat = tng_util_trajectory_next_frame_present_data_blocks_find(input, frame,
743                                                                    nRequestedIds, requestedIds,
744                                                                    nextFrame,
745                                                                    nBlocks, blockIds);
746
747     if (stat == TNG_CRITICAL)
748     {
749         gmx_file("Cannot read TNG file. Cannot find data blocks of next frame.");
750     }
751     else if (stat == TNG_FAILURE)
752     {
753         return FALSE;
754     }
755     return TRUE;
756 #else
757     GMX_UNUSED_VALUE(input);
758     GMX_UNUSED_VALUE(frame);
759     GMX_UNUSED_VALUE(nRequestedIds);
760     GMX_UNUSED_VALUE(requestedIds);
761     GMX_UNUSED_VALUE(nextFrame);
762     GMX_UNUSED_VALUE(nBlocks);
763     GMX_UNUSED_VALUE(blockIds);
764     return FALSE;
765 #endif
766 }
767
768 gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t     input,
769                                                    gmx_int64_t          blockId,
770                                                    real               **values,
771                                                    gmx_int64_t         *frameNumber,
772                                                    double              *frameTime,
773                                                    gmx_int64_t         *nValuesPerFrame,
774                                                    gmx_int64_t         *nAtoms,
775                                                    real                *prec,
776                                                    char                *name,
777                                                    int                  maxLen,
778                                                    gmx_bool            *bOK)
779 {
780 #ifdef GMX_USE_TNG
781     tng_function_status stat;
782     char                datatype = -1;
783     gmx_int64_t         codecId;
784     int                 blockDependency;
785     void               *data = 0;
786     double              localPrec;
787
788     stat = tng_data_block_name_get(input, blockId, name, maxLen);
789     if (stat != TNG_SUCCESS)
790     {
791         gmx_file("Cannot read next frame of TNG file");
792     }
793     stat = tng_data_block_dependency_get(input, blockId, &blockDependency);
794     if (stat != TNG_SUCCESS)
795     {
796         gmx_file("Cannot read next frame of TNG file");
797     }
798     if (blockDependency & TNG_PARTICLE_DEPENDENT)
799     {
800         tng_num_particles_get(input, nAtoms);
801         stat = tng_util_particle_data_next_frame_read(input,
802                                                       blockId,
803                                                       &data,
804                                                       &datatype,
805                                                       frameNumber,
806                                                       frameTime);
807     }
808     else
809     {
810         *nAtoms = 1; /* There are not actually any atoms, but it is used for
811                         allocating memory */
812         stat    = tng_util_non_particle_data_next_frame_read(input,
813                                                              blockId,
814                                                              &data,
815                                                              &datatype,
816                                                              frameNumber,
817                                                              frameTime);
818     }
819     if (stat == TNG_CRITICAL)
820     {
821         gmx_file("Cannot read next frame of TNG file");
822     }
823     if (stat == TNG_FAILURE)
824     {
825         *bOK = TRUE;
826         return FALSE;
827     }
828
829     stat = tng_data_block_num_values_per_frame_get(input, blockId, nValuesPerFrame);
830     if (stat != TNG_SUCCESS)
831     {
832         gmx_file("Cannot read next frame of TNG file");
833     }
834     snew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms);
835     convert_array_to_real_array(data,
836                                 *values,
837                                 getDistanceScaleFactor(input),
838                                 *nAtoms,
839                                 *nValuesPerFrame,
840                                 datatype);
841
842     tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec);
843
844     /* This must be updated if/when more lossy compression methods are added */
845     if (codecId != TNG_TNG_COMPRESSION)
846     {
847         *prec = -1.0;
848     }
849     else
850     {
851         *prec = localPrec;
852     }
853
854     *bOK = TRUE;
855     return TRUE;
856 #else
857     GMX_UNUSED_VALUE(input);
858     GMX_UNUSED_VALUE(blockId);
859     GMX_UNUSED_VALUE(values);
860     GMX_UNUSED_VALUE(frameNumber);
861     GMX_UNUSED_VALUE(frameTime);
862     GMX_UNUSED_VALUE(nValuesPerFrame);
863     GMX_UNUSED_VALUE(nAtoms);
864     GMX_UNUSED_VALUE(prec);
865     GMX_UNUSED_VALUE(name);
866     GMX_UNUSED_VALUE(maxLen);
867     GMX_UNUSED_VALUE(bOK);
868     return FALSE;
869 #endif
870 }