Write forces and velocities to compressed TNG.
authorMagnus Lundborg <lundborg.magnus@gmail.com>
Thu, 26 Nov 2015 10:50:59 +0000 (11:50 +0100)
committerDavid van der Spoel <davidvanderspoel@gmail.com>
Sat, 5 Dec 2015 23:23:03 +0000 (00:23 +0100)
If there is no uncompressed coordinate output write forces
and velocities to the TNG file with compressed coordinate
output. If there is uncompressed coordinate output to a
TNG file forces and velocities will be written to it.

Use a greatest common divisor to set the frequency of some TNG
data output to ensure lambdas and box shape are written at least
as often as anything else.

This commit closes #1863.

Change-Id: I61bb5513f5080847f9098ff4fd7f01c8d1415a8f

src/gromacs/fileio/tngio.cpp
src/gromacs/mdlib/mdoutf.cpp

index 7976fdbe3dbc6d7e968cf8be38dc74a079a04df3..cf21019a55d318a46853852a53b83ffbba2be56b 100644 (file)
@@ -372,7 +372,7 @@ static void set_writing_intervals(tng_trajectory_t  tng,
     set_writing_interval_func_pointer set_writing_interval = tng_util_generic_write_interval_set;
 #endif
     int  xout, vout, fout;
-//     int  gcd = -1, lowest = -1;
+    int  gcd = -1, lowest = -1;
     char compression;
 
     tng_set_frames_per_frame_set(tng, bUseLossyCompression, ir);
@@ -380,8 +380,19 @@ static void set_writing_intervals(tng_trajectory_t  tng,
     if (bUseLossyCompression)
     {
         xout        = ir->nstxout_compressed;
-        vout        = 0;
-        fout        = 0;
+
+        /* If there is no uncompressed coordinate output write forces
+           and velocities to the compressed tng file. */
+        if (ir->nstxout)
+        {
+            vout        = 0;
+            fout        = 0;
+        }
+        else
+        {
+            vout        = ir->nstvout;
+            fout        = ir->nstfout;
+        }
         compression = TNG_TNG_COMPRESSION;
     }
     else
@@ -396,34 +407,17 @@ static void set_writing_intervals(tng_trajectory_t  tng,
         set_writing_interval(tng, xout, 3, TNG_TRAJ_POSITIONS,
                              "POSITIONS", TNG_PARTICLE_BLOCK_DATA,
                              compression);
-        /* The design of TNG makes it awkward to try to write a box
-         * with multiple periodicities, which might be co-prime. Since
-         * the use cases for the box with a frame consisting only of
-         * velocities seem low, for now we associate box writing with
-         * position writing. */
-        set_writing_interval(tng, xout, 9, TNG_TRAJ_BOX_SHAPE,
-                             "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA,
-                             TNG_GZIP_COMPRESSION);
         /* TODO: if/when we write energies to TNG also, reconsider how
          * and when box information is written, because GROMACS
          * behaviour pre-5.0 was to write the box with every
          * trajectory frame and every energy frame, and probably
          * people depend on this. */
 
-        /* TODO: If we need to write lambda values at steps when
-         * positions (or other data) are not also being written, then
-         * code in mdoutf.c will need to match however that is
-         * organized here. */
-        set_writing_interval(tng, xout, 1, TNG_GMX_LAMBDA,
-                             "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
-                             TNG_GZIP_COMPRESSION);
-
-        /* FIXME: gcd and lowest currently not used. */
-//         gcd = greatest_common_divisor_if_positive(gcd, xout);
-//         if (lowest < 0 || xout < lowest)
-//         {
-//             lowest = xout;
-//         }
+        gcd = greatest_common_divisor_if_positive(gcd, xout);
+        if (lowest < 0 || xout < lowest)
+        {
+            lowest = xout;
+        }
     }
     if (vout)
     {
@@ -431,12 +425,11 @@ static void set_writing_intervals(tng_trajectory_t  tng,
                              "VELOCITIES", TNG_PARTICLE_BLOCK_DATA,
                              compression);
 
-        /* FIXME: gcd and lowest currently not used. */
-//         gcd = greatest_common_divisor_if_positive(gcd, vout);
-//         if (lowest < 0 || vout < lowest)
-//         {
-//             lowest = vout;
-//         }
+        gcd = greatest_common_divisor_if_positive(gcd, vout);
+        if (lowest < 0 || vout < lowest)
+        {
+            lowest = vout;
+        }
     }
     if (fout)
     {
@@ -444,29 +437,30 @@ static void set_writing_intervals(tng_trajectory_t  tng,
                              "FORCES", TNG_PARTICLE_BLOCK_DATA,
                              TNG_GZIP_COMPRESSION);
 
-        /* FIXME: gcd and lowest currently not used. */
-//         gcd = greatest_common_divisor_if_positive(gcd, fout);
-//         if (lowest < 0 || fout < lowest)
-//         {
-//             lowest = fout;
-//         }
-    }
-    /* FIXME: See above. gcd interval for lambdas is disabled. */
-//     if (gcd > 0)
-//     {
-//         /* Lambdas written at an interval of the lowest common denominator
-//          * of other output */
-//         set_writing_interval(tng, gcd, 1, TNG_GMX_LAMBDA,
-//                                  "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
-//                                  TNG_GZIP_COMPRESSION);
-//
-//         if (gcd < lowest / 10)
-//         {
-//             gmx_warning("The lowest common denominator of trajectory output is "
-//                         "every %d step(s), whereas the shortest output interval "
-//                         "is every %d steps.", gcd, lowest);
-//         }
-//     }
+        gcd = greatest_common_divisor_if_positive(gcd, fout);
+        if (lowest < 0 || fout < lowest)
+        {
+            lowest = fout;
+        }
+    }
+    if (gcd > 0)
+    {
+        /* Lambdas and box shape written at an interval of the lowest common
+           denominator of other output */
+        set_writing_interval(tng, gcd, 1, TNG_GMX_LAMBDA,
+                             "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA,
+                             TNG_GZIP_COMPRESSION);
+
+        set_writing_interval(tng, gcd, 9, TNG_TRAJ_BOX_SHAPE,
+                             "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA,
+                             TNG_GZIP_COMPRESSION);
+        if (gcd < lowest / 10)
+        {
+            gmx_warning("The lowest common denominator of trajectory output is "
+                        "every %d step(s), whereas the shortest output interval "
+                        "is every %d steps.", gcd, lowest);
+        }
+    }
 }
 #endif
 
