Split essential dynamics eigenvector reading.
authorChristian Blau <cblau@gwdg.de>
Mon, 6 Aug 2018 06:46:12 +0000 (08:46 +0200)
committerChristian Blau <cblau@gwdg.de>
Wed, 8 Aug 2018 12:08:58 +0000 (14:08 +0200)
Split off input parameter reading in all t_eigvec from working memory
allocation for buffers or simulation state variables. Preparation to
splitting t_eigvec and t_edflood data structures in constant input
data, temporary buffers, and data describing the simulation state.

Moved the initialReferencePosition and referenceSlope out of t_eigvec
into t_edflood, because it is only used in flooding and is meaningless
for all other data structures using t_eigvec.

Part of #2590

Change-Id: Id01aeca97489a02a6ed7c7ed2789fd11b978a115

src/gromacs/essentialdynamics/edsam.cpp

index c4d16a0e3906bf153a51aeb2c12fe2ea3b0adf96..47a5489d00a13a6c69f20d116375eac8e97925f8 100644 (file)
@@ -98,9 +98,6 @@ typedef struct
     real   *fproj;   /* instantaneous f projections    */
     real    radius;  /* instantaneous radius           */
     real   *refproj; /* starting or target projections */
-    /* When using flooding as harmonic restraint: The current reference projection
-     * is at each step calculated from the initial refproj0 and the slope. */
-    real  *refproj0, *refprojslope;
 } t_eigvec;
 
 
@@ -132,6 +129,10 @@ typedef struct
     real     alpha2;
     rvec    *forces_cartesian;
     t_eigvec vecs;         /* use flooding for these */
+    /* When using flooding as harmonic restraint: The current reference projection
+     * is at each step calculated from the initial initialReferenceProjection and the slope. */
+    real  *initialReferenceProjection;
+    real  *referenceProjectionSlope;
 } t_edflood;
 
 
@@ -738,7 +739,7 @@ static void write_edo_flood(t_edpar *edi, FILE *fp, real rmsd)
         /* Check whether the reference projection changes with time (this can happen
          * in case flooding is used as harmonic restraint). If so, output the
          * current reference projection */
-        if (edi->flood.bHarmonic && edi->flood.vecs.refprojslope[i] != 0.0)
+        if (edi->flood.bHarmonic && edi->flood.referenceProjectionSlope[i] != 0.0)
         {
             fprintf(fp, EDcol_efmt, edi->flood.vecs.refproj[i]);
         }
@@ -783,7 +784,7 @@ static real flood_energy(t_edpar *edi, int64_t step)
     {
         for (i = 0; i < edi->flood.vecs.neig; i++)
         {
-            edi->flood.vecs.refproj[i] = edi->flood.vecs.refproj0[i] + step * edi->flood.vecs.refprojslope[i];
+            edi->flood.vecs.refproj[i] = edi->flood.initialReferenceProjection[i] + step * edi->flood.referenceProjectionSlope[i];
         }
     }
 
@@ -1233,7 +1234,7 @@ static void bc_ed_positions(const t_commrec *cr, struct gmx_edx *s, int stype)
 
 
 /* Broadcasts the eigenvector data */
-static void bc_ed_vecs(const t_commrec *cr, t_eigvec *ev, int length, gmx_bool bHarmonic)
+static void bc_ed_vecs(const t_commrec *cr, t_eigvec *ev, int length)
 {
     int i;
 
@@ -1256,14 +1257,6 @@ static void bc_ed_vecs(const t_commrec *cr, t_eigvec *ev, int length, gmx_bool b
         nblock_bc(cr, length, ev->vec[i]);
     }
 
-    /* For harmonic restraints the reference projections can change with time */
-    if (bHarmonic)
-    {
-        snew_bc(cr, ev->refproj0, ev->neig);
-        snew_bc(cr, ev->refprojslope, ev->neig);
-        nblock_bc(cr, ev->neig, ev->refproj0    );
-        nblock_bc(cr, ev->neig, ev->refprojslope);
-    }
 }
 
 
@@ -1293,14 +1286,24 @@ static void broadcast_ed_data(const t_commrec *cr, gmx_edsam * ed, int numedis)
         bc_ed_positions(cr, &(edi->sori), eedORI); /* origin positions                                */
 
         /* Broadcast eigenvectors */
