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