@@ -782,16 +776,6 @@ void gmx_fwrite_tng(tng_trajectory_t tng,
         {
             gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
         }
-        /* TNG-MF1 compression only compresses positions and velocities. Use lossless
-         * compression for box shape regardless of output mode */
-        if (write_data(tng, step, elapsedSeconds,
-                       reinterpret_cast<const real *>(box),
-                       9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
-                       TNG_NON_PARTICLE_BLOCK_DATA,
-                       TNG_GZIP_COMPRESSION) != TNG_SUCCESS)
-        {
-            gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
-        }
     }
 
     if (v)
@@ -821,7 +805,16 @@ void gmx_fwrite_tng(tng_trajectory_t tng,
     }
 
     /* TNG-MF1 compression only compresses positions and velocities. Use lossless
-     * compression for lambdas regardless of output mode */
+     * compression for lambdas and box shape regardless of output mode */
+    if (write_data(tng, step, elapsedSeconds,
+                   reinterpret_cast<const real *>(box),
+                   9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
+                   TNG_NON_PARTICLE_BLOCK_DATA,
+                   TNG_GZIP_COMPRESSION) != TNG_SUCCESS)
+    {
+        gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?");
+    }
+
     if (write_data(tng, step, elapsedSeconds,
                    reinterpret_cast<const real *>(&lambda),
                    1, TNG_GMX_LAMBDA, "LAMBDAS",
index df1ef1f40989a10366784778814cfa82e52739eb..96b6bd6528f68066777edf7d8e792aa30f6cbbf0 100644 (file)
@@ -112,6 +112,28 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
 
         sprintf(filemode, bAppendFiles ? "a+" : "w+");
 
+        if (EI_DYNAMICS(ir->eI) &&
+            ir->nstxout_compressed > 0)
+        {
+            const char *filename;
+            filename = ftp2fn(efCOMPRESSED, nfile, fnm);
+            switch (fn2ftp(filename))
+            {
+                case efXTC:
+                    of->fp_xtc                  = open_xtc(filename, filemode);
+                    break;
+                case efTNG:
+                    gmx_tng_open(filename, filemode[0], &of->tng_low_prec);
+                    if (filemode[0] == 'w')
+                    {
+                        gmx_tng_prepare_low_prec_writing(of->tng_low_prec, top_global, ir);
+                    }
+                    bCiteTng = TRUE;
+                    break;
+                default:
+                    gmx_incons("Invalid reduced precision file format");
+            }
+        }
         if ((EI_DYNAMICS(ir->eI) || EI_ENERGY_MINIMIZATION(ir->eI))
 #ifndef GMX_FAHCORE
             &&
@@ -128,7 +150,14 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
             {
                 case efTRR:
                 case efTRN:
-                    of->fp_trn = gmx_trr_open(filename, filemode);
+                    /* If there is no uncompressed coordinate output and
+                       there is compressed TNG output write forces
+                       and/or velocities to the TNG file instead. */
+                    if (ir->nstxout != 0 || ir->nstxout_compressed == 0 ||
+                        !of->tng_low_prec)
+                    {
+                        of->fp_trn = gmx_trr_open(filename, filemode);
+                    }
                     break;
                 case efTNG:
                     gmx_tng_open(filename, filemode[0], &of->tng);
@@ -142,28 +171,6 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
                     gmx_incons("Invalid full precision file format");
             }
         }
-        if (EI_DYNAMICS(ir->eI) &&
-            ir->nstxout_compressed > 0)
-        {
-            const char *filename;
-            filename = ftp2fn(efCOMPRESSED, nfile, fnm);
-            switch (fn2ftp(filename))
-            {
-                case efXTC:
-                    of->fp_xtc                  = open_xtc(filename, filemode);
-                    break;
-                case efTNG:
-                    gmx_tng_open(filename, filemode[0], &of->tng_low_prec);
-                    if (filemode[0] == 'w')
-                    {
-                        gmx_tng_prepare_low_prec_writing(of->tng_low_prec, top_global, ir);
-                    }
-                    bCiteTng = TRUE;
-                    break;
-                default:
-                    gmx_incons("Invalid reduced precision file format");
-            }
-        }
         if (EI_DYNAMICS(ir->eI) || EI_ENERGY_MINIMIZATION(ir->eI))
         {
             of->fp_ene = open_enx(ftp2fn(efEDR, nfile, fnm), filemode);
@@ -333,12 +340,28 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
                 }
             }
 
-            gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
-                           state_local->box,
-                           top_global->natoms,
-                           (mdof_flags & MDOF_X) ? state_global->x : NULL,
-                           (mdof_flags & MDOF_V) ? global_v : NULL,
-                           (mdof_flags & MDOF_F) ? f_global : NULL);
+            /* If a TNG file is open for uncompressed coordinate output also write
+               velocities and forces to it. */
+            else if (of->tng)
+            {
+                gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
+                               state_local->box,
+                               top_global->natoms,
+                               (mdof_flags & MDOF_X) ? state_global->x : NULL,
+                               (mdof_flags & MDOF_V) ? global_v : NULL,
+                               (mdof_flags & MDOF_F) ? f_global : NULL);
+            }
+            /* If only a TNG file is open for compressed coordinate output (no uncompressed
+               coordinate output) also write forces and velocities to it. */
+            else if (of->tng_low_prec)
+            {
+                gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, state_local->lambda[efptFEP],
+                               state_local->box,
+                               top_global->natoms,
+                               (mdof_flags & MDOF_X) ? state_global->x : NULL,
+                               (mdof_flags & MDOF_V) ? global_v : NULL,
+                               (mdof_flags & MDOF_F) ? f_global : NULL);
+            }
         }
         if (mdof_flags & MDOF_X_COMPRESSED)
         {