-        bc_ed_vecs(cr, &edi->vecs.mon, edi->sav.nr, FALSE);
-        bc_ed_vecs(cr, &edi->vecs.linfix, edi->sav.nr, FALSE);
-        bc_ed_vecs(cr, &edi->vecs.linacc, edi->sav.nr, FALSE);
-        bc_ed_vecs(cr, &edi->vecs.radfix, edi->sav.nr, FALSE);
-        bc_ed_vecs(cr, &edi->vecs.radacc, edi->sav.nr, FALSE);
-        bc_ed_vecs(cr, &edi->vecs.radcon, edi->sav.nr, FALSE);
+        bc_ed_vecs(cr, &edi->vecs.mon, edi->sav.nr);
+        bc_ed_vecs(cr, &edi->vecs.linfix, edi->sav.nr);
+        bc_ed_vecs(cr, &edi->vecs.linacc, edi->sav.nr);
+        bc_ed_vecs(cr, &edi->vecs.radfix, edi->sav.nr);
+        bc_ed_vecs(cr, &edi->vecs.radacc, edi->sav.nr);
+        bc_ed_vecs(cr, &edi->vecs.radcon, edi->sav.nr);
         /* Broadcast flooding eigenvectors and, if needed, values for the moving reference */
-        bc_ed_vecs(cr, &edi->flood.vecs,  edi->sav.nr, edi->flood.bHarmonic);
+        bc_ed_vecs(cr, &edi->flood.vecs,  edi->sav.nr);
+
+        /* For harmonic restraints the reference projections can change with time */
+        if (edi->flood.bHarmonic)
+        {
+            snew_bc(cr, edi->flood.initialReferenceProjection, edi->flood.vecs.neig);
+            snew_bc(cr, edi->flood.referenceProjectionSlope, edi->flood.vecs.neig);
+            nblock_bc(cr, edi->flood.vecs.neig, edi->flood.initialReferenceProjection);
+            nblock_bc(cr, edi->flood.vecs.neig, edi->flood.referenceProjectionSlope);
+        }
+
 
         /* Set the pointer to the next ED group */
         if (edi->next_edi)
@@ -1470,111 +1473,140 @@ static void read_edx(FILE *file, int number, int *anrs, rvec *x)
     }
 }
 
