27760147cd5c92302430c743101f357f1f2aec89
[alexxy/gromacs.git] / src / gromacs / fileio / vmdio.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2012,2013,2014,2015,2016, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "gmxpre.h"
36
37 #include "vmdio.h"
38
39 #include "config.h"
40
41 /* Derived from PluginMgr.C and catdcd.c */
42
43 /* PluginMgr.C: Copyright: */
44 /***************************************************************************
45  * cr
46  * cr            (C) Copyright 1995-2009 The Board of Trustees of the
47  * cr                        University of Illinois
48  * cr                         All Rights Reserved
49  * cr
50    Developed by:           Theoretical and Computational Biophysics Group
51                         University of Illinois at Urbana-Champaign
52                         http://www.ks.uiuc.edu/
53
54    Permission is hereby granted, free of charge, to any person obtaining a copy of
55    this software and associated documentation files (the Software), to deal with
56    the Software without restriction, including without limitation the rights to
57    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
58    of the Software, and to permit persons to whom the Software is furnished to
59    do so, subject to the following conditions:
60
61    Redistributions of source code must retain the above copyright notice,
62    this list of conditions and the following disclaimers.
63
64    Redistributions in binary form must reproduce the above copyright notice,
65    this list of conditions and the following disclaimers in the documentation
66    and/or other materials provided with the distribution.
67
68    Neither the names of Theoretical and Computational Biophysics Group,
69    University of Illinois at Urbana-Champaign, nor the names of its contributors
70    may be used to endorse or promote products derived from this Software without
71    specific prior written permission.
72
73    THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
74    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
75    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
76    THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
77    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
78    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
79    OTHER DEALINGS WITH THE SOFTWARE.
80  ***************************************************************************/
81
82 /* catdcd.c: Copyright: */
83 /*****************************************************************************/
84 /*                                                                           */
85 /* (C) Copyright 2001-2005 Justin Gullingsrud and the University of Illinois.*/
86 /*                                                                           */
87 /*****************************************************************************/
88
89 #include <assert.h>
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <string.h>
93
94 /*
95  * Plugin header files; get plugin source from www.ks.uiuc.edu/Research/vmd"
96  */
97 #include "external/vmd_molfile/molfile_plugin.h"
98 #include "external/vmd_molfile/vmddlopen.h"
99 #if !GMX_NATIVE_WINDOWS
100 #include <glob.h>
101 #else
102 #ifndef _WIN32_IE
103 #define _WIN32_IE 0x0500 /* SHGetFolderPath is available since WinXP/IE5 */
104 #endif
105 #include <shlobj.h>
106 #include <windows.h>
107 #endif
108
109 #include "gromacs/fileio/gmxfio.h"
110 #include "gromacs/math/vec.h"
111 #include "gromacs/pbcutil/pbc.h"
112 #include "gromacs/trajectory/trajectoryframe.h"
113 #include "gromacs/utility/basedefinitions.h"
114 #include "gromacs/utility/fatalerror.h"
115 #include "gromacs/utility/futil.h"
116 #include "gromacs/utility/smalloc.h"
117
118
119 typedef int (*initfunc)(void);
120 typedef int (*regfunc)(void *, vmdplugin_register_cb);
121 typedef int (*finifunc)(void);
122
123
124
125 static int register_cb(void *v, vmdplugin_t *p)
126 {
127     const char      *key       = p->name;
128     gmx_vmdplugin_t *vmdplugin = static_cast<gmx_vmdplugin_t *>(v);
129
130     if (strcmp(key, vmdplugin->filetype) == 0)
131     {
132         vmdplugin->api = (molfile_plugin_t *)p;
133     }
134     return VMDPLUGIN_SUCCESS;
135 }
136
137 static int load_sharedlibrary_plugins(const char *fullpath, gmx_vmdplugin_t *vmdplugin)
138 {
139     /* Open the dll; try to execute the init function. */
140     void *handle, *ifunc, *registerfunc;
141     handle = vmddlopen(fullpath);
142     if (!handle)
143     {
144         if (debug)
145         {
146             fprintf(debug, "\nUnable to open dynamic library %s.\n%s\n",  fullpath, vmddlerror());         /*only to debug because of stdc++ erros */
147         }
148         return 0;
149     }
150
151     ifunc = vmddlsym(handle, "vmdplugin_init");
152     if (!ifunc || ((initfunc)(ifunc))())
153     {
154         printf("\nvmdplugin_init() for %s returned an error; plugin(s) not loaded.\n", fullpath);
155         vmddlclose(handle);
156         return 0;
157     }
158
159     registerfunc = vmddlsym(handle, "vmdplugin_register");
160     if (!registerfunc)
161     {
162         printf("\nDidn't find the register function in %s; plugin(s) not loaded.\n", fullpath);
163         vmddlclose(handle);
164         return 0;
165     }
166     else
167     {
168         /* Load plugins from the library.*/
169         ((regfunc)registerfunc)(vmdplugin, register_cb);
170     }
171
172     /* in case this library does not support the filetype, close it */
173     if (vmdplugin->api == NULL)
174     {
175         vmddlclose(handle);
176     }
177
178     return 1;
179 }
180
181 /*return: 1: success, 0: last frame, -1: error*/
182 gmx_bool read_next_vmd_frame(gmx_vmdplugin_t *vmdplugin, t_trxframe *fr)
183 {
184     int                rc, i;
185     rvec               vec, angle;
186     molfile_timestep_t ts;
187
188
189     fr->bV = vmdplugin->bV;
190
191 #if GMX_DOUBLE
192     snew(ts.coords, fr->natoms*3);
193     if (fr->bV)
194     {
195         snew(ts.velocities, fr->natoms*3);
196     }
197 #else
198     ts.coords = (float*)fr->x;
199     if (fr->bV)
200     {
201         ts.velocities = (float*)fr->v;
202     }
203 #endif
204
205     rc = vmdplugin->api->read_next_timestep(vmdplugin->handle, fr->natoms, &ts);
206
207     if (rc < -1)
208     {
209         fprintf(stderr, "\nError reading input file (error code %d)\n", rc);
210     }
211     if (rc < 0)
212     {
213         vmdplugin->api->close_file_read(vmdplugin->handle);
214         return 0;
215     }
216
217 #if GMX_DOUBLE
218     for (i = 0; i < fr->natoms; i++)
219     {
220         fr->x[i][0] = .1*ts.coords[i*3];
221         fr->x[i][1] = .1*ts.coords[i*3+1];
222         fr->x[i][2] = .1*ts.coords[i*3+2];
223         if (fr->bV)
224         {
225             fr->v[i][0] = .1*ts.velocities[i*3];
226             fr->v[i][1] = .1*ts.velocities[i*3+1];
227             fr->v[i][2] = .1*ts.velocities[i*3+2];
228         }
229     }
230     sfree(ts.coords);
231     if (fr->bV)
232     {
233         sfree(ts.velocities);
234     }
235 #else
236     for (i = 0; i < fr->natoms; i++)
237     {
238         svmul(.1, fr->x[i], fr->x[i]);
239         if (fr->bV)
240         {
241             svmul(.1, fr->v[i], fr->v[i]);
242         }
243     }
244 #endif
245
246     fr->bX   = 1;
247     fr->bBox = 1;
248     vec[0]   = .1*ts.A; vec[1] = .1*ts.B; vec[2] = .1*ts.C;
249     angle[0] = ts.alpha; angle[1] = ts.beta; angle[2] = ts.gamma;
250     matrix_convert(fr->box, vec, angle);
251     if (vmdplugin->api->abiversion > 10)
252     {
253         fr->bTime = TRUE;
254         fr->time  = ts.physical_time;
255     }
256     else
257     {
258         fr->bTime = FALSE;
259     }
260
261
262     return 1;
263 }
264
265 static int load_vmd_library(const char *fn, gmx_vmdplugin_t *vmdplugin)
266 {
267     char            pathname[GMX_PATH_MAX];
268     const char     *pathenv;
269     const char     *err;
270     int             ret = 0;
271     char            pathenv_buffer[GMX_PATH_MAX];
272 #if !GMX_NATIVE_WINDOWS
273     glob_t          globbuf;
274     const char     *defpath_suffix = "/plugins/*/molfile";
275     const char     *defpathenv     = GMX_VMD_PLUGIN_PATH;
276 #else
277     WIN32_FIND_DATA ffd;
278     HANDLE          hFind = INVALID_HANDLE_VALUE;
279     char            progfolder[GMX_PATH_MAX];
280     char            defpathenv[GMX_PATH_MAX];
281     const char     *defpath_suffix = "\\plugins\\WIN32\\molfile";
282     SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, progfolder);
283     sprintf(defpathenv, "%s\\University of Illinois\\VMD\\plugins\\WIN32\\molfile", progfolder);
284 #endif
285
286     vmdplugin->api      = NULL;
287     vmdplugin->filetype = strrchr(fn, '.');
288     if (!vmdplugin->filetype)
289     {
290         return 0;
291     }
292     vmdplugin->filetype++;
293
294     /* First look for an explicit path given at run time for the
295      * plugins, then an implicit run-time path, and finally for one
296      * given at configure time. This last might be hard-coded to the
297      * default for VMD installs. */
298     pathenv = getenv("VMD_PLUGIN_PATH");
299     if (pathenv == NULL)
300     {
301         pathenv = getenv("VMDDIR");
302         if (NULL == pathenv)
303         {
304             printf("\nNeither VMD_PLUGIN_PATH or VMDDIR set. ");
305             printf("Using default location:\n%s\n", defpathenv);
306             pathenv = defpathenv;
307         }
308         else
309         {
310             printf("\nVMD_PLUGIN_PATH no set, but VMDDIR is set. ");
311 #ifdef _MSC_VER
312             _snprintf_s(pathenv_buffer, sizeof(pathenv_buffer), _TRUNCATE, "%s%s", pathenv, defpath_suffix);
313 #else
314             snprintf(pathenv_buffer, sizeof(pathenv_buffer), "%s%s", pathenv, defpath_suffix);
315 #endif
316             printf("Using semi-default location:\n%s\n", pathenv_buffer);
317             pathenv = pathenv_buffer;
318         }
319     }
320     strncpy(pathname, pathenv, sizeof(pathname));
321 #if !GMX_NATIVE_WINDOWS
322     strcat(pathname, "/*.so");
323     glob(pathname, 0, NULL, &globbuf);
324     if (globbuf.gl_pathc == 0)
325     {
326         printf("\nNo VMD Plugins found\n"
327                "Set the environment variable VMD_PLUGIN_PATH to the molfile folder within the\n"
328                "VMD installation.\n"
329                "The architecture (e.g. 32bit versus 64bit) of GROMACS and VMD has to match.\n");
330         return 0;
331     }
332     for (size_t i = 0; i < globbuf.gl_pathc && vmdplugin->api == NULL; i++)
333     {
334         /* FIXME: Undefined which plugin is chosen if more than one plugin
335            can read a certain file ending. Requires some additional command
336            line option or enviroment variable to specify which plugin should
337            be picked.
338          */
339         ret |= load_sharedlibrary_plugins(globbuf.gl_pathv[i], vmdplugin);
340     }
341     globfree(&globbuf);
342 #else
343     strcat(pathname, "\\*.so");
344     hFind = FindFirstFile(pathname, &ffd);
345     if (INVALID_HANDLE_VALUE == hFind)
346     {
347         printf("\nNo VMD Plugins found\n");
348         return 0;
349     }
350     do
351     {
352         char filename[GMX_PATH_MAX];
353         sprintf(filename, "%s\\%s", pathenv, ffd.cFileName);
354         ret |= load_sharedlibrary_plugins(filename, vmdplugin);
355     }
356     while (FindNextFile(hFind, &ffd )  != 0 && vmdplugin->api == NULL);
357     FindClose(hFind);
358 #endif
359
360     if (!ret)
361     {
362         printf("\nCould not open any VMD library.\n");
363         err = vmddlerror();
364         if (!err)
365         {
366             printf("Compiled with dlopen?\n");
367         }
368         else
369         {
370             printf("Last error:\n%s\n", err);
371         }
372         return 0;
373     }
374
375     if (vmdplugin->api == NULL)
376     {
377         printf("\nNo plugin for %s found\n", vmdplugin->filetype);
378         return 0;
379     }
380
381     if (vmdplugin->api->abiversion < 10)
382     {
383         printf("\nPlugin and/or VMD is too old. At least VMD 1.8.6 is required.\n");
384         return 0;
385     }
386
387     printf("\nUsing VMD plugin: %s (%s)\n", vmdplugin->api->name, vmdplugin->api->prettyname);
388
389     return 1;
390
391 }
392
393 int read_first_vmd_frame(const char *fn, gmx_vmdplugin_t **vmdpluginp, t_trxframe *fr)
394 {
395     molfile_timestep_metadata_t *metadata = NULL;
396     gmx_vmdplugin_t             *vmdplugin;
397
398     snew(vmdplugin, 1);
399     *vmdpluginp = vmdplugin;
400     if (!load_vmd_library(fn, vmdplugin))
401     {
402         return 0;
403     }
404
405     vmdplugin->handle = vmdplugin->api->open_file_read(fn, vmdplugin->filetype, &fr->natoms);
406
407     if (!vmdplugin->handle)
408     {
409         fprintf(stderr, "\nError: could not open file '%s' for reading.\n",
410                 fn);
411         return 0;
412     }
413
414     if (fr->natoms == MOLFILE_NUMATOMS_UNKNOWN)
415     {
416         fprintf(stderr, "\nFormat of file %s does not record number of atoms.\n", fn);
417         return 0;
418     }
419     else if (fr->natoms == MOLFILE_NUMATOMS_NONE)
420     {
421         fprintf(stderr, "\nNo atoms found by VMD plugin in file %s.\n", fn );
422         return 0;
423     }
424     else if (fr->natoms < 1)     /*should not be reached*/
425     {
426         fprintf(stderr, "\nUnknown number of atoms %d for VMD plugin opening file %s.\n",
427                 fr->natoms, fn );
428         return 0;
429     }
430
431     snew(fr->x, fr->natoms);
432
433     vmdplugin->bV = 0;
434     if (vmdplugin->api->abiversion > 10 && vmdplugin->api->read_timestep_metadata)
435     {
436         vmdplugin->api->read_timestep_metadata(vmdplugin->handle, metadata);
437         assert(metadata);
438         vmdplugin->bV = metadata->has_velocities;
439         if (vmdplugin->bV)
440         {
441             snew(fr->v, fr->natoms);
442         }
443     }
444     else
445     {
446         fprintf(stderr,
447                 "\nThis trajectory is being read with a VMD plug-in from before VMD"
448                 "\nversion 1.8, or from a trajectory that lacks time step metadata."
449                 "\nEither way, GROMACS cannot tell whether the trajectory has velocities.\n");
450     }
451     return 1;
452
453 }