LCOV - code coverage report
Current view: top level - molfile - gromacsplugin.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 107 360 29.7 %
Date: 2024-10-18 14:00:27 Functions: 5 23 21.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             : University of Illinois Open Source License
       3             : Copyright 2003 Theoretical and Computational Biophysics Group, 
       4             : All rights reserved.
       5             : 
       6             : Developed by:           Theoretical and Computational Biophysics Group
       7             :                         University of Illinois at Urbana-Champaign
       8             :                         http://www.ks.uiuc.edu/
       9             : 
      10             : Permission is hereby granted, free of charge, to any person obtaining a copy of
      11             : this software and associated documentation files (the Software), to deal with 
      12             : the Software without restriction, including without limitation the rights to 
      13             : use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
      14             : of the Software, and to permit persons to whom the Software is furnished to 
      15             : do so, subject to the following conditions:
      16             : 
      17             : Redistributions of source code must retain the above copyright notice, 
      18             : this list of conditions and the following disclaimers.
      19             : 
      20             : Redistributions in binary form must reproduce the above copyright notice, 
      21             : this list of conditions and the following disclaimers in the documentation 
      22             : and/or other materials provided with the distribution.
      23             : 
      24             : Neither the names of Theoretical and Computational Biophysics Group, 
      25             : University of Illinois at Urbana-Champaign, nor the names of its contributors 
      26             : may be used to endorse or promote products derived from this Software without 
      27             : specific prior written permission.
      28             : 
      29             : THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
      30             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
      31             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
      32             : THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
      33             : OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
      34             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
      35             : OTHER DEALINGS WITH THE SOFTWARE.
      36             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      37             : #if defined(__PLUMED_HAS_MOLFILE_PLUGINS) && ! defined(__PLUMED_HAS_EXTERNAL_MOLFILE_PLUGINS)
      38             : /***************************************************************************
      39             :  *cr
      40             :  *cr            (C) Copyright 1995-2016 The Board of Trustees of the
      41             :  *cr                        University of Illinois
      42             :  *cr                         All Rights Reserved
      43             :  *cr
      44             :  ***************************************************************************/
      45             : 
      46             : /***************************************************************************
      47             :  * RCS INFORMATION:
      48             :  *
      49             :  *      $RCSfile: gromacsplugin.C,v $
      50             :  *      $Author: johns $       $Locker:  $             $State: Exp $
      51             :  *      $Revision: 1.54 $       $Date: 2017/05/20 05:37:53 $
      52             :  *
      53             :  ***************************************************************************/
      54             : 
      55             : #include "largefiles.h"   /* platform dependent 64-bit file I/O defines */
      56             : 
      57             : #include <math.h>
      58             : #include <stdio.h>
      59             : #include <stdlib.h>
      60             : #include <string.h>
      61             : #include <ctype.h>
      62             : #include "Gromacs.h"
      63             : #include "molfile_plugin.h"
      64             : 
      65             : #if defined(_AIX)
      66             : #include <strings.h>
      67             : #endif
      68             : 
      69             : namespace PLMD{
      70             : namespace molfile{
      71             : 
      72             : #ifndef M_PI
      73             : #define M_PI           3.14159265358979323846
      74             : #endif
      75             : 
      76             : #if defined(WIN32) || defined(WIN64)
      77             : #define strcasecmp stricmp
      78             : #endif
      79             : 
      80             : typedef struct {
      81             :   md_file *mf;
      82             :   int natoms;
      83             :   int step;
      84             :   float timeval;
      85             :   molfile_atom_t *atomlist;
      86             :   molfile_metadata_t *meta;
      87             : } gmxdata;
      88             : 
      89           0 : static void convert_vmd_box_for_writing(const molfile_timestep_t *ts, float *x, float *y, float *z)
      90             : {
      91             : //     const float sa = sin((double)ts->alpha/180.0*M_PI);
      92           0 :     const float ca = cos((double)ts->alpha/180.0*M_PI);
      93           0 :     const float cb = cos((double)ts->beta/180.0*M_PI);
      94           0 :     const float cg = cos((double)ts->gamma/180.0*M_PI);
      95           0 :     const float sg = sin((double)ts->gamma/180.0*M_PI);
      96             : 
      97           0 :     x[0] = ts->A / ANGS_PER_NM;
      98           0 :     y[0] = 0.0;
      99           0 :     z[0] = 0.0;
     100           0 :     x[1] = ts->B*cg / ANGS_PER_NM; // ts->B*ca when writing trr?!
     101           0 :     y[1] = ts->B*sg / ANGS_PER_NM; // ts->B*sa when writing trr?!
     102           0 :     z[1] = 0.0;
     103           0 :     x[2] = ts->C*cb / ANGS_PER_NM;
     104           0 :     y[2] = (ts->C / ANGS_PER_NM)*(ca - cb*cg)/sg;
     105           0 :     z[2] = (ts->C / ANGS_PER_NM)*sqrt((double)(1.0 + 2.0*ca*cb*cg
     106           0 :                                - ca*ca - cb*cb - cg*cg)/(1.0 - cg*cg));
     107           0 : }
     108             : 
     109           0 : static void *open_gro_read(const char *filename, const char *,
     110             :     int *natoms) {
     111             : 
     112             :     md_file *mf;
     113             :     md_header mdh;
     114             :     gmxdata *gmx;
     115             : 
     116           0 :     mf = mdio_open(filename, MDFMT_GRO);
     117           0 :     if (!mf) {
     118           0 :         fprintf(stderr, "gromacsplugin) Cannot open file '%s', %s\n",
     119             :                 filename, mdio_errmsg(mdio_errno()));
     120           0 :         return NULL;
     121             :     }
     122             : 
     123             :     // read in the header data (careful not to rewind!)
     124           0 :     if (gro_header(mf, mdh.title, MAX_MDIO_TITLE,
     125             :     &mdh.timeval, &mdh.natoms, 0) < 0) {
     126           0 :         fprintf(stderr, "gromacsplugin) Cannot read header fromm '%s', %s\n",
     127             :                 filename, mdio_errmsg(mdio_errno()));
     128             :             // XXX should free the file handle...
     129           0 :         return NULL;
     130             :     }
     131           0 :     *natoms = mdh.natoms;
     132           0 :     gmx = new gmxdata;
     133             :     memset(gmx,0,sizeof(gmxdata));
     134           0 :     gmx->mf = mf;
     135           0 :     gmx->natoms = mdh.natoms;
     136           0 :     gmx->meta = new molfile_metadata_t;
     137             :     memset(gmx->meta,0,sizeof(molfile_metadata_t));
     138           0 :     strncpy(gmx->meta->title, mdh.title, 80);
     139           0 :     gmx->timeval = mdh.timeval;
     140           0 :     return gmx;
     141             : }
     142             : 
     143           0 : static int read_gro_structure(void *mydata, int *optflags,
     144             :     molfile_atom_t *atoms) {
     145             : 
     146             :   md_atom ma;
     147             :   char buf[MAX_GRO_LINE + 1];
     148             :   gmxdata *gmx = (gmxdata *)mydata;
     149             : 
     150           0 :   *optflags = MOLFILE_NOOPTIONS; // no optional data
     151             : 
     152             :   // read in each atom and add it into the molecule
     153           0 :   for (int i = 0; i < gmx->natoms; i++) {
     154           0 :     molfile_atom_t *atom = atoms+i;
     155           0 :     if (gro_rec(gmx->mf, &ma) < 0) {
     156           0 :       fprintf(stderr, "gromacsplugin) Error reading atom %d from file, %s\n",
     157             :               i+1, mdio_errmsg(mdio_errno()));
     158           0 :       return MOLFILE_ERROR;
     159             :     }
     160           0 :     strcpy(atom->name, ma.atomname);
     161           0 :     strcpy(atom->type, ma.atomname);
     162           0 :     strcpy(atom->resname, ma.resname);
     163           0 :     atom->resid = atoi(ma.resid);
     164           0 :     atom->chain[0] = '\0';
     165           0 :     atom->segid[0] = '\0';
     166             :   }
     167             : 
     168           0 :   if (mdio_readline(gmx->mf, buf, MAX_GRO_LINE + 1, 0) < 0) {
     169           0 :     fprintf(stderr, "gromacsplugin) Warning, error reading box, %s\n",
     170             :             mdio_errmsg(mdio_errno()));
     171             :   }
     172             : 
     173           0 :   rewind(gmx->mf->f);
     174             :   return MOLFILE_SUCCESS;
     175             : }
     176             : 
     177           0 : static int read_gro_molecule_metadata(void *v, molfile_metadata_t **metadata) {
     178             :   gmxdata *gmx = (gmxdata *)v;
     179           0 :   *metadata = gmx->meta;
     180           0 :   return MOLFILE_SUCCESS;
     181             : }
     182             : 
     183           0 : static int read_gro_timestep(void *v, int natoms, molfile_timestep_t *ts) {
     184             :   gmxdata *gmx = (gmxdata *)v;
     185             :   md_ts mdts;
     186             :   memset(&mdts, 0, sizeof(md_ts));
     187           0 :   mdts.natoms = natoms;
     188             : 
     189           0 :   if (mdio_timestep(gmx->mf, &mdts) < 0)
     190             :     return MOLFILE_ERROR;
     191           0 :   if (ts) {
     192           0 :     memcpy(ts->coords, mdts.pos, 3 * sizeof(float) * gmx->natoms);
     193           0 :     if (mdts.box) {
     194           0 :       ts->A = mdts.box->A;
     195           0 :       ts->B = mdts.box->B;
     196           0 :       ts->C = mdts.box->C;
     197           0 :       ts->alpha = mdts.box->alpha;
     198           0 :       ts->beta = mdts.box->beta;
     199           0 :       ts->gamma = mdts.box->gamma;
     200             :     }
     201             :   }
     202           0 :   mdio_tsfree(&mdts);
     203           0 :   return MOLFILE_SUCCESS;
     204             : }
     205             : 
     206           0 : static void close_gro_read(void *v) {
     207             :   gmxdata *gmx = (gmxdata *)v;
     208           0 :   mdio_close(gmx->mf);
     209           0 :   delete gmx->meta;
     210           0 :   delete gmx;
     211           0 : }
     212             : 
     213             : // open file for writing
     214           0 : static void *open_gro_write(const char *filename, const char *filetype,
     215             :     int natoms) {
     216             : 
     217             :     md_file *mf;
     218             :     gmxdata *gmx;
     219             : 
     220           0 :     mf = mdio_open(filename, MDFMT_GRO, MDIO_WRITE);
     221           0 :     if (!mf) {
     222           0 :         fprintf(stderr, "gromacsplugin) Cannot open file '%s', %s\n",
     223             :                 filename, mdio_errmsg(mdio_errno()));
     224           0 :         return NULL;
     225             :     }
     226           0 :     gmx = new gmxdata;
     227             :     memset(gmx,0,sizeof(gmxdata));
     228           0 :     gmx->mf = mf;
     229           0 :     gmx->natoms = natoms;
     230             :     gmx->step   = 0;
     231           0 :     gmx->meta = new molfile_metadata_t;
     232             :     memset(gmx->meta,0,sizeof(molfile_metadata_t));
     233             :     gmx->meta->title[0] = '\0';
     234             : 
     235           0 :     return gmx;
     236             : }
     237             : 
     238           0 : static int write_gro_structure(void *v, int optflags,
     239             :     const molfile_atom_t *atoms) {
     240             : 
     241             :   gmxdata *gmx = (gmxdata *)v;
     242           0 :   int natoms = gmx->natoms;
     243           0 :   gmx->atomlist = (molfile_atom_t *)malloc(natoms*sizeof(molfile_atom_t));
     244             :   memcpy(gmx->atomlist, atoms, natoms*sizeof(molfile_atom_t));
     245             : 
     246           0 :   return MOLFILE_SUCCESS;
     247             : }
     248             : 
     249           0 : static int write_gro_timestep(void *v, const molfile_timestep_t *ts) {
     250             :   gmxdata *gmx = (gmxdata *)v;
     251             :   const molfile_atom_t *atom;
     252             :   const float *pos, *vel;
     253             :   float x[3], y[3], z[3];
     254             :   int i;
     255             : 
     256           0 :   if (gmx->natoms == 0)
     257             :     return MOLFILE_SUCCESS;
     258             : 
     259           0 :   atom = gmx->atomlist;
     260           0 :   pos = ts->coords;
     261           0 :   vel = ts->velocities;
     262             : 
     263             :   /* The title cannot be written */
     264             : /*  fprintf(gmx->mf->f, "%s", gmx->meta->title);*/
     265             :   /* Write a dummy title instead */
     266           0 :   fprintf(gmx->mf->f, "generated by VMD");
     267             : #if vmdplugin_ABIVERSION > 10
     268           0 :   fprintf(gmx->mf->f, ", t= %f", ts->physical_time);
     269             : #endif
     270           0 :   fprintf(gmx->mf->f, "\n");
     271             : 
     272           0 :   fprintf(gmx->mf->f, "%d\n", gmx->natoms);
     273           0 :   for (i=0; i<gmx->natoms; i++)
     274             :   {
     275           0 :      fprintf(gmx->mf->f, "%5d%-5s%5s%5d%8.3f%8.3f%8.3f",
     276           0 :              atom->resid, atom->resname, atom->name,
     277           0 :              (i+1) % 100000, // GRO format only supports indices up to 99999
     278             :                              // but since GROMACS ignores indices, modular
     279             :                              // arithmetic prevents formatting problems for 
     280             :                              // very large structures
     281           0 :              pos[0] / ANGS_PER_NM, pos[1] / ANGS_PER_NM, pos[2] / ANGS_PER_NM);
     282           0 :      if(vel)
     283             :      {
     284           0 :          fprintf(gmx->mf->f, "%8.4f%8.4f%8.4f", vel[0] / ANGS_PER_NM, vel[1] / ANGS_PER_NM, vel[2] / ANGS_PER_NM);
     285           0 :          vel += 3;
     286             :      }
     287           0 :      fprintf(gmx->mf->f, "\n");
     288           0 :      ++atom;
     289           0 :      pos += 3;
     290             :   }
     291           0 :   convert_vmd_box_for_writing(ts, x, y, z);
     292           0 :   fprintf(gmx->mf->f, "%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f%10.5f\n", x[0], y[1], z[2], y[0], z[0], x[1], z[1], x[2], y[2]);
     293             : 
     294             :   return MOLFILE_SUCCESS;
     295             : }
     296             : 
     297           0 : static void close_gro_write(void *v) {
     298             :   gmxdata *gmx = (gmxdata *)v;
     299           0 :   mdio_close(gmx->mf);
     300           0 :   free(gmx->atomlist);
     301           0 :   delete gmx->meta;
     302           0 :   delete gmx;
     303           0 : }
     304             : 
     305             : 
     306           0 : static void *open_g96_read(const char *filename, const char *,
     307             :     int *natoms) {
     308             : 
     309             :     md_file *mf;
     310             :     md_header mdh;
     311             :     char gbuf[MAX_G96_LINE + 1];
     312             : 
     313           0 :     mf = mdio_open(filename, MDFMT_G96);
     314           0 :     if (!mf) {
     315           0 :         fprintf(stderr, "gromacsplugin) Cannot open file '%s', %s\n",
     316             :                 filename, mdio_errmsg(mdio_errno()));
     317           0 :         return NULL;
     318             :     }
     319             : 
     320             :         // read in the header data
     321           0 :         if (g96_header(mf, mdh.title, MAX_MDIO_TITLE, &mdh.timeval) < 0) {
     322           0 :             fprintf(stderr, "gromacsplugin) Cannot read header from '%s', %s\n",
     323             :                     filename, mdio_errmsg(mdio_errno()));
     324           0 :             return NULL;
     325             :         }
     326             : 
     327             :         // First, look for a timestep block
     328           0 :         if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0) {
     329           0 :             fprintf(stderr, "gromacsplugin) Cannot read header from '%s', %s\n",
     330             :                     filename, mdio_errmsg(mdio_errno()));
     331           0 :             return NULL;
     332             :         }
     333           0 :         if (!strcasecmp(gbuf, "TIMESTEP")) {
     334             :             // Read in the value line and the END line, and the next
     335           0 :             if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0 ||
     336           0 :                 mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0 ||
     337           0 :                 mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0) {
     338           0 :               fprintf(stderr, "gromacsplugin) Cannot read header from '%s', %s\n",
     339             :                       filename, mdio_errmsg(mdio_errno()));
     340           0 :               return NULL;
     341             :             }
     342             :         }
     343           0 :         if (strcasecmp(gbuf, "POSITION") && strcasecmp(gbuf, "REFPOSITION")) {
     344           0 :           fprintf(stderr, "gromacsplugin) No structure information in file %s\n", filename);
     345           0 :           return NULL;
     346             :         }
     347           0 :         *natoms = g96_countatoms(mf);
     348             : 
     349           0 :         gmxdata *gmx = new gmxdata;
     350             :         memset(gmx,0,sizeof(gmxdata));
     351           0 :         gmx->mf = mf;
     352           0 :         gmx->natoms = *natoms; 
     353           0 :         return gmx;
     354             : }
     355             : 
     356           0 : static int read_g96_structure(void *mydata, int *optflags,
     357             :     molfile_atom_t *atoms) {
     358             : 
     359             :     char gbuf[MAX_G96_LINE + 1];
     360             :     gmxdata *gmx = (gmxdata *)mydata;
     361             :     md_atom ma;
     362           0 :     md_file *mf = gmx->mf;
     363             : 
     364           0 :     *optflags = MOLFILE_NOOPTIONS; // no optional data
     365             : 
     366           0 :         for (int i = 0; i < gmx->natoms; i++) {
     367           0 :             molfile_atom_t *atom = atoms+i;
     368           0 :             if (g96_rec(mf, &ma) < 0) {
     369           0 :                 fprintf(stderr, "gromacsplugin) Error reading atom %d from file, %s\n",
     370             :                   i+1, mdio_errmsg(mdio_errno()));
     371           0 :                 return MOLFILE_ERROR;
     372             :             }
     373           0 :             strcpy(atom->name, ma.atomname);
     374           0 :             strcpy(atom->type, ma.atomname);
     375           0 :             strcpy(atom->resname, ma.resname);
     376           0 :             atom->resid = atoi(ma.resid);
     377           0 :             atom->chain[0] = '\0';
     378           0 :             atom->segid[0] = '\0';
     379             :         }
     380             : 
     381           0 :         if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0) {
     382           0 :             fprintf(stderr, "gromacsplugin) Warning, error reading END record, %s\n",
     383             :                 mdio_errmsg(mdio_errno()));
     384             :         }
     385             : 
     386             :             // ... another problem: there may or may not be a VELOCITY
     387             :             // block or a BOX block, so we need to read one line beyond
     388             :             // the POSITION block to determine this. If neither VEL. nor
     389             :             // BOX are present we've read a line too far and infringed
     390             :             // on the next timestep, so we need to keep track of the
     391             :             // position now for a possible fseek() later to backtrack.
     392           0 :             long fpos = ftell(mf->f);
     393             : 
     394             :             // Now we must read in the velocities and the box, if present
     395           0 :             if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) >= 0) {
     396             : 
     397             :                 // Is there a velocity block present ?
     398           0 :                 if (!strcasecmp(gbuf, "VELOCITY") || !strcasecmp(gbuf, "VELOCITYRED")) {
     399             :                         // Ignore all the coordinates - VMD doesn't use them
     400             :                         for (;;) {
     401           0 :                                 if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0)
     402             :                                         return MOLFILE_ERROR;
     403           0 :                                 if (!strcasecmp(gbuf, "END")) break;
     404             :                         }
     405             : 
     406             :                         // Again, record our position because we may need
     407             :                         // to fseek here later if we read too far.
     408           0 :                         fpos = ftell(mf->f);
     409             : 
     410             :                         // Go ahead and read the next line.
     411           0 :                         if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0)
     412             :                     return MOLFILE_ERROR;
     413             :                 }
     414             : 
     415             :                 // Is there a box present ?
     416           0 :                 if (!strcasecmp(gbuf, "BOX")) {
     417             :                         // Ignore the box coordinates at this time.
     418           0 :                         if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0)
     419             :                     return MOLFILE_ERROR;
     420           0 :                         if (mdio_readline(mf, gbuf, MAX_G96_LINE + 1) < 0)
     421             :                     return MOLFILE_ERROR;
     422           0 :                         if (strcasecmp(gbuf, "END"))
     423             :                     return MOLFILE_ERROR;
     424             :                 }
     425             :                 else {
     426             :                         // We have read too far, so fseek back to the
     427             :                         // last known safe position so we don't return
     428             :                         // with the file pointer set infringing on the
     429             :                         // next timestep data.
     430           0 :                         fseek(mf->f, fpos, SEEK_SET);
     431             :                 }
     432             :         }
     433             :         else {
     434             :             // Go ahead and rewind for good measure
     435           0 :             fseek(mf->f, fpos, SEEK_SET);
     436             :         }
     437           0 :         rewind(mf->f);
     438             :         return MOLFILE_SUCCESS;
     439             : }
     440             : 
     441           0 : static int read_g96_timestep(void *v, int natoms, molfile_timestep_t *ts) {
     442             : 
     443             :   gmxdata *gmx = (gmxdata *)v;
     444             :   md_ts mdts;
     445             :   memset(&mdts, 0, sizeof(md_ts));
     446           0 :   mdts.natoms = natoms;
     447             : 
     448           0 :   if (mdio_timestep(gmx->mf, &mdts) < 0)
     449             :     return MOLFILE_ERROR;
     450           0 :   if (ts) {
     451           0 :     memcpy(ts->coords, mdts.pos, 3 * sizeof(float) * gmx->natoms);
     452           0 :     if (mdts.box) {
     453           0 :       ts->A = mdts.box->A;
     454           0 :       ts->B = mdts.box->B;
     455           0 :       ts->C = mdts.box->C;
     456           0 :       ts->alpha = mdts.box->alpha;
     457           0 :       ts->beta = mdts.box->beta;
     458           0 :       ts->gamma = mdts.box->gamma;
     459             :     }
     460             :   }
     461           0 :   mdio_tsfree(&mdts);
     462           0 :   return MOLFILE_SUCCESS;
     463             : }
     464             : 
     465           0 : static void close_g96_read(void *v) {
     466             :   gmxdata *gmx = (gmxdata *)v;
     467           0 :   mdio_close(gmx->mf);
     468           0 :   delete gmx;
     469           0 : }
     470             : 
     471             : 
     472             : //
     473             : // TRR and XTC files
     474             : //
     475             : 
     476         209 : static void *open_trr_read(const char *filename, const char *filetype,
     477             :     int *natoms) {
     478             : 
     479             :     md_file *mf;
     480             :     md_header mdh;
     481             :     gmxdata *gmx;
     482             :     int format;
     483             : 
     484         209 :     if (!strcmp(filetype, "trr"))
     485             :       format = MDFMT_TRR;
     486         204 :     else if (!strcmp(filetype, "trj"))
     487             :       format = MDFMT_TRJ;
     488         204 :     else if (!strcmp(filetype, "xtc"))
     489             :       format = MDFMT_XTC;
     490             :     else
     491             :       return NULL;
     492             : 
     493         209 :     mf = mdio_open(filename, format);
     494         209 :     if (!mf) {
     495           0 :         fprintf(stderr, "gromacsplugin) Cannot open file '%s', %s\n",
     496             :                 filename, mdio_errmsg(mdio_errno()));
     497           0 :         return NULL;
     498             :     }
     499         209 :     if (mdio_header(mf, &mdh) < 0) {
     500           0 :         mdio_close(mf);
     501           0 :         fprintf(stderr, "gromacsplugin) Cannot read header fromm '%s', %s\n",
     502             :                 filename, mdio_errmsg(mdio_errno()));
     503           0 :         return NULL;
     504             :     }
     505         209 :     *natoms = mdh.natoms;
     506         209 :     gmx = new gmxdata;
     507             :     memset(gmx,0,sizeof(gmxdata));
     508         209 :     gmx->mf = mf;
     509         209 :     gmx->natoms = mdh.natoms;
     510         209 :     return gmx;
     511             : }
     512             : 
     513       18758 : static int read_trr_timestep(void *v, int natoms, molfile_timestep_t *ts) {
     514             :   gmxdata *gmx = (gmxdata *)v;
     515             :   md_ts mdts;
     516             :   memset(&mdts, 0, sizeof(md_ts));
     517       18758 :   mdts.natoms = natoms;
     518             : 
     519       18758 :   if (mdio_timestep(gmx->mf, &mdts) < 0) {
     520         209 :     if (mdio_errno() == MDIO_EOF || mdio_errno() == MDIO_IOERROR) {
     521             :       // XXX Lame, why does mdio treat IOERROR like EOF?
     522             :       return MOLFILE_ERROR;
     523             :     }
     524           0 :     fprintf(stderr, "gromacsplugin) Error reading timestep, %s\n",
     525             :             mdio_errmsg(mdio_errno()));
     526           0 :     return MOLFILE_ERROR;
     527             :   }
     528       18549 :   if (mdts.natoms != gmx->natoms) {
     529           0 :     fprintf(stderr, "gromacsplugin) Timestep in file contains wrong number of atoms\n");
     530           0 :     fprintf(stderr, "gromacsplugin) Found %d, expected %d\n", mdts.natoms, gmx->natoms);
     531           0 :     mdio_tsfree(&mdts);
     532           0 :     return MOLFILE_ERROR;
     533             :   }
     534             : 
     535       18549 :   if (ts) {
     536       18549 :     if (mdts.pos) 
     537       18549 :       memcpy(ts->coords, mdts.pos, 3 * sizeof(float) * gmx->natoms);
     538             :     else 
     539             :       printf("gromacsplugin) Warning: skipping empty timestep!\n");
     540             : 
     541       18549 :     if (mdts.box) {
     542       18549 :       ts->A = mdts.box->A;
     543       18549 :       ts->B = mdts.box->B;
     544       18549 :       ts->C = mdts.box->C;
     545       18549 :       ts->alpha = mdts.box->alpha;
     546       18549 :       ts->beta = mdts.box->beta;
     547       18549 :       ts->gamma = mdts.box->gamma;
     548             :     }
     549             :   }
     550       18549 :   mdio_tsfree(&mdts);
     551       18549 :   return MOLFILE_SUCCESS;
     552             : }
     553             : 
     554         209 : static void close_trr_read(void *v) {
     555             :   gmxdata *gmx = (gmxdata *)v;
     556         209 :   mdio_close(gmx->mf);
     557         209 :   delete gmx;
     558         209 : }
     559             : 
     560             : // open file for writing
     561           0 : static void *open_trr_write(const char *filename, const char *filetype,
     562             :     int natoms) {
     563             : 
     564             :     md_file *mf;
     565             :     gmxdata *gmx;
     566             :     int format;
     567             : 
     568           0 :     if (!strcmp(filetype, "trr"))
     569             :       format = MDFMT_TRR;
     570           0 :     else if (!strcmp(filetype, "xtc"))
     571             :       format = MDFMT_XTC;
     572             :     else
     573             :       return NULL;
     574             : 
     575           0 :     mf = mdio_open(filename, format, MDIO_WRITE);
     576           0 :     if (!mf) {
     577           0 :         fprintf(stderr, "gromacsplugin) Cannot open file '%s', %s\n",
     578             :                 filename, mdio_errmsg(mdio_errno()));
     579           0 :         return NULL;
     580             :     }
     581           0 :     gmx = new gmxdata;
     582             :     memset(gmx,0,sizeof(gmxdata));
     583           0 :     gmx->mf = mf;
     584           0 :     gmx->natoms = natoms;
     585             :     // set some parameters for the output stream:
     586             :     // start at step 0, convert to big-endian, write single precision.
     587             :     gmx->step   = 0;
     588           0 :     gmx->mf->rev = host_is_little_endian();
     589           0 :     gmx->mf->prec = sizeof(float);
     590           0 :     return gmx;
     591             : }
     592             : 
     593             : // write a trr timestep. the file format has a header with each record
     594           0 : static int write_trr_timestep(void *mydata, const molfile_timestep_t *ts)
     595             : {
     596             :   const float nm=0.1;
     597             : 
     598             :   gmxdata *gmx = (gmxdata *)mydata;
     599             : 
     600             :   // determine and write header from structure info.
     601             :   // write trr header. XXX: move this to Gromacs.h ??
     602           0 :   if (gmx->mf->fmt == MDFMT_TRR) {
     603             :     int i;
     604             : 
     605           0 :     if ( put_trx_int(gmx->mf, TRX_MAGIC)            // ID
     606           0 :          || put_trx_string(gmx->mf, "GMX_trn_file") // version
     607           0 :          || put_trx_int(gmx->mf, 0)                 // ir_size (ignored)
     608           0 :          || put_trx_int(gmx->mf, 0)                 // e_size (ignored)
     609           0 :          || put_trx_int(gmx->mf, 9*sizeof(float))   // box
     610           0 :          || put_trx_int(gmx->mf, 0)                 // vir_size (ignored)
     611           0 :          || put_trx_int(gmx->mf, 0)                 // pres_size (ignored)
     612           0 :          || put_trx_int(gmx->mf, 0)                 // top_size (ignored)
     613           0 :          || put_trx_int(gmx->mf, 0)                 // sym_size (ignored)
     614           0 :          || put_trx_int(gmx->mf, 3*sizeof(float)*gmx->natoms) // coordinates
     615           0 :          || put_trx_int(gmx->mf, 0)                 // no velocities
     616           0 :          || put_trx_int(gmx->mf, 0)                 // no forces
     617           0 :          || put_trx_int(gmx->mf, gmx->natoms)       // number of atoms
     618           0 :          || put_trx_int(gmx->mf, gmx->step)         // current step number
     619           0 :          || put_trx_int(gmx->mf, 0)                 // nre (ignored)
     620           0 :          || put_trx_real(gmx->mf, 0.1*gmx->step)    // current time. (dummy value: 0.1)
     621           0 :          || put_trx_real(gmx->mf, 0.0))             // current lambda
     622           0 :       return MOLFILE_ERROR;
     623             : 
     624             :     // set up box according to the VMD unitcell conventions.
     625             :     // the a-vector is collinear with the x-axis and
     626             :     // the b-vector is in the xy-plane.
     627           0 :     const float sa = sin((double)ts->alpha/180.0*M_PI);
     628           0 :     const float ca = cos((double)ts->alpha/180.0*M_PI);
     629           0 :     const float cb = cos((double)ts->beta/180.0*M_PI);
     630           0 :     const float cg = cos((double)ts->gamma/180.0*M_PI);
     631           0 :     const float sg = sin((double)ts->gamma/180.0*M_PI);
     632             :     float box[9];
     633           0 :     box[0] = ts->A;    box[1] = 0.0;      box[2] = 0.0;
     634           0 :     box[3] = ts->B*ca; box[4] = ts->B*sa; box[5] = 0.0;
     635           0 :     box[6] = ts->C*cb; box[7] = ts->C*(ca - cb*cg)/sg;
     636           0 :     box[8] = ts->C*sqrt((double)(1.0 + 2.0*ca*cb*cg
     637           0 :                                  - ca*ca - cb*cb - cg*cg)/(1.0 - cg*cg));
     638             : 
     639           0 :     for (i=0; i<9; ++i) {
     640           0 :       if (put_trx_real(gmx->mf, box[i]*nm))
     641             :         return MOLFILE_ERROR;
     642             :     }
     643             : #ifdef TEST_TRR_PLUGIN
     644             :     fprintf(stderr, "gromacsplugin) box is:\n %f %f %f\n %f %f %f\n %f %f %f\n\n",
     645             :             box[0], box[1], box[2], box[3], box[4], box[5], box[6], box[7], box[8]);
     646             : #endif
     647             : 
     648             :     // write coordinates
     649           0 :     for (i=0; i<(3*gmx->natoms); ++i) {
     650           0 :       if (put_trx_real(gmx->mf, ts->coords[i]*nm))
     651             :         return MOLFILE_ERROR;
     652             :     }
     653             :   } else {
     654           0 :     fprintf(stderr, "gromacsplugin) only .trr is supported for writing\n");
     655           0 :     return MOLFILE_ERROR;
     656             :   }
     657             : 
     658           0 :   ++ gmx->step;
     659           0 :   return MOLFILE_SUCCESS;
     660             :   }
     661             : 
     662             : 
     663           0 : static void close_trr_write(void *v) {
     664             :   gmxdata *gmx = (gmxdata *)v;
     665           0 :   mdio_close(gmx->mf);
     666           0 :   delete gmx;
     667           0 : }
     668             : 
     669             : #define GROMACS_PLUGIN_MAJOR_VERSION 1
     670             : #define GROMACS_PLUGIN_MINOR_VERSION 3 
     671             : 
     672             : //
     673             : // plugin registration stuff below
     674             : //
     675             : 
     676             : static molfile_plugin_t gro_plugin;
     677             : static molfile_plugin_t g96_plugin;
     678             : static molfile_plugin_t trr_plugin;
     679             : static molfile_plugin_t xtc_plugin;
     680             : static molfile_plugin_t trj_plugin;
     681             : 
     682             : 
     683       10632 : VMDPLUGIN_API int VMDPLUGIN_init() {
     684             :   // GRO plugin init
     685             :   memset(&gro_plugin, 0, sizeof(molfile_plugin_t));
     686       10632 :   gro_plugin.abiversion = vmdplugin_ABIVERSION;
     687       10632 :   gro_plugin.type = MOLFILE_PLUGIN_TYPE;
     688       10632 :   gro_plugin.name = "gro";
     689       10632 :   gro_plugin.prettyname = "Gromacs GRO";
     690       10632 :   gro_plugin.author = "David Norris, Justin Gullingsrud, Magnus Lundborg";
     691       10632 :   gro_plugin.majorv = GROMACS_PLUGIN_MAJOR_VERSION;
     692       10632 :   gro_plugin.minorv = GROMACS_PLUGIN_MINOR_VERSION;
     693             :   gro_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
     694       10632 :   gro_plugin.filename_extension = "gro";
     695       10632 :   gro_plugin.open_file_read = open_gro_read;
     696       10632 :   gro_plugin.read_structure = read_gro_structure;
     697       10632 :   gro_plugin.read_next_timestep = read_gro_timestep;
     698       10632 :   gro_plugin.close_file_read = close_gro_read;
     699       10632 :   gro_plugin.open_file_write = open_gro_write;
     700       10632 :   gro_plugin.write_structure = write_gro_structure;
     701       10632 :   gro_plugin.write_timestep = write_gro_timestep;
     702       10632 :   gro_plugin.close_file_write = close_gro_write;
     703       10632 :   gro_plugin.read_molecule_metadata = read_gro_molecule_metadata;
     704             : 
     705             :   // G96 plugin init
     706             :   memset(&g96_plugin, 0, sizeof(molfile_plugin_t));
     707       10632 :   g96_plugin.abiversion = vmdplugin_ABIVERSION;
     708       10632 :   g96_plugin.type = MOLFILE_PLUGIN_TYPE;
     709       10632 :   g96_plugin.name = "g96";
     710       10632 :   g96_plugin.prettyname = "Gromacs g96";
     711       10632 :   g96_plugin.author = "David Norris, Justin Gullingsrud";
     712       10632 :   g96_plugin.majorv = GROMACS_PLUGIN_MAJOR_VERSION;
     713       10632 :   g96_plugin.minorv = GROMACS_PLUGIN_MINOR_VERSION;
     714             :   g96_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
     715       10632 :   g96_plugin.filename_extension = "g96";
     716       10632 :   g96_plugin.open_file_read = open_g96_read;
     717       10632 :   g96_plugin.read_structure = read_g96_structure;
     718       10632 :   g96_plugin.read_next_timestep = read_g96_timestep;
     719       10632 :   g96_plugin.close_file_read = close_g96_read;
     720             : 
     721             :   // TRR plugin
     722             :   memset(&trr_plugin, 0, sizeof(molfile_plugin_t));
     723       10632 :   trr_plugin.abiversion = vmdplugin_ABIVERSION;
     724       10632 :   trr_plugin.type = MOLFILE_PLUGIN_TYPE;
     725       10632 :   trr_plugin.name = "trr";
     726       10632 :   trr_plugin.prettyname = "Gromacs TRR Trajectory";
     727       10632 :   trr_plugin.author = "David Norris, Justin Gullingsrud, Axel Kohlmeyer";
     728       10632 :   trr_plugin.majorv = GROMACS_PLUGIN_MAJOR_VERSION;
     729       10632 :   trr_plugin.minorv = GROMACS_PLUGIN_MINOR_VERSION;
     730             :   trr_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
     731       10632 :   trr_plugin.filename_extension = "trr";
     732       10632 :   trr_plugin.open_file_read = open_trr_read;
     733       10632 :   trr_plugin.read_next_timestep = read_trr_timestep;
     734       10632 :   trr_plugin.close_file_read = close_trr_read;
     735       10632 :   trr_plugin.open_file_write = open_trr_write;
     736       10632 :   trr_plugin.write_timestep = write_trr_timestep;
     737       10632 :   trr_plugin.close_file_write = close_trr_write;
     738             : 
     739             :   // XTC plugin 
     740             :   memset(&xtc_plugin, 0, sizeof(molfile_plugin_t));
     741       10632 :   xtc_plugin.abiversion = vmdplugin_ABIVERSION;
     742       10632 :   xtc_plugin.type = MOLFILE_PLUGIN_TYPE;
     743       10632 :   xtc_plugin.name = "xtc";
     744       10632 :   xtc_plugin.prettyname = "Gromacs XTC Compressed Trajectory";
     745       10632 :   xtc_plugin.author = "David Norris, Justin Gullingsrud";
     746       10632 :   xtc_plugin.majorv = GROMACS_PLUGIN_MAJOR_VERSION;
     747       10632 :   xtc_plugin.minorv = GROMACS_PLUGIN_MINOR_VERSION;
     748             :   xtc_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
     749       10632 :   xtc_plugin.filename_extension = "xtc";
     750       10632 :   xtc_plugin.open_file_read = open_trr_read;
     751       10632 :   xtc_plugin.read_next_timestep = read_trr_timestep;
     752       10632 :   xtc_plugin.close_file_read = close_trr_read;
     753             : 
     754             :   // TRJ plugin
     755             :   memset(&trj_plugin, 0, sizeof(molfile_plugin_t));
     756       10632 :   trj_plugin.abiversion = vmdplugin_ABIVERSION;
     757       10632 :   trj_plugin.type = MOLFILE_PLUGIN_TYPE;
     758       10632 :   trj_plugin.name = "trj";
     759       10632 :   trj_plugin.prettyname = "Gromacs TRJ Trajectory";
     760       10632 :   trj_plugin.author = "David Norris, Justin Gullingsrud";
     761       10632 :   trj_plugin.majorv = GROMACS_PLUGIN_MAJOR_VERSION;
     762       10632 :   trj_plugin.minorv = GROMACS_PLUGIN_MINOR_VERSION;
     763             :   trj_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
     764       10632 :   trj_plugin.filename_extension = "trj";
     765       10632 :   trj_plugin.open_file_read = open_trr_read;
     766       10632 :   trj_plugin.read_next_timestep = read_trr_timestep;
     767       10632 :   trj_plugin.close_file_read = close_trr_read;
     768             : 
     769       10632 :   return 0;
     770             : }
     771             : 
     772       10632 : VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
     773       10632 :   (*cb)(v, (vmdplugin_t *)&gro_plugin);
     774       10632 :   (*cb)(v, (vmdplugin_t *)&g96_plugin);
     775       10632 :   (*cb)(v, (vmdplugin_t *)&trr_plugin);
     776       10632 :   (*cb)(v, (vmdplugin_t *)&trj_plugin);
     777       10632 :   (*cb)(v, (vmdplugin_t *)&xtc_plugin);
     778       10632 :   return 0;
     779             : }
     780             : 
     781           0 : VMDPLUGIN_API int VMDPLUGIN_fini() {
     782           0 :   return 0;
     783             : }
     784             : 
     785             : }
     786             : }
     787             : 
     788             : 
     789             : #ifdef TEST_G96_PLUGIN
     790             : 
     791             : int main(int argc, char *argv[]) {
     792             :   int natoms;
     793             : 
     794             :   molfile_timestep_t timestep;
     795             :   void *v;
     796             :   int i;
     797             : 
     798             :   if (argc < 2) return 1;
     799             :   while (--argc) {
     800             :     ++argv;
     801             :     v = open_g96_read(*argv, "g96", &natoms);
     802             :     if (!v) {
     803             :       fprintf(stderr, "open_g96_read failed for file %s\n", *argv);
     804             :       return 1;
     805             :     }
     806             :     timestep.coords = (float *)malloc(3*sizeof(float)*natoms);
     807             :     i = 0;
     808             :     while(!read_g96_timestep(v, natoms, &timestep)) {
     809             :       ++i;
     810             :     }
     811             :     fprintf(stderr, "ended read_g96_timestep on step %d\n", i);
     812             :     free(timestep.coords);
     813             :     close_g96_read(v);
     814             :   }
     815             :   return 0;
     816             : }
     817             : 
     818             : #endif
     819             : 
     820             : #ifdef TEST_TRR_PLUGIN
     821             : 
     822             : int main(int argc, char *argv[]) {
     823             :   int natoms;
     824             : 
     825             :   molfile_timestep_t timestep;
     826             :   void *v, *w;
     827             :   int i;
     828             : 
     829             :   if (argc != 3) return 1;
     830             :   v = open_trr_read(argv[1], "trr", &natoms);
     831             :   if (!v) {
     832             :     fprintf(stderr, "open_trr_read failed for file %s\n", argv[1]);
     833             :     return 1;
     834             :   }
     835             :   timestep.coords = (float *)malloc(3*sizeof(float)*natoms);
     836             :   w = open_trr_write(argv[2], "trr", natoms);
     837             :   if (!w) {
     838             :     fprintf(stderr, "open_trr_write failed for file %s\n", argv[2]);
     839             :     return 1;
     840             :   }
     841             : 
     842             :   i = 0;
     843             :   while(!read_trr_timestep(v, natoms, &timestep)) {
     844             :     ++i;
     845             :     if (write_trr_timestep(w, &timestep)) {
     846             :       fprintf(stderr, "write error\n");
     847             :       return 1;
     848             :     }
     849             :   }
     850             : 
     851             :   fprintf(stderr, "ended read_trr_timestep on step %d\n", i);
     852             :   free(timestep.coords);
     853             :   close_trr_read(v);
     854             :   close_trr_write(w);
     855             :   return 0;
     856             : }
     857             : 
     858             : #endif
     859             : 
     860             : #endif

Generated by: LCOV version 1.16