-
-static void scan_edvec(FILE *in, int nr, rvec *vec)
+namespace
 {
-    char   line[STRLEN+1];
-    int    i;
-    double x, y, z;
-
-
-    for (i = 0; (i < nr); i++)
+/*!\brief Read eigenvector coordinates for multiple eigenvectors from a file.
+ * \param[in] in the file to read from
+ * \param[in] numAtoms the number of atoms/coordinates for the eigenvector
+ * \param[out] vec the eigen-vectors
+ * \param[in] nEig the number of eigenvectors
+ */
+void scan_edvec(FILE *in, int numAtoms, rvec ***vec, int nEig)
+{
+    snew(*vec, nEig);
+    for (int iEigenvector = 0; iEigenvector < nEig; iEigenvector++)
     {
-        fgets2 (line, STRLEN, in);
-        sscanf (line, max_ev_fmt_lelele, &x, &y, &z);
-        vec[i][XX] = x;
-        vec[i][YY] = y;
-        vec[i][ZZ] = z;
+        snew((*vec)[iEigenvector], numAtoms);
+        for (int iAtom = 0; iAtom < numAtoms; iAtom++)
+        {
+            char   line[STRLEN+1];
+            double x, y, z;
+            fgets2(line, STRLEN, in);
+            sscanf(line, max_ev_fmt_lelele, &x, &y, &z);
+            (*vec)[iEigenvector][iAtom][XX] = x;
+            (*vec)[iEigenvector][iAtom][YY] = y;
+            (*vec)[iEigenvector][iAtom][ZZ] = z;
+        }
     }
-}
-
 
-static void read_edvec(FILE *in, int nr, t_eigvec *tvec, gmx_bool bReadRefproj, gmx_bool *bHaveReference)
+}
+/*!\brief Read an essential dynamics eigenvector and corresponding step size.
+ * \param[in] in input file
+ * \param[in] nrAtoms number of atoms/coordinates
+ * \param[out] tvec the eigenvector
+ */
+void read_edvec(FILE *in, int nrAtoms, t_eigvec *tvec)
 {
-    int    i, idum, nscan;
-    double rdum, refproj_dum = 0.0, refprojslope_dum = 0.0;
-    char   line[STRLEN+1];
-
-
     tvec->neig = read_checked_edint(in, "NUMBER OF EIGENVECTORS");
-    if (tvec->neig > 0)
+    if (tvec->neig <= 0)
     {
-        snew(tvec->ieig, tvec->neig);
-        snew(tvec->stpsz, tvec->neig);
-        snew(tvec->vec, tvec->neig);
-        snew(tvec->xproj, tvec->neig);
-        snew(tvec->fproj, tvec->neig);
-        snew(tvec->refproj, tvec->neig);
-        if (bReadRefproj)
-        {
-            snew(tvec->refproj0, tvec->neig);
-            snew(tvec->refprojslope, tvec->neig);
-        }
-
-        for (i = 0; (i < tvec->neig); i++)
-        {
-            fgets2 (line, STRLEN, in);
-            if (bReadRefproj) /* ONLY when using flooding as harmonic restraint */
-            {
-                nscan = sscanf(line, max_ev_fmt_dlflflf, &idum, &rdum, &refproj_dum, &refprojslope_dum);
-                /* Zero out values which were not scanned */
-                switch (nscan)
-                {
-                    case 4:
-                        /* Every 4 values read, including reference position */
-                        *bHaveReference = TRUE;
-                        break;
-                    case 3:
-                        /* A reference position is provided */
-                        *bHaveReference = TRUE;
-                        /* No value for slope, set to 0 */
-                        refprojslope_dum = 0.0;
-                        break;
-                    case 2:
-                        /* No values for reference projection and slope, set to 0 */
-                        refproj_dum      = 0.0;
-                        refprojslope_dum = 0.0;
-                        break;
-                    default:
-                        gmx_fatal(FARGS, "Expected 2 - 4 (not %d) values for flooding vec: <nr> <spring const> <refproj> <refproj-slope>\n", nscan);
-                }
-                tvec->refproj[i]      = refproj_dum;
-                tvec->refproj0[i]     = refproj_dum;
-                tvec->refprojslope[i] = refprojslope_dum;
-            }
-            else /* Normal flooding */
-            {
-                nscan = sscanf(line, max_ev_fmt_dlf, &idum, &rdum);
-                if (nscan != 2)
-                {
-                    gmx_fatal(FARGS, "Expected 2 values for flooding vec: <nr> <stpsz>\n");
-                }
-            }
-            tvec->ieig[i]  = idum;
-            tvec->stpsz[i] = rdum;
-        } /* end of loop over eigenvectors */
+        return;
+    }
 
-        for (i = 0; (i < tvec->neig); i++)
+    snew(tvec->ieig, tvec->neig);
+    snew(tvec->stpsz, tvec->neig);
+    for (int i = 0; i < tvec->neig; i++)
+    {
+        char      line[STRLEN+1];
+        fgets2(line, STRLEN, in);
+        int       numEigenVectors;
+        double    stepSize;
+        const int nscan = sscanf(line, max_ev_fmt_dlf, &numEigenVectors, &stepSize);
+        if (nscan != 2)
         {
-            snew(tvec->vec[i], nr);
-            scan_edvec(in, nr, tvec->vec[i]);
+            gmx_fatal(FARGS, "Expected 2 values for flooding vec: <nr> <stpsz>\n");
         }
-    }
+        tvec->ieig[i]  = numEigenVectors;
+        tvec->stpsz[i] = stepSize;
+    }   /* end of loop over eigenvectors */
+
+    scan_edvec(in, nrAtoms, &tvec->vec, tvec->neig);
 }
