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