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