+/*!\brief Read an essential dynamics eigenvector and intial reference projections and slopes if available.
+ *
+ * Eigenvector and its intial reference and slope are stored on the
+ * same line in the .edi format. To avoid re-winding the .edi file,
+ * the reference eigen-vector and reference data are read in one go.
+ *
+ * \param[in] in input file
+ * \param[in] nrAtoms number of atoms/coordinates
+ * \param[out] tvec the eigenvector
+ * \param[out] initialReferenceProjection The projection onto eigenvectors as read from file.
+ * \param[out] referenceProjectionSlope The slope of the reference projections.
+ */
+bool readEdVecWithReferenceProjection(FILE *in, int nrAtoms, t_eigvec *tvec, real ** initialReferenceProjection, real ** referenceProjectionSlope)
+{
+    bool providesReference = false;
+    tvec->neig = read_checked_edint(in, "NUMBER OF EIGENVECTORS");
+    if (tvec->neig <= 0)
+    {
+        return false;
+    }
 
+    snew(tvec->ieig, tvec->neig);
+    snew(tvec->stpsz, tvec->neig);
+    snew(*initialReferenceProjection, tvec->neig);
+    snew(*referenceProjectionSlope, tvec->neig);
+    for (int i = 0; i < tvec->neig; i++)
+    {
+        char      line[STRLEN+1];
+        fgets2 (line, STRLEN, in);
+        int       numEigenVectors;
+        double    stepSize            = 0.;
+        double    referenceProjection = 0.;
+        double    referenceSlope      = 0.;
+        const int nscan               = sscanf(line, max_ev_fmt_dlflflf, &numEigenVectors, &stepSize, &referenceProjection, &referenceSlope);
+        /* Zero out values which were not scanned */
+        switch (nscan)
+        {
+            case 4:
+                /* Every 4 values read, including reference position */
+                providesReference = true;
+                break;
+            case 3:
+                /* A reference position is provided */
+                providesReference = true;
+                /* No value for slope, set to 0 */
+                referenceSlope = 0.0;
+                break;
+            case 2:
+                /* No values for reference projection and slope, set to 0 */
+                referenceProjection = 0.0;
+                referenceSlope      = 0.0;
+                break;
+            default:
+                gmx_fatal(FARGS, "Expected 2 - 4 (not %d) values for flooding vec: <nr> <spring const> <refproj> <refproj-slope>\n", nscan);
+        }
+        (*initialReferenceProjection)[i]            = referenceProjection;
+        (*referenceProjectionSlope)[i]              = referenceSlope;
 
-/* calls read_edvec for the vector groups, only for flooding there is an extra call */
-static void read_edvecs(FILE *in, int nr, t_edvecs *vecs)
-{
-    gmx_bool bHaveReference = FALSE;
+        tvec->ieig[i]  = numEigenVectors;
+        tvec->stpsz[i] = stepSize;
+    }   /* end of loop over eigenvectors */
 
+    scan_edvec(in, nrAtoms, &tvec->vec, tvec->neig);
+    return providesReference;
+}
 
-    read_edvec(in, nr, &vecs->mon, FALSE, &bHaveReference);
-    read_edvec(in, nr, &vecs->linfix, FALSE, &bHaveReference);
-    read_edvec(in, nr, &vecs->linacc, FALSE, &bHaveReference);
-    read_edvec(in, nr, &vecs->radfix, FALSE, &bHaveReference);
-    read_edvec(in, nr, &vecs->radacc, FALSE, &bHaveReference);
-    read_edvec(in, nr, &vecs->radcon, FALSE, &bHaveReference);
+/*!\brief Allocate working memory for the eigenvectors.
+ * \param[in,out] tvec eigenvector for which memory will be allocated
+ */
+void setup_edvec(t_eigvec *tvec)
+{
+    snew(tvec->xproj, tvec->neig);
+    snew(tvec->fproj, tvec->neig);
+    snew(tvec->refproj, tvec->neig);
+}
 }
 
 
@@ -1631,6 +1663,14 @@ void setup_edi(t_edpar *edi)
     {
         edi->sori.sqrtm    = nullptr;
     }
