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