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