+    setup_edvec(&edi->vecs.linacc);
+    setup_edvec(&edi->vecs.mon);
+    setup_edvec(&edi->vecs.linfix);
+    setup_edvec(&edi->vecs.linacc);
+    setup_edvec(&edi->vecs.radfix);
+    setup_edvec(&edi->vecs.radacc);
+    setup_edvec(&edi->vecs.radcon);
+    setup_edvec(&edi->flood.vecs);
 }
 
 /*!\brief Check if edi file version supports CONST_FORCE_FLOODING.
@@ -1687,9 +1727,6 @@ void exitWhenMagicNumberIsInvalid(int magicNumber, const char * fn)
  */
 void read_edi(FILE* in, t_edpar *edi, int nr_mdatoms, bool hasConstForceFlooding, const char *fn)
 {
-    /* Was a specific reference point for the flooding/umbrella potential provided in the edi file? */
-    gmx_bool  bHaveReference = FALSE;
-
     bool      bEOF;
     /* check the number of atoms */
     edi->nini = read_edint(in, &bEOF);
@@ -1738,8 +1775,24 @@ void read_edi(FILE* in, t_edpar *edi, int nr_mdatoms, bool hasConstForceFlooding
     edi->bRefEqAv = check_if_same(edi->sref, edi->sav);
 
     /* eigenvectors */
-    read_edvecs(in, edi->sav.nr, &edi->vecs);
-    read_edvec(in, edi->sav.nr, &edi->flood.vecs, edi->flood.bHarmonic, &bHaveReference);
+
+    read_edvec(in, edi->sav.nr, &edi->vecs.mon);
+    read_edvec(in, edi->sav.nr, &edi->vecs.linfix);
+    read_edvec(in, edi->sav.nr, &edi->vecs.linacc);
+    read_edvec(in, edi->sav.nr, &edi->vecs.radfix);
+    read_edvec(in, edi->sav.nr, &edi->vecs.radacc);
+    read_edvec(in, edi->sav.nr, &edi->vecs.radcon);
+
+    /* Was a specific reference point for the flooding/umbrella potential provided in the edi file? */
+    bool  bHaveReference = false;
+    if (edi->flood.bHarmonic)
+    {
+        bHaveReference = readEdVecWithReferenceProjection(in, edi->sav.nr, &edi->flood.vecs, &edi->flood.initialReferenceProjection, &edi->flood.referenceProjectionSlope);
+    }
+    else
+    {
+        read_edvec(in, edi->sav.nr, &edi->flood.vecs);
+    }
 
     /* target positions */
     edi->star.nr = read_edint(in, &bEOF);
@@ -2300,21 +2353,21 @@ static int ed_constraints(int edtype, t_edpar *edi)
 }
 
 
-/* Copies reference projection 'refproj' to fixed 'refproj0' variable for flooding/
+/* Copies reference projection 'refproj' to fixed 'initialReferenceProjection' variable for flooding/
  * umbrella sampling simulations. */
-static void copyEvecReference(t_eigvec* floodvecs)
+static void copyEvecReference(t_eigvec* floodvecs, real * initialReferenceProjection)
 {
     int i;
 
 
-    if (nullptr == floodvecs->refproj0)
+    if (nullptr == initialReferenceProjection)
     {
-        snew(floodvecs->refproj0, floodvecs->neig);
+        snew(initialReferenceProjection, floodvecs->neig);
     }
 
     for (i = 0; i < floodvecs->neig; i++)
     {
-        floodvecs->refproj0[i] = floodvecs->refproj[i];
+        initialReferenceProjection[i] = floodvecs->refproj[i];
     }
 }
 
@@ -2570,7 +2623,7 @@ static void write_edo_legend(gmx_edsam * ed, int nED, const gmx_output_env_t *oe
 
                 /* Output the current reference projection if it changes with time;
                  * this can happen when flooding is used as harmonic restraint */
-                if (edi->flood.bHarmonic && edi->flood.vecs.refprojslope[i] != 0.0)
+                if (edi->flood.bHarmonic && edi->flood.referenceProjectionSlope[i] != 0.0)
                 {
                     sprintf(buf, "EV%d ref.prj.", edi->flood.vecs.ieig[i]);
                     nice_legend(&setname, &nsets, &LegendStr, buf, "nm", get_EDgroupChar(nr_edi, nED));
@@ -2860,7 +2913,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
                     rad_project(edi, &edi->sori.x[avindex], &edi->flood.vecs);
                     /* We already know that no (moving) reference position was provided,
                      * therefore we can overwrite refproj[0]*/
-                    copyEvecReference(&edi->flood.vecs);
+                    copyEvecReference(&edi->flood.vecs, edi->flood.initialReferenceProjection);
                 }
             }
             else /* No origin structure given */
@@ -2874,7 +2927,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
                         fprintf(stderr, "ED: A (possibly changing) ref. projection will define the flooding potential center.\n");
                         for (i = 0; i < edi->flood.vecs.neig; i++)
                         {
-                            edi->flood.vecs.refproj[i] = edi->flood.vecs.refproj0[i];
+                            edi->flood.vecs.refproj[i] = edi->flood.initialReferenceProjection[i];
                         }
                     }
                     else
@@ -2897,7 +2950,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
                     fprintf(stdout, "ED: EV %d flooding potential center: %11.4e", edi->flood.vecs.ieig[i], edi->flood.vecs.refproj[i]);
                     if (edi->flood.bHarmonic)
                     {
-                        fprintf(stdout, " (adding %11.4e/timestep)", edi->flood.vecs.refprojslope[i]);
+                        fprintf(stdout, " (adding %11.4e/timestep)", edi->flood.referenceProjectionSlope[i]);
                     }
                     fprintf(stdout, "\n");
                 }