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