1 /* MACHINE GENERATED FILE, DO NOT EDIT! */
2 
3 #define VMDPLUGIN molfile_basissetplugin
4 #define STATIC_PLUGIN 1
5 
6 /***************************************************************************
7  *cr
8  *cr            (C) Copyright 1995-2016 The Board of Trustees of the
9  *cr                        University of Illinois
10  *cr                         All Rights Reserved
11  *cr
12  ***************************************************************************/
13 
14 /***************************************************************************
15  * RCS INFORMATION:
16  *
17  *      $RCSfile: basissetplugin.c,v $
18  *      $Author: johns $       $Locker:  $             $State: Exp $
19  *      $Revision: 1.14 $       $Date: 2016/11/28 05:01:53 $
20  *
21  ***************************************************************************/
22 
23 /* *******************************************************
24  *
25  *          B A S I S    S E T    P L U G I N
26  *
27  * This plugin reads basis sets for quantum chemical
28  * calculations. The basis set must be in the GAMESS format.
29  * Such files can be downloaded for virtually any basis set
30  * from the EMSL basis set exchange website:
31  * https://bse.pnl.gov/bse/portal
32  *
33  * ********************************************************/
34 
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <math.h>
41 
42 #include "qmplugin.h"
43 #include "unit_conversion.h"
44 
45 #define ANGSTROM 0
46 #define BOHR     1
47 #define SPIN_ALPHA 0
48 #define SPIN_BETA  1
49 
50 /*
51  * Error reporting macro for use in DEBUG mode
52  */
53 #ifdef GAMESS_DEBUG
54 #define PRINTERR fprintf(stderr, "\n In file %s, line %d: \n %s \n \n", \
55                             __FILE__, __LINE__, strerror(errno))
56 #else
57 #define PRINTERR (void)(0)
58 #endif
59 
60 /*
61  * Error reporting macro for the multiple fgets calls in
62  * the code
63  */
64 #define GET_LINE(x,y) if (!fgets(x, sizeof(x), y)) return FALSE
65 
66 #define UNK_SHELL -666
67 #define SPD_D_SHELL -5
68 #define SPD_P_SHELL -4
69 #define SPD_S_SHELL -3
70 #define SP_S_SHELL -2
71 #define SP_P_SHELL -1
72 #define S_SHELL 0
73 #define P_SHELL 1
74 #define D_SHELL 2
75 #define F_SHELL 3
76 #define G_SHELL 4
77 #define H_SHELL 5
78 
79 #define FOUND   1
80 #define STOPPED 2
81 
82 #define NUM_ELEMENTS 109
83 
84 /* Translation table for element to atomic numbers for element
85  * names used Gamess format files from EMSL */
86 static const char *elements[] = {
87   "(unknown)", "HYDROGEN", "HELIUM", "LITHIUM", "BERYLLIUM", "BORON",
88   "CARBON", "NITROGEN", "OXYGEN", "FLUORINE", "NEON",
89   "SODIUM", "MAGNESIUM", "ALUMINUM", "SILICON", "PHOSPHOROUS",
90   "SULFUR", "CHLORINE", "ARGON", "POTASSIUM", "CALCIUM", "SCANDIUM",
91   "TITANIUM", "VANADIUM", "CHROMIUM", "MANGANESE", "IRON", "COBALT",
92   "NICKEL", "COPPER", "ZINC", "GALLIUM", "GERMANIUM", "ARSENIC",
93   "SELENIUM", "BROMINE", "KRYPTON",
94   "RUBIDIUM", "STRONTIUM", "YTTRIUM", "ZIRCONIUM", "NIOBIUM",
95   "MOLYBDENUM", "TECHNETIUM", "RUTHENIUM", "RHODIUM", "PALLADIUM",
96   "SILVER", "CADMIUM", "INDIUM", "TIN", "ANTIMONY", "TELLURIUM",
97   "IODINE", "XENON",
98   "CESIUM", "BARIUM", "LANTHANUM", "CER", "PRASEODYMIUM", "NEODYMIUM",
99   "PROMETIUM", "SAMARIUM", "EUROPIUM", "GADOLIUM", "TERBIUM",
100   "DYSPROSIUM", "HOLMIUM", "ERBIUM", "THULIUM", "YTTERBIUM",
101   "LUTETIUM", "HAFNIUM", "TANTALUM", "TUNGSTEN", "RHENIUM", "OSMIUM",
102   "IRIDIUM", "PLATINUM", "GOLD", "MERCURY", "THALLIUM", "LEAD",
103   "BISMUTH", "POLONIUM", "ASTATINE", "RADON",
104   "FRANCIUM", "RADIUM", "ACTINIUM", "THORIUM", "PROTACTINIUM",
105   "URANIUM", "NEPTUNIUM", "PLUTONIUM", "AMERICIUM", "CURIUM",
106   "BERKELIUM", "CALIFORNIUM", "EINSTEINIUM", "FERMIUM", "MENDELEVIUM",
107   "NOBELIUM", "LAWRENCIUM", "RUTHERFORDIUM", "DUBNIUM", "SEABORGIUM",
108   "BOHRIUM", "HASSIUM", "MEITNERIUM"};
109 
110 
111 
112 /* ######################################################## */
113 /* declaration/documentation of internal (static) functions */
114 /* ######################################################## */
115 
116 static void print_input_data(qmdata_t *);
117 
118 
119 /* the function get_basis we also parse the basis function section to
120  * determine the number of basis functions, contraction
121  * coefficients. For Pople/Huzinga style basis sets
122  * this numbers are in principle fixed, and could hence
123  * be provided by the the plugin itself; however, the user might
124  * define his own basis/contraction coeffients and hence reading
125  * them from the input file seem to be somewhat more general. */
126 static int get_basis (qmdata_t *);
127 
128 
129 /* read all primitives for the current shell */
130 static int read_shell_primitives(qmdata_t *, prim_t **prim,
131                                  char *shellsymm, int icoeff);
132 
133 /* convert shell type from char to int */
134 static int shelltype_int(char type);
135 
136 /* Populate the flat arrays containing the basis set data */
137 static int fill_basis_arrays(qmdata_t *);
138 
139 
140 /* ######################################################## */
141 /* Functions that are needed by the molfile_plugin          */
142 /* interface to provide VMD with the parsed data            */
143 /* ######################################################## */
144 
145 
146 /***************************************************************
147  *
148  * Called by VMD to open the file and get the number
149  * of atoms.
150  *
151  * *************************************************************/
open_basis_read(const char * filename,const char * filetype,int * natoms)152 static void *open_basis_read(const char *filename,
153                   const char *filetype, int *natoms) {
154 
155   FILE *fd;
156   qmdata_t *data;
157 
158 
159   /* open the input file */
160   fd = fopen(filename, "rb");
161 
162   if (!fd) {
163     PRINTERR;
164     return NULL;
165   }
166 
167   /* allocate memory for main data structure */
168   data = (qmdata_t *)calloc(1,sizeof(qmdata_t));
169 
170   /* make sure memory was allocated properly */
171   if (data == NULL) {
172     PRINTERR;
173     return NULL;
174   }
175 
176   data->num_shells = 0;
177   data->num_basis_funcs = 0;
178   data->num_basis_atoms = 0;
179 
180   /* initialize some of the character arrays */
181   memset(data->basis_string,0,sizeof(data->basis_string));
182 
183   /* store file pointer in qmdata_t struct */
184   data->file = fd;
185 
186   /* Read the basis set */
187   if (!get_basis(data)) return NULL;
188 
189 
190   /* provide VMD with the proper number of atoms */
191   *natoms = 0;
192 
193   /* Test print the parsed data in same format as logfile */
194   print_input_data(data);
195 
196   return data;
197 }
198 
199 
200 
201 
202 /*****************************************************
203  *
204  * provide VMD with the sizes of the QM related
205  * data structure arrays that need to be made
206  * available
207  *
208  *****************************************************/
read_basis_metadata(void * mydata,molfile_qm_metadata_t * metadata)209 static int read_basis_metadata(void *mydata,
210     molfile_qm_metadata_t *metadata) {
211 
212   qmdata_t *data = (qmdata_t *)mydata;
213 
214   metadata->ncart = 0;
215   metadata->nimag = 0;
216   metadata->nintcoords = 0;
217 
218   metadata->have_sysinfo = 0;
219   metadata->have_carthessian = 0;
220   metadata->have_inthessian = 0;
221   metadata->have_normalmodes = 0;
222 
223   /* orbital + basis set data */
224   metadata->num_basis_funcs = data->num_basis_funcs;
225   metadata->num_basis_atoms = data->num_basis_atoms;
226   metadata->num_shells      = data->num_shells;
227   metadata->wavef_size      = 0;
228 
229   return MOLFILE_SUCCESS;
230 }
231 
232 
233 /******************************************************
234  *
235  * Provide VMD with the static (i.e. non-trajectory)
236  * data. That means we are filling the molfile_plugin
237  * data structures.
238  *
239  ******************************************************/
read_basis_rundata(void * mydata,molfile_qm_t * qm_data)240 static int read_basis_rundata(void *mydata,
241                                molfile_qm_t *qm_data) {
242 
243   qmdata_t *data = (qmdata_t *)mydata;
244   int i;
245   molfile_qm_basis_t   *basis_data   = &qm_data->basis;
246 
247 /*   strncpy(sys_data->basis_string, data->basis_string, */
248 /*           sizeof(sys_data->basis_string)); */
249 
250 
251 #if vmdplugin_ABIVERSION > 11
252   /* fill in molfile_qm_basis_t */
253   if (data->num_basis_funcs) {
254     for (i=0; i<data->num_basis_atoms; i++) {
255       basis_data->num_shells_per_atom[i] = data->num_shells_per_atom[i];
256       basis_data->atomic_number[i] = data->atomicnum_per_basisatom[i];
257     }
258 
259     for (i=0; i<data->num_shells; i++) {
260       basis_data->num_prim_per_shell[i] = data->num_prim_per_shell[i];
261       basis_data->shell_types[i] = data->shell_types[i];
262     }
263 
264     for (i=0; i<2*data->num_basis_funcs; i++) {
265       basis_data->basis[i] = data->basis[i];
266     }
267   }
268 #endif
269 
270   return MOLFILE_SUCCESS;
271 }
272 
273 
274 
275 /**********************************************************
276  *
277  * clean up when done and free all the memory do avoid
278  * memory leaks
279  *
280  **********************************************************/
close_basis_read(void * mydata)281 static void close_basis_read(void *mydata) {
282 
283   qmdata_t *data = (qmdata_t *)mydata;
284   int i, j;
285   fclose(data->file);
286 
287   free(data->basis);
288   free(data->shell_types);
289   free(data->atomicnum_per_basisatom);
290   free(data->num_shells_per_atom);
291   free(data->num_prim_per_shell);
292   free(data->angular_momentum);
293   free(data->filepos_array);
294 
295   if (data->basis_set) {
296     for(i=0; i<data->num_basis_atoms; i++) {
297       for (j=0; j<data->basis_set[i].numshells; j++) {
298         free(data->basis_set[i].shell[j].prim);
299       }
300       free(data->basis_set[i].shell);
301     }
302     free(data->basis_set);
303   }
304 
305   free(data);
306 }
307 
308 /* ####################################################### */
309 /*             End of API functions                        */
310 /* The following functions actually do the file parsing.   */
311 /* ####################################################### */
312 
313 
314 #define TORF(x) (x ? "T" : "F")
315 
print_input_data(qmdata_t * data)316 static void print_input_data(qmdata_t *data) {
317   int i, j, k;
318   int primcount=0;
319   int shellcount=0;
320 
321 /*   printf("\n"); */
322 /*   printf("     BASIS OPTIONS\n"); */
323 /*   printf("     -------------\n"); */
324 /*   printf("%s\n", data->basis_string); */
325 /*   printf("\n\n\n"); */
326   printf("\n");
327   printf("     ATOMIC BASIS SET\n");
328   printf("     ----------------\n");
329   printf(" THE CONTRACTED PRIMITIVE FUNCTIONS HAVE BEEN UNNORMALIZED\n");
330   printf(" THE CONTRACTED BASIS FUNCTIONS ARE NOW NORMALIZED TO UNITY\n");
331   printf("\n");
332   printf("  SHELL TYPE  PRIMITIVE        EXPONENT          CONTRACTION COEFFICIENT(S)\n");
333   printf("\n");
334 
335   printf(" =================================================================\n");
336   for (i=0; i<data->num_basis_atoms; i++) {
337     printf("%-8d (%10s)\n\n", data->basis_set[i].atomicnum, data->basis_set[i].name);
338     printf("\n");
339 
340     for (j=0; j<data->basis_set[i].numshells; j++) {
341 
342       for (k=0; k<data->basis_set[i].shell[j].numprims; k++) {
343         printf("%6d   %d %7d %22f%22f\n", j,
344                data->basis_set[i].shell[j].type,
345                primcount+1,
346                data->basis_set[i].shell[j].prim[k].exponent,
347                data->basis_set[i].shell[j].prim[k].contraction_coeff);
348         primcount++;
349       }
350 
351       printf("\n");
352       shellcount++;
353     }
354   }
355   printf("\n");
356   printf(" TOTAL NUMBER OF BASIS SET SHELLS             =%5d\n", data->num_shells);
357   printf(" TOTAL NUMBER OF ATOMS                        =%5i\n", data->numatoms);
358   printf("\n");
359 }
360 
361 
362 
363 
364 /*******************************************************
365  *
366  * this function reads in the basis set data
367  *
368  * ******************************************************/
get_basis(qmdata_t * data)369 int get_basis(qmdata_t *data) {
370 
371   char buffer[BUFSIZ];
372   char word[4][BUFSIZ];
373   int i = 0;
374   int success = 0;
375   int numread, numshells;
376   shell_t *shell;
377   long filepos;
378 
379   /* initialize buffers */
380   buffer[0] = '\0';
381   for (i=0; i<3; i++) word[i][0] = '\0';
382 
383   if (!pass_keyline(data->file, "$DATA", NULL))
384     printf("basissetplugin) No basis set found!\n");
385 
386 
387   /* Allocate space for the basis for all atoms */
388   /* When the molecule is symmetric the actual number atoms with
389    * a basis set could be smaller */
390   data->basis_set = (basis_atom_t*)calloc(1, sizeof(basis_atom_t));
391 
392 
393   i = 0; /* basis atom counter */
394 
395   do {
396     prim_t *prim = NULL;
397     char shelltype;
398     int numprim = 0;
399     int icoeff = 0;
400     filepos = ftell(data->file);
401     GET_LINE(buffer, data->file);
402 
403     /* Count the number of relevant words in the line. */
404     numread = sscanf(buffer,"%s %s %s %s",&word[0][0], &word[1][0],
405            &word[2][0], &word[3][0]);
406 
407     if (!strcmp(&word[0][0], "$END")) break;
408 
409     switch (numread) {
410       case 1:
411         /* Next atom */
412         if (i>0) {
413           data->basis_set = (basis_atom_t*)realloc(data->basis_set, (i+1)*sizeof(basis_atom_t));
414         }
415 
416         strcpy(data->basis_set[i].name, &word[0][0]);
417 
418 
419         /* read the basis set for the current atom */
420         shell = (shell_t*)calloc(1, sizeof(shell_t));
421         numshells = 0;
422 
423         do {
424           filepos = ftell(data->file);
425           numprim = read_shell_primitives(data, &prim, &shelltype, icoeff);
426 
427           if (numprim>0) {
428             /* make sure we have eiter S, L, P, D, F or G shells */
429             if ( (shelltype!='S' && shelltype!='L' && shelltype!='P' &&
430                   shelltype!='D' && shelltype!='F' && shelltype!='G') ) {
431               printf("basissetplugin) WARNING ... %c shells are not supported \n", shelltype);
432             }
433 
434             /* create new shell */
435             if (numshells) {
436               shell = (shell_t*)realloc(shell, (numshells+1)*sizeof(shell_t));
437             }
438             shell[numshells].numprims = numprim;
439             shell[numshells].type = shelltype_int(shelltype);
440             shell[numshells].prim = prim;
441             data->num_basis_funcs += numprim;
442 
443             /* We split L-shells into one S and one P-shell.
444              * I.e. for L-shells we have to go back read the shell again
445              * this time using the second contraction coefficients. */
446             if (shelltype=='L' && !icoeff) {
447               fseek(data->file, filepos, SEEK_SET);
448               icoeff++;
449             } else if (shelltype=='L' && icoeff) {
450               shell[numshells].type = SP_P_SHELL;
451               icoeff = 0;
452             }
453 
454             numshells++;
455           }
456         } while (numprim);
457 
458         /* store shells in atom */
459         data->basis_set[i].numshells = numshells;
460         data->basis_set[i].shell = shell;
461 
462         /* store the total number of basis functions */
463         data->num_shells += numshells;
464         i++;
465 
466         /* go back one line so that we can read the name of the
467          * next atom */
468         fseek(data->file, filepos, SEEK_SET);
469 
470         break;
471 
472     }
473 
474   } while (!success);
475 
476 
477   printf("basissetplugin) Parsed %d uncontracted basis functions for %d atoms.\n",
478          data->num_basis_funcs, i);
479 
480   data->num_basis_atoms = i;
481 
482   /* allocate and populate flat arrays needed for molfileplugin */
483   return fill_basis_arrays(data);
484 }
485 
486 
487 /**************************************************
488  *
489  * Convert shell type from char to int.
490  *
491  ************************************************ */
shelltype_int(char type)492 static int shelltype_int(char type) {
493   int shelltype;
494 
495   switch (type) {
496     case 'L':
497       shelltype = SP_S_SHELL;
498       break;
499     case 'M':
500       shelltype = SP_P_SHELL;
501       break;
502     case 'S':
503       shelltype = S_SHELL;
504       break;
505     case 'P':
506       shelltype = P_SHELL;
507       break;
508     case 'D':
509       shelltype = D_SHELL;
510       break;
511     case 'F':
512       shelltype = F_SHELL;
513       break;
514     case 'G':
515       shelltype = G_SHELL;
516       break;
517     default:
518       shelltype = UNK_SHELL;
519       break;
520   }
521 
522   return shelltype;
523 }
524 
525 
526 
527 /******************************************************
528  *
529  * Populate the flat arrays containing the basis
530  * set data.
531  *
532  ******************************************************/
fill_basis_arrays(qmdata_t * data)533 static int fill_basis_arrays(qmdata_t *data) {
534   int i, j, k;
535   int shellcount = 0;
536   int primcount = 0;
537   float *basis;
538   int *num_shells_per_atom;
539   int *num_prim_per_shell;
540   int *shell_types;
541   int *atomicnum_per_basisatom;
542 
543   /* Count the total number of primitives which
544    * determines the size of the basis array. */
545   for(i=0; i<data->num_basis_atoms; i++) {
546     for (j=0; j<data->basis_set[i].numshells; j++) {
547       primcount += data->basis_set[i].shell[j].numprims;
548     }
549   }
550 
551   /* reserve space for pointer to array containing basis
552    * info, i.e. contraction coeficients and expansion
553    * coefficients; need 2 entries per basis function, i.e.
554    * exponent and contraction coefficient; also,
555    * allocate space for the array holding the orbital symmetry
556    * information per primitive Gaussian.
557    * Finally, initialize the arrays holding the number of
558    * shells per atom and the number of primitives per shell*/
559   basis = (float *)calloc(2*primcount,sizeof(float));
560 
561   /* make sure memory was allocated properly */
562   if (basis == NULL) {
563     PRINTERR;
564     return MOLFILE_ERROR;
565   }
566 
567   shell_types = (int *)calloc(data->num_shells, sizeof(int));
568 
569   /* make sure memory was allocated properly */
570   if (shell_types == NULL) {
571     PRINTERR;
572     return MOLFILE_ERROR;
573   }
574 
575   num_shells_per_atom = (int *)calloc(data->num_basis_atoms, sizeof(int));
576 
577   /* make sure memory was allocated properly */
578   if (num_shells_per_atom == NULL) {
579     PRINTERR;
580     return MOLFILE_ERROR;
581   }
582 
583   num_prim_per_shell = (int *)calloc(data->num_shells, sizeof(int));
584 
585   /* make sure memory was allocated properly */
586   if (num_prim_per_shell == NULL) {
587     PRINTERR;
588     return MOLFILE_ERROR;
589   }
590 
591   atomicnum_per_basisatom = (int *)calloc(data->num_basis_atoms, sizeof(int));
592 
593   /* make sure memory was allocated properly */
594   if (atomicnum_per_basisatom == NULL) {
595     PRINTERR;
596     return MOLFILE_ERROR;
597   }
598 
599 
600   /* store pointers in struct qmdata_t */
601   data->basis = basis;
602   data->shell_types = shell_types;
603   data->num_shells_per_atom = num_shells_per_atom;
604   data->num_prim_per_shell = num_prim_per_shell;
605   data->atomicnum_per_basisatom = atomicnum_per_basisatom;
606 
607   primcount = 0;
608   for (i=0; i<data->num_basis_atoms; i++) {
609     int j;
610     /* assign atomic number from element name */
611     data->basis_set[i].atomicnum = 0;
612     for (j=0; j<NUM_ELEMENTS; j++) {
613       if (!strcmp(elements[j], data->basis_set[i].name)) {
614         data->basis_set[i].atomicnum = j;
615         break;
616       }
617     }
618     atomicnum_per_basisatom[i] = data->basis_set[i].atomicnum;
619 
620     num_shells_per_atom[i] = data->basis_set[i].numshells;
621 
622     for (j=0; j<data->basis_set[i].numshells; j++) {
623       shell_types[shellcount] = data->basis_set[i].shell[j].type;
624       num_prim_per_shell[shellcount] = data->basis_set[i].shell[j].numprims;
625 
626       for (k=0; k<data->basis_set[i].shell[j].numprims; k++) {
627         basis[2*primcount  ] = data->basis_set[i].shell[j].prim[k].exponent;
628         basis[2*primcount+1] = data->basis_set[i].shell[j].prim[k].contraction_coeff;
629         primcount++;
630       }
631       shellcount++;
632     }
633   }
634 
635   return TRUE;
636 }
637 
638 
639 /******************************************************
640  *
641  * read all primitives for the current shell
642  *
643  ******************************************************/
read_shell_primitives(qmdata_t * data,prim_t ** prim,char * shelltype,int icoeff)644 static int read_shell_primitives(qmdata_t *data, prim_t **prim, char *shelltype,
645                                  int icoeff) {
646   char buffer[BUFSIZ];
647   float exponent = 0.0;
648   float contract[2] = {0.0, 0.0};
649   int i, success;
650   int primcounter = 0, nprim = 0;;
651 
652   GET_LINE(buffer, data->file);
653   success = sscanf(buffer,"%c %d", shelltype, &nprim);
654 
655   (*prim) = (prim_t*)calloc(nprim, sizeof(prim_t));
656 
657   for (i=0; i<nprim; i++) {
658     GET_LINE(buffer, data->file);
659     success = sscanf(buffer,"%*d %f %f %f",
660                        &exponent, &contract[0], &contract[1]);
661 
662     /* store in basis array and increase the counter */
663     switch (success) {
664       case 2:
665         /* store exponent */
666         (*prim)[i].exponent = exponent;
667 
668         /* store coefficient */
669         (*prim)[i].contraction_coeff = contract[0];
670 
671         primcounter++;
672         break;
673 
674       case 3:
675         /* store exponent */
676         (*prim)[i].exponent = exponent;
677 
678         /* store coefficient */
679         (*prim)[i].contraction_coeff = contract[icoeff];
680 
681         primcounter++;
682         break;
683 
684       case -1:
685         /* otherwise it's an empty line which represents the end of the shell */
686         break;
687 
688       case 1:
689         /* the user had given the next atom a numeric name */
690         break;
691     }
692 
693   }
694 
695   if (!primcounter) free(*prim);
696 
697   return primcounter;
698 }
699 
700 
701 
702 
703 /*************************************************************
704  *
705  * plugin registration
706  *
707  **************************************************************/
708 static molfile_plugin_t plugin;
709 
VMDPLUGIN_init(void)710 VMDPLUGIN_API int VMDPLUGIN_init(void) {
711   memset(&plugin, 0, sizeof(molfile_plugin_t));
712   plugin.abiversion = vmdplugin_ABIVERSION;
713   plugin.type = MOLFILE_PLUGIN_TYPE;
714   plugin.name = "basisset";
715   plugin.prettyname = "Basis Set";
716   plugin.author = "Jan Saam";
717   plugin.majorv = 0;
718   plugin.minorv = 1;
719   plugin.is_reentrant = VMDPLUGIN_THREADUNSAFE;
720   plugin.filename_extension = "basis";
721   plugin.open_file_read  = open_basis_read;
722   plugin.close_file_read = close_basis_read;
723   plugin.read_structure = NULL;
724 
725   plugin.read_qm_metadata = read_basis_metadata;
726   plugin.read_qm_rundata  = read_basis_rundata;
727 
728 #if vmdplugin_ABIVERSION > 11
729   plugin.read_timestep_metadata    = NULL;
730   plugin.read_qm_timestep_metadata = NULL;
731   plugin.read_timestep = NULL;
732 #endif
733 
734   return VMDPLUGIN_SUCCESS;
735 }
736 
VMDPLUGIN_register(void * v,vmdplugin_register_cb cb)737 VMDPLUGIN_API int VMDPLUGIN_register(void *v, vmdplugin_register_cb cb) {
738   (*cb)(v, (vmdplugin_t *)&plugin);
739   return VMDPLUGIN_SUCCESS;
740 }
741 
VMDPLUGIN_fini(void)742 VMDPLUGIN_API int VMDPLUGIN_fini(void) {
743   return VMDPLUGIN_SUCCESS;
744 }
745