Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

tngplugin.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  * RCS INFORMATION:
00003  *
00004  *      $RCSfile: tngplugin.C,v $
00005  *      $Author: johns $       $Locker:  $             $State: Exp $
00006  *      $Revision: 1.7 $       $Date: 2015/10/12 03:00:46 $
00007  *
00008  ***************************************************************************
00009  * DESCRIPTION:
00010  *   VMD plugin to allow reading and writing of Gromacs TNG trajectories.
00011  *   This software and the TNG library are made available under the
00012  *   BSD license.  For details, see the license information associated
00013  *   with the Gromacs TNG library that this code depends on at:
00014  *     http://www.gromacs.org/
00015  *
00016  *   The TNG trajectory format is described in this publication:
00017  *     "An efficient and extensible format, library, and API for
00018  *     binary trajectory data from molecular simulations"
00019  *     Journal of Computational Chemistry 2013, DOI: 10.1002/jcc.23495
00020  *     http://onlinelibrary.wiley.com/doi/10.1002/jcc.23495/abstract
00021  *
00022  *   The TNG git repo is the master location for the sources, though
00023  *   the standard git SSL checks have to be disabled to access it:
00024  *      env GIT_SSL_NO_VERIFY=1 git clone https://gerrit.gromacs.org/tng
00025  *
00026  *   This version of the TNG plugin requires version 1.7.4 or greater
00027  *   of the TNG library.
00028  *
00029  ***************************************************************************/
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <math.h>
00035 #include <tng/tng_io.h>
00036 #include "molfile_plugin.h"
00037 
00038 #define TNG_PLUGIN_MAJOR_VERSION 1
00039 #define TNG_PLUGIN_MINOR_VERSION 0
00040 
00041 #ifndef M_PI_2
00042 #define M_PI_2 1.57079632679489661922
00043 #endif
00044 
00045 typedef struct {
00046   tng_trajectory_t tng_traj;
00047   int natoms;
00048   int step;
00049 //   int stride_length;
00050   int64_t n_frames;
00051   int coord_exponential;
00052 //   int64_t n_frames_per_frame_set;
00053   double time_per_frame;
00054   int has_velocities;
00055 } tngdata;
00056 
00057 static void convert_tng_box_shape_to_vmd(float *box_shape, float *vmd_box)
00058 {
00059     float A, B, C;
00060 
00061     A = sqrt(box_shape[0]*box_shape[0] +
00062              box_shape[1]*box_shape[1] +
00063              box_shape[2]*box_shape[2]);
00064     B = sqrt(box_shape[3]*box_shape[3] +
00065              box_shape[4]*box_shape[4] +
00066              box_shape[5]*box_shape[5]);
00067     C = sqrt(box_shape[6]*box_shape[6] +
00068              box_shape[7]*box_shape[7] +
00069              box_shape[8]*box_shape[8]);
00070 
00071     if ((A<=0) || (B<=0) || (C<=0))
00072     {
00073         vmd_box[0] = vmd_box[1] = vmd_box[2] = 0;
00074         vmd_box[3] = vmd_box[4] = vmd_box[5] = 90;
00075     }
00076     else
00077     {
00078         vmd_box[0] = A;
00079         vmd_box[1] = B;
00080         vmd_box[2] = C;
00081         vmd_box[3] = acos( (box_shape[3]*box_shape[6]+
00082                             box_shape[4]*box_shape[7]+
00083                             box_shape[5]*box_shape[8])/(B*C) ) * 90.0/M_PI_2;
00084         vmd_box[4] = acos( (box_shape[0]*box_shape[6]+
00085                             box_shape[1]*box_shape[7]+
00086                             box_shape[2]*box_shape[8])/(A*C) ) * 90.0/M_PI_2;
00087         vmd_box[5] = acos( (box_shape[0]*box_shape[3]+
00088                             box_shape[1]*box_shape[4]+
00089                             box_shape[2]*box_shape[5])/(A*B) ) * 90.0/M_PI_2;
00090     }
00091 }
00092 
00093 static void convert_vmd_box_shape_to_tng(const molfile_timestep_t *ts, float *box_shape)
00094 {
00095 //     const float sa = sin((double)ts->alpha/180.0*M_PI);
00096     const float ca = cos((double)ts->alpha/180.0*M_PI);
00097     const float cb = cos((double)ts->beta/180.0*M_PI);
00098     const float cg = cos((double)ts->gamma/180.0*M_PI);
00099     const float sg = sin((double)ts->gamma/180.0*M_PI);
00100 
00101     box_shape[0] = ts->A;
00102     box_shape[1] = 0.0;
00103     box_shape[2] = 0.0;
00104     box_shape[3] = ts->B*cg; // ts->B*ca when writing trr?!
00105     box_shape[4] = ts->B*sg; // ts->B*sa when writing trr?!
00106     box_shape[5] = 0.0;
00107     box_shape[6] = ts->C*cb;
00108     box_shape[7] = ts->C*(ca - cb*cg)/sg;
00109     box_shape[8] = ts->C*sqrt((double)(1.0 + 2.0*ca*cb*cg
00110                                        - ca*ca - cb*cb - cg*cg)/(1.0 - cg*cg));
00111 }
00112 
00113 static void *open_tng_read(const char *filename, const char*,
00114                            int *natoms)
00115 {
00116     tngdata *tng;
00117     tng_function_status stat;
00118     int64_t n, exp;
00119 
00120     tng = new tngdata;
00121 
00122     stat = tng_util_trajectory_open(filename, 'r', &tng->tng_traj);
00123     if(stat != TNG_SUCCESS)
00124     {
00125         fprintf(stderr, "tngplugin) Cannot open file '%s'\n", filename);
00126         return NULL;
00127     }
00128 
00129     tng_num_particles_get(tng->tng_traj, &n);
00130     *natoms = (int)n;
00131     tng->natoms = (int)n;
00132     tng->step = 0;
00133     tng_num_frames_get(tng->tng_traj, &n);
00134     tng->n_frames = n;
00135     tng->has_velocities = 0;
00136 
00137     tng_distance_unit_exponential_get(tng->tng_traj, &exp);
00138     tng->coord_exponential = (int) exp;
00139 
00140 
00141     return tng;
00142 }
00143 
00144 static int read_tng_structure(void *v, int *optflags,
00145                                molfile_atom_t *atoms)
00146 {
00147     tngdata *tng = (tngdata *)v;
00148     char long_name[16], short_name[2];
00149     int64_t id;
00150 
00151     *optflags = MOLFILE_NOOPTIONS;
00152     for(int i = 0; i < tng->natoms; i++)
00153     {
00154         molfile_atom_t *atom = atoms+i;
00155         tng_atom_name_of_particle_nr_get(tng->tng_traj, i, long_name, 16);
00156         strcpy(atom->name, long_name);
00157         tng_atom_type_of_particle_nr_get(tng->tng_traj, i, long_name, 16);
00158         strcpy(atom->type, long_name);
00159         tng_residue_name_of_particle_nr_get(tng->tng_traj, i, long_name, 16);
00160         strcpy(atom->resname, long_name);
00161         tng_global_residue_id_of_particle_nr_get(tng->tng_traj, i, &id);
00162         atom->resid = (int)id;
00163 //         fprintf(stderr, "resid: %d\n", (int)id);
00164         tng_chain_name_of_particle_nr_get(tng->tng_traj, i, short_name, 2);
00165         strcpy(atom->chain, short_name);
00166         atom->segid[0] = '\0';
00167     }
00168 //     fprintf(stderr, "Structure opened\n");
00169     return MOLFILE_SUCCESS;
00170 }
00171 
00172 #if vmdplugin_ABIVERSION > 14
00173 static int read_tng_bonds(void *v, int *nbonds, int **fromptr, int **toptr,
00174                           float **bondorderptr, int **bondtypeptr,
00175                           int *nbondtypes, char ***bondtypename)
00176 #else
00177 static int read_tng_bonds(void *v, int *nbonds, int **fromptr, int **toptr,
00178                           float **bondorderptr)
00179 #endif
00180 {
00181     int64_t *from_atoms = 0, *to_atoms = 0, bond_cnt, i;
00182     tng_function_status stat;
00183 
00184     tngdata *tng = (tngdata *)v;
00185 
00186     stat = tng_molsystem_bonds_get(tng->tng_traj, &bond_cnt, &from_atoms,
00187                                    &to_atoms);
00188     if(stat != TNG_SUCCESS)
00189     {
00190         return MOLFILE_ERROR;
00191     }
00192 
00193     if(bond_cnt <= 0)
00194     {
00195         fprintf(stderr, "tngplugin) No bonds found in molsystem\n");
00196         *nbonds = 0;
00197         *fromptr = 0;
00198         *toptr = 0;
00199         return MOLFILE_SUCCESS;
00200     }
00201 
00202     /* Convert from int64_t to int. The fact that VMD and TNG use different
00203      * int types can lead to problems if there are very many atoms and/or
00204      * bonds */
00205     *nbonds = (int) bond_cnt;
00206     *fromptr = (int *)malloc((*nbonds) * sizeof(int));
00207     *toptr = (int *)malloc((*nbonds) * sizeof(int));
00208     *bondorderptr = 0;
00209 
00210 #if vmdplugin_ABIVERSION > 14
00211     *bondtypeptr = 0;
00212     *nbondtypes = 0;
00213     *bondtypename = 0;
00214 #endif
00215 
00216     for(i = 0; i < *nbonds; i++)
00217     {
00218         (*fromptr)[i] = (int)from_atoms[i] + 1;
00219         (*toptr)[i] = (int)to_atoms[i] + 1;
00220 //         fprintf(stderr, "Adding bond from %d to %d\n", (*fromptr)[i], (*toptr)[i]);
00221     }
00222 
00223     return MOLFILE_SUCCESS;
00224 }
00225 
00226 static void convert_to_float(void *from, float *to, const float fact, const int natoms, const int nvalues, const char datatype)
00227 {
00228     int i, j;
00229 
00230     switch(datatype)
00231     {
00232     case TNG_FLOAT_DATA:
00233         if(fact == 1)
00234         {
00235             memcpy(to, from, nvalues * sizeof(float) * natoms);
00236         }
00237         else
00238         {
00239             for(i = 0; i < natoms; i++)
00240             {
00241                 for(j = 0; j < nvalues; j++)
00242                 {
00243                     to[i*3+j] = (float)((float *)from)[i*3+j] * fact;
00244                 }
00245             }
00246         }
00247         break;
00248     case TNG_INT_DATA:
00249         for(i = 0; i < natoms; i++)
00250         {
00251             for(j = 0; j < nvalues; j++)
00252             {
00253                 to[i*3+j] = (float)((int64_t *)from)[i*3+j] * fact;
00254             }
00255         }
00256         break;
00257     case TNG_DOUBLE_DATA:
00258         for(i = 0; i < natoms; i++)
00259         {
00260             for(j = 0; j < nvalues; j++)
00261             {
00262                 to[i*3+j] = (float)((double *)from)[i*3+j] * fact;
00263             }
00264         }
00265         break;
00266     default:
00267         fprintf(stderr, "tngplugin) Cannot cast data\n");
00268     }
00269     return;
00270 }
00271 
00272 static int read_tng_timestep(void *v, int natoms, molfile_timestep_t *ts)
00273 {
00274     /* The pointers that will be allocated by the TNG must be NULL before allocation. */
00275     void *values = 0;
00276     char datatype;
00277     float box_shape[9], vmd_box[6];
00278     float fact = 1;
00279     int64_t frame, n, temp, temp2;
00280     tng_function_status stat;
00281     tngdata *tng = (tngdata *)v;
00282 
00283     if(!ts)
00284     {
00285         return MOLFILE_ERROR;
00286     }
00287 
00288 //     fprintf(stderr, "Reading framestep from TNG\n");
00289 
00290     stat = tng_util_particle_data_next_frame_read(tng->tng_traj, TNG_TRAJ_POSITIONS, &values,
00291                                                   &datatype, &frame, &ts->physical_time);
00292     if(stat != TNG_SUCCESS)
00293     {
00294         return MOLFILE_ERROR;
00295     }
00296 //     fprintf(stderr, "tngplugin) Timestep %d (%f), frame %d (%d), %d atoms\n",
00297 //             tng->step, ts->physical_time, (int)frame, (int)tng->n_frames, natoms);
00298 
00299     /* TODO: Here it would be possible to add reading of the energy and pressure
00300      * measurements supported in VMD if they are present in the TNG file */
00301     tng_num_particles_get(tng->tng_traj, &n);
00302     if(n != natoms)
00303     {
00304         fprintf(stderr, "tngplugin) Timestep in file contains wrong number of atoms\n");
00305         fprintf(stderr, "tngplugin) Found %d, expected %d\n", (int)n, natoms);
00306         return MOLFILE_ERROR;
00307     }
00308 
00309     if(tng->coord_exponential != -10)
00310     {
00311         fact = pow(10.0, tng->coord_exponential + 10);
00312     }
00313 
00314     convert_to_float(values, ts->coords, fact, natoms, 3, datatype);
00315 
00316     if(ts->velocities)
00317     {
00318 //         fprintf(stderr, "tngplugin) Reading velocities\n");
00319         stat = tng_particle_data_vector_interval_get(tng->tng_traj, TNG_TRAJ_VELOCITIES, frame,
00320                                                      frame, TNG_USE_HASH, &values,
00321                                                      &n, &temp, &temp2, &datatype);
00322         if(stat == TNG_CRITICAL)
00323         {
00324             return MOLFILE_ERROR;
00325         }
00326         if(stat == TNG_SUCCESS)
00327         {
00328             convert_to_float(values, ts->velocities, fact, natoms, 3, datatype);
00329         }
00330     }
00331 
00332     stat = tng_data_vector_interval_get(tng->tng_traj, TNG_TRAJ_BOX_SHAPE,
00333                                         frame, frame, TNG_USE_HASH, &values,
00334                                         &temp, &temp2, &datatype);
00335     if(stat == TNG_CRITICAL)
00336     {
00337         return MOLFILE_ERROR;
00338     }
00339     if(stat == TNG_SUCCESS)
00340     {
00341         convert_to_float(values, box_shape, fact, 1, 9, datatype);
00342 
00343         convert_tng_box_shape_to_vmd(box_shape, vmd_box);
00344         if(ts)
00345         {
00346             ts->A = vmd_box[0];
00347             ts->B = vmd_box[1];
00348             ts->C = vmd_box[2];
00349             ts->alpha = vmd_box[3];
00350             ts->beta = vmd_box[4];
00351             ts->gamma = vmd_box[5];
00352         }
00353     }
00354 
00355     ++tng->step;
00356     if(values)
00357     {
00358         free(values);
00359     }
00360 
00361     return MOLFILE_SUCCESS;
00362 }
00363 
00364 static int read_timestep_metadata(void *v, molfile_timestep_metadata_t *metadata)
00365 {
00366     tng_function_status stat;
00367     tngdata *tng = (tngdata *)v;
00368 
00369     /* Check only once if there are velocities in the file at all. */
00370     if(tng->has_velocities == 0)
00371     {
00372         stat = tng_frame_set_read_current_only_data_from_block_id(tng->tng_traj, TNG_SKIP_HASH, TNG_TRAJ_VELOCITIES);
00373 
00374         if(stat == TNG_CRITICAL)
00375         {
00376             metadata->has_velocities = 0;
00377             return MOLFILE_ERROR;
00378         }
00379         else if(stat == TNG_SUCCESS)
00380         {
00381             fprintf(stderr, "tngplugin) Trajectory contains velocities\n");
00382             tng->has_velocities = 1;
00383         }
00384         else
00385         {
00386             fprintf(stderr, "tngplugin) Trajectory does not contain velocities\n");
00387             tng->has_velocities = -1;
00388         }
00389     }
00390     if(tng->has_velocities == 1)
00391     {
00392         metadata->has_velocities = 1;
00393     }
00394     else
00395     {
00396         metadata->has_velocities = 0;
00397     }
00398 
00399     return MOLFILE_SUCCESS;
00400 }
00401 
00402 static void close_tng(void *v)
00403 {
00404     tngdata *tng = (tngdata *)v;
00405     tng_util_trajectory_close(&tng->tng_traj);
00406     delete tng;
00407 }
00408 
00409 static void *open_tng_write(const char *filename, const char*,
00410                             int natoms)
00411 {
00412     tngdata *tng;
00413     tng_function_status stat;
00414 //     int64_t n, exp;
00415 
00416     tng = new tngdata;
00417 
00418     stat = tng_util_trajectory_open(filename, 'w', &tng->tng_traj);
00419     if(stat != TNG_SUCCESS)
00420     {
00421         fprintf(stderr, "tngplugin) Cannot open file '%s'\n", filename);
00422         return NULL;
00423     }
00424 
00425     tng->natoms = natoms;
00426     tng->step = 0;
00427     tng->coord_exponential = -10;
00428     tng_distance_unit_exponential_set(tng->tng_traj, -10);
00429 
00430     tng->time_per_frame = -1;
00431 
00432     return tng;
00433 }
00434 
00435 static int write_tng_structure(void *v, int optflags, const molfile_atom_t *atoms)
00436 {
00437     /* VMD atoms do not contain molecule information, which
00438      * complicates TNG writing a bit. */
00439     tng_molecule_t tng_mol = 0;
00440     tng_chain_t tng_chain = 0;
00441     tng_residue_t tng_residue = 0;
00442     tng_atom_t tng_atom;
00443     int prev_resid = -1;
00444     char new_chain_name[4] = "X_A";
00445 
00446     tngdata *tng = (tngdata *)v;
00447 
00448     /* A dummy molecule must be added. All atoms will be added to it. */
00449     if(tng_molecule_find(tng->tng_traj, "MOL", -1, &tng_mol) != TNG_SUCCESS)
00450     {
00451         tng_molecule_add(tng->tng_traj, "MOL", &tng_mol);
00452     }
00453 
00454     for(int i = 0; i < tng->natoms; i++)
00455     {
00456         if(tng_chain == 0)
00457         {
00458             if(tng_molecule_chain_find(tng->tng_traj, tng_mol, atoms[i].chain, -1, &tng_chain) !=
00459                 TNG_SUCCESS)
00460             {
00461                 tng_molecule_chain_add(tng->tng_traj, tng_mol, atoms[i].chain, &tng_chain);
00462             }
00463         }
00464         else if(tng_residue != 0)
00465         {
00466             if(prev_resid >= 0)
00467             {
00468                 if(prev_resid > atoms[i].resid)
00469                 {
00470                     new_chain_name[0] = atoms[i].chain[0];
00471                     ++new_chain_name[2];
00472                     tng_molecule_chain_add(tng->tng_traj, tng_mol, new_chain_name, &tng_chain);
00473                 }
00474             }
00475         }
00476 //         fprintf(stderr, "tngplugin) Looking for residue: %s, %d\n", atoms[i].resname, atoms[i].resid);
00477         if (tng_chain_residue_find(tng->tng_traj, tng_chain, atoms[i].resname,
00478                                    atoms[i].resid, &tng_residue) != TNG_SUCCESS)
00479         {
00480             tng_chain_residue_w_id_add(tng->tng_traj, tng_chain, atoms[i].resname,
00481                                        atoms[i].resid, &tng_residue);
00482             prev_resid = atoms[i].resid;
00483         }
00484         tng_residue_atom_add(tng->tng_traj, tng_residue, atoms[i].name, atoms[i].type, &tng_atom);
00485     }
00486     tng_molecule_cnt_set(tng->tng_traj, tng_mol, 1);
00487 
00488     return MOLFILE_SUCCESS;
00489 }
00490 
00491 #if vmdplugin_ABIVERSION > 14
00492 static int write_tng_bonds(void *v, int nbonds, int *from, int *to,
00493                           float *bondorder, int *bondtype,
00494                           int nbondtypes, char **bondtypename)
00495 #else
00496 static int write_tng_bonds(void *v, int nbonds, int *from, int *to,
00497                           float *bondorder)
00498 #endif
00499 {
00500     tng_molecule_t tng_mol;
00501     tng_bond_t tng_bond;
00502     int i;
00503 
00504     if(nbonds == 0)
00505     {
00506         return MOLFILE_SUCCESS;
00507     }
00508 
00509     tngdata *tng = (tngdata *)v;
00510 
00511     /* A dummy molecule must be added. All atoms will be added to it. */
00512     if(tng_molecule_find(tng->tng_traj, "MOL", -1, &tng_mol) != TNG_SUCCESS)
00513     {
00514         tng_molecule_add(tng->tng_traj, "MOL", &tng_mol);
00515     }
00516 
00517     for (i = 0; i < nbonds; i++)
00518     {
00519         if(tng_molecule_bond_add(tng->tng_traj, tng_mol, from[i]-1, to[i]-1, &tng_bond) != TNG_SUCCESS)
00520         {
00521             fprintf(stderr, "tngplugin) Error adding bond %d (from %d to %d).\n", i, from[i], to[i]);
00522             return MOLFILE_ERROR;
00523         }
00524     }
00525     return MOLFILE_SUCCESS;
00526 }
00527 
00528 static int write_tng_timestep(void *v, const molfile_timestep_t *ts)
00529 {
00530     float box_shape[9];
00531     tngdata *tng = (tngdata *)v;
00532 
00533     /* If there are fewer particles in the TNG mol system (write_tng_structure
00534      * has not already been performed) compensate by creating implicit particles,
00535      * which will not have full atom information. */
00536     tng_implicit_num_particles_set(tng->tng_traj, tng->natoms);
00537 
00538     if(!ts)
00539     {
00540         return MOLFILE_ERROR;
00541     }
00542 
00543     convert_vmd_box_shape_to_tng(ts, box_shape);
00544     if(tng->step == 1 && ts->physical_time != 0)
00545     {
00546         tng->time_per_frame = ts->physical_time;
00547         tng_time_per_frame_set(tng->tng_traj, tng->time_per_frame);
00548     }
00549     if(tng->time_per_frame < 0)
00550     {
00551 //         fprintf(stderr, "tngplugin) Writing frame without time stamp\n");
00552         tng_util_box_shape_write(tng->tng_traj, tng->step, box_shape);
00553         tng_util_pos_write(tng->tng_traj, tng->step, ts->coords);
00554     }
00555     else
00556     {
00557 //         fprintf(stderr, "tngplugin) Writing frame with time stamp\n");
00558         tng_util_box_shape_with_time_write(tng->tng_traj, tng->step, ts->physical_time,
00559                                            box_shape);
00560         tng_util_pos_with_time_write(tng->tng_traj, tng->step, ts->physical_time,
00561                                      ts->coords);
00562     }
00563     if(tng->step == 0)
00564     {
00565         tng_util_pos_write_interval_set(tng->tng_traj, 1);
00566         tng_util_box_shape_write_interval_set(tng->tng_traj, 1);
00567     }
00568     if(ts->velocities)
00569     {
00570 //         fprintf(stderr, "tngplugin) Writing TNG velocities\n");
00571         if(tng->time_per_frame < 0)
00572         {
00573             tng_util_vel_write(tng->tng_traj, tng->step, ts->velocities);
00574         }
00575         else
00576         {
00577             tng_util_vel_with_time_write(tng->tng_traj, tng->step, ts->physical_time,
00578                                          ts->velocities);
00579         }
00580         if(tng->step == 0)
00581         {
00582             tng_util_vel_write_interval_set(tng->tng_traj, 1);
00583         }
00584     }
00585 
00586     tng->step++;
00587 
00588     return MOLFILE_SUCCESS;
00589 }
00590 
00591 static molfile_plugin_t tng_plugin;
00592 
00593 VMDPLUGIN_API int VMDPLUGIN_init() {
00594   // TNG plugin init
00595   memset(&tng_plugin, 0, sizeof(molfile_plugin_t));
00596   tng_plugin.abiversion = vmdplugin_ABIVERSION;
00597   tng_plugin.type = MOLFILE_PLUGIN_TYPE;
00598   tng_plugin.name = "tng";
00599   tng_plugin.prettyname = "TNG: Trajectory Next Generation (testing)";
00600   tng_plugin.author = "Magnus Lundborg";
00601   tng_plugin.majorv = TNG_PLUGIN_MAJOR_VERSION;
00602   tng_plugin.minorv = TNG_PLUGIN_MINOR_VERSION;
00603   tng_plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
00604   tng_plugin.filename_extension = "tng";
00605   tng_plugin.open_file_read = open_tng_read;
00606   tng_plugin.read_structure = read_tng_structure;
00607   tng_plugin.read_bonds = read_tng_bonds;
00608   tng_plugin.read_next_timestep = read_tng_timestep;
00609   tng_plugin.close_file_read = close_tng;
00610   tng_plugin.open_file_write = open_tng_write;
00611   tng_plugin.write_structure = write_tng_structure;
00612   tng_plugin.write_timestep = write_tng_timestep;
00613   tng_plugin.close_file_write = close_tng;
00614   tng_plugin.write_bonds = write_tng_bonds;
00615   tng_plugin.read_timestep_metadata = read_timestep_metadata;
00616 
00617   return VMDPLUGIN_SUCCESS;
00618 }
00619 
00620 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
00621   (*cb)(v, (vmdplugin_t *)&tng_plugin);
00622   return VMDPLUGIN_SUCCESS;
00623 }
00624 
00625 VMDPLUGIN_API int VMDPLUGIN_fini() {
00626   return VMDPLUGIN_SUCCESS;
00627 }
00628 
00629 

Generated on Wed Nov 11 03:06:35 2020 for VMD Plugins (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002