Fix MingW build
[alexxy/gromacs.git] / src / gromacs / fileio / vmdio.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2012,2013,2014, 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
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 /* Derived from PluginMgr.C and catdcd.c */
41
42 /* PluginMgr.C: Copyright: */
43 /***************************************************************************
44  * cr
45  * cr            (C) Copyright 1995-2009 The Board of Trustees of the
46  * cr                        University of Illinois
47  * cr                         All Rights Reserved
48  * cr
49    Developed by:           Theoretical and Computational Biophysics Group
50                         University of Illinois at Urbana-Champaign
51                         http://www.ks.uiuc.edu/
52
53    Permission is hereby granted, free of charge, to any person obtaining a copy of
54    this software and associated documentation files (the Software), to deal with
55    the Software without restriction, including without limitation the rights to
56    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
57    of the Software, and to permit persons to whom the Software is furnished to
58    do so, subject to the following conditions:
59
60    Redistributions of source code must retain the above copyright notice,
61    this list of conditions and the following disclaimers.
62
63    Redistributions in binary form must reproduce the above copyright notice,
64    this list of conditions and the following disclaimers in the documentation
65    and/or other materials provided with the distribution.
66
67    Neither the names of Theoretical and Computational Biophysics Group,
68    University of Illinois at Urbana-Champaign, nor the names of its contributors
69    may be used to endorse or promote products derived from this Software without
70    specific prior written permission.
71
72    THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
73    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
74    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
75    THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
76    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
77    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
78    OTHER DEALINGS WITH THE SOFTWARE.
79  ***************************************************************************/
80
81 /* catdcd.c: Copyright: */
82 /*****************************************************************************/
83 /*                                                                           */
84 /* (C) Copyright 2001-2005 Justin Gullingsrud and the University of Illinois.*/
85 /*                                                                           */
86 /*****************************************************************************/
87
88 #include <stdlib.h>
89 #include <stdio.h>
90 #include <string.h>
91 #include <assert.h>
92
93 #include <config.h>
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 #ifndef 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 <windows.h>
106 #include <shlobj.h>
107 #endif
108 #include "gromacs/utility/smalloc.h"
109 #include "futil.h"
110 #include "vmdio.h"
111
112
113 #include "types/simple.h"
114 #include "vec.h"
115 #include "gmxfio.h"
116
117
118 typedef int (*initfunc)(void);
119 typedef int (*regfunc)(void *, vmdplugin_register_cb);
120 typedef int (*finifunc)(void);
121
122
123
124 static int register_cb(void *v, vmdplugin_t *p)
125 {
126     const char     *key       = p->name;
127     t_gmxvmdplugin *vmdplugin = (t_gmxvmdplugin*)v;
128
129     if (strcmp(key, vmdplugin->filetype) == 0)
130     {
131         vmdplugin->api = (molfile_plugin_t *)p;
132     }
133     return VMDPLUGIN_SUCCESS;
134 }
135
136 static int load_sharedlibrary_plugins(const char *fullpath, t_gmxvmdplugin* vmdplugin)
137 {
138     /* Open the dll; try to execute the init function. */
139     void *handle, *ifunc, *registerfunc;
140     handle = vmddlopen(fullpath);
141     if (!handle)
142     {
143         if (debug)
144         {
145             fprintf(debug, "\nUnable to open dynamic library %s.\n%s\n",  fullpath, vmddlerror());         /*only to debug because of stdc++ erros */
146         }
147         return 0;
148     }
149
150     ifunc = vmddlsym(handle, "vmdplugin_init");
151     if (!ifunc || ((initfunc)(ifunc))())
152     {
153         printf("\nvmdplugin_init() for %s returned an error; plugin(s) not loaded.\n", fullpath);
154         vmddlclose(handle);
155         return 0;
156     }
157
158     registerfunc = vmddlsym(handle, "vmdplugin_register");
159     if (!registerfunc)
160     {
161         printf("\nDidn't find the register function in %s; plugin(s) not loaded.\n", fullpath);
162         vmddlclose(handle);
163         return 0;
164     }
165     else
166     {
167         /* Load plugins from the library.*/
168         ((regfunc)registerfunc)(vmdplugin, register_cb);
169     }
170
171     /* in case this library does not support the filetype, close it */
172     if (vmdplugin->api == NULL)
173     {
174         vmddlclose(handle);
175     }
176
177     return 1;
178 }
179
180 /*return: 1: success, 0: last frame, -1: error*/
181 gmx_bool read_next_vmd_frame(t_trxframe *fr)
182 {
183     int                rc, i;
184     rvec               vec, angle;
185     molfile_timestep_t ts;
186
187
188     fr->bV = fr->vmdplugin->bV;
189
190 #ifdef GMX_DOUBLE
191     snew(ts.coords, fr->natoms*3);
192     if (fr->bV)
193     {
194         snew(ts.velocities, fr->natoms*3);
195     }
196 #else
197     ts.coords = (float*)fr->x;
198     if (fr->bV)
199     {
200         ts.velocities = (float*)fr->v;
201     }
202 #endif
203
204     rc = fr->vmdplugin->api->read_next_timestep(fr->vmdplugin->handle, fr->natoms, &ts);
205
206     if (rc < -1)
207     {
208         fprintf(stderr, "\nError reading input file (error code %d)\n", rc);
209     }
210     if (rc < 0)
211     {
212         fr->vmdplugin->api->close_file_read(fr->vmdplugin->handle);
213         return 0;
214     }
215
216 #ifdef GMX_DOUBLE
217     for (i = 0; i < fr->natoms; i++)
218     {
219         fr->x[i][0] = .1*ts.coords[i*3];
220         fr->x[i][1] = .1*ts.coords[i*3+1];
221         fr->x[i][2] = .1*ts.coords[i*3+2];
222         if (fr->bV)
223         {
224             fr->v[i][0] = .1*ts.velocities[i*3];
225             fr->v[i][1] = .1*ts.velocities[i*3+1];
226             fr->v[i][2] = .1*ts.velocities[i*3+2];
227         }
228     }
229     sfree(ts.coords);
230     if (fr->bV)
231     {
232         sfree(ts.velocities);
233     }
234 #else
235     for (i = 0; i < fr->natoms; i++)
236     {
237         svmul(.1, fr->x[i], fr->x[i]);
238         if (fr->bV)
239         {
240             svmul(.1, fr->v[i], fr->v[i]);
241         }
242     }
243 #endif
244
245     fr->bX   = 1;
246     fr->bBox = 1;
247     vec[0]   = .1*ts.A; vec[1] = .1*ts.B; vec[2] = .1*ts.C;
248     angle[0] = ts.alpha; angle[1] = ts.beta; angle[2] = ts.gamma;
249     matrix_convert(fr->box, vec, angle);
250     if (fr->vmdplugin->api->abiversion > 10)
251     {
252         fr->bTime = TRUE;
253         fr->time  = ts.physical_time;
254     }
255     else
256     {
257         fr->bTime = FALSE;
258     }
259
260
261     return 1;
262 }
263
264 static int load_vmd_library(const char *fn, t_gmxvmdplugin *vmdplugin)
265 {
266     char            pathname[GMX_PATH_MAX], filename[GMX_PATH_MAX];
267     const char     *pathenv;
268     const char     *err;
269     int             i;
270     int             ret = 0;
271     char            pathenv_buffer[GMX_PATH_MAX];
272 #ifndef 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 #ifndef 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 (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         sprintf(filename, "%s\\%s", pathenv, ffd.cFileName);
353         ret |= load_sharedlibrary_plugins(filename, vmdplugin);
354     }
355     while (FindNextFile(hFind, &ffd )  != 0 && vmdplugin->api == NULL);
356     FindClose(hFind);
357 #endif
358
359     if (!ret)
360     {
361         printf("\nCould not open any VMD library.\n");
362         err = vmddlerror();
363         if (!err)
364         {
365             printf("Compiled with dlopen?\n");
366         }
367         else
368         {
369             printf("Last error:\n%s\n", err);
370         }
371         return 0;
372     }
373
374     if (vmdplugin->api == NULL)
375     {
376         printf("\nNo plugin for %s found\n", vmdplugin->filetype);
377         return 0;
378     }
379
380     if (vmdplugin->api->abiversion < 10)
381     {
382         printf("\nPlugin and/or VMD is too old. At least VMD 1.8.6 is required.\n");
383         return 0;
384     }
385
386     printf("\nUsing VMD plugin: %s (%s)\n", vmdplugin->api->name, vmdplugin->api->prettyname);
387
388     return 1;
389
390 }
391
392 int read_first_vmd_frame(const char *fn, t_trxframe *fr)
393 {
394     molfile_timestep_metadata_t *metadata = NULL;
395
396     snew(fr->vmdplugin, 1);
397     if (!load_vmd_library(fn, fr->vmdplugin))
398     {
399         return 0;
400     }
401
402     fr->vmdplugin->handle = fr->vmdplugin->api->open_file_read(fn, fr->vmdplugin->filetype, &fr->natoms);
403
404     if (!fr->vmdplugin->handle)
405     {
406         fprintf(stderr, "\nError: could not open file '%s' for reading.\n",
407                 fn);
408         return 0;
409     }
410
411     if (fr->natoms == MOLFILE_NUMATOMS_UNKNOWN)
412     {
413         fprintf(stderr, "\nFormat of file %s does not record number of atoms.\n", fn);
414         return 0;
415     }
416     else if (fr->natoms == MOLFILE_NUMATOMS_NONE)
417     {
418         fprintf(stderr, "\nNo atoms found by VMD plugin in file %s.\n", fn );
419         return 0;
420     }
421     else if (fr->natoms < 1)     /*should not be reached*/
422     {
423         fprintf(stderr, "\nUnknown number of atoms %d for VMD plugin opening file %s.\n",
424                 fr->natoms, fn );
425         return 0;
426     }
427
428     snew(fr->x, fr->natoms);
429
430     fr->vmdplugin->bV = 0;
431     if (fr->vmdplugin->api->abiversion > 10 && fr->vmdplugin->api->read_timestep_metadata)
432     {
433         fr->vmdplugin->api->read_timestep_metadata(fr->vmdplugin->handle, metadata);
434         assert(metadata);
435         fr->vmdplugin->bV = metadata->has_velocities;
436         if (fr->vmdplugin->bV)
437         {
438             snew(fr->v, fr->natoms);
439         }
440     }
441     else
442     {
443         fprintf(stderr,
444                 "\nThis trajectory is being read with a VMD plug-in from before VMD"
445                 "\nversion 1.8, or from a trajectory that lacks time step metadata."
446                 "\nEither way, GROMACS cannot tell whether the trajectory has velocities.\n");
447     }
448     return 1;
449
450 }