Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

TclVolMap.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2019 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: TclVolMap.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.123 $      $Date: 2019/11/06 23:36:09 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  * These are essentially just Tcl wrappers for the volmap commands in
00019  * VolMapCreate.C.
00020  *
00021  ***************************************************************************/
00022 
00023 #include <math.h>
00024 #include <stdlib.h>
00025 #include <tcl.h>
00026 #include "TclCommands.h"
00027 #include "AtomSel.h"
00028 #include "VMDApp.h"
00029 #include "MoleculeList.h"
00030 #include "config.h"
00031 #include "Measure.h"
00032 #include "VolumetricData.h"
00033 #include "VolMapCreate.h"
00034 #include "Inform.h"
00035 #include "MeasureSymmetry.h"
00036 
00037 // XXX Todo List: 
00038 // - Make this into an independent Tcl function 
00039 //  (e.g.: "volmap new density <blah...>"
00040 // - Make friends with as-of-yet non-existing VMD volumetric map I/O
00041 // - parse and allow user to set useful params
00042 
00043 // Function: volmap <maptype> <selection> [-weight <none|atom value|string array>] 
00044 // Options for all maptypes:
00045 //   -allframes
00046 //   -res <res>
00047 // Options for "density":
00048 //   -weight <none|atom value|string array>
00049 //   -scale <radius scale>
00050 
00051 
00052 static int parse_minmax_args(Tcl_Interp *interp, int arg_minmax,
00053                              Tcl_Obj * const objv[], double *minmax) {
00054   int num, i;
00055   Tcl_Obj **data, **vecmin, **vecmax;
00056     
00057   // get the list containing minmax
00058   if (Tcl_ListObjGetElements(interp, objv[arg_minmax], &num, &data) != TCL_OK) {
00059     Tcl_SetResult(interp, (char *)"volmap: could not read parameter (-minmax)", TCL_STATIC);
00060     return TCL_ERROR;
00061   }
00062   if (num != 2) {
00063     Tcl_SetResult(interp, (char *)"volmap: minmax requires a list with two vectors (-minmax)", TCL_STATIC);
00064     return TCL_ERROR;
00065   }
00066   // get the list containing min
00067   if (Tcl_ListObjGetElements(interp, data[0], &num, &vecmin) != TCL_OK) {
00068     return TCL_ERROR;
00069   }
00070   if (num != 3) {
00071     Tcl_SetResult(interp, (char *)"volmap: the first vector does not contain 3 elements (-minmax)", TCL_STATIC);
00072     return TCL_ERROR;
00073   }
00074   // get the list containing max
00075   if (Tcl_ListObjGetElements(interp, data[1], &num, &vecmax) != TCL_OK) {
00076     return TCL_ERROR;
00077   }
00078   if (num != 3) {
00079     Tcl_SetResult(interp, (char *)"volmap: the second vector does not contain 3 elements (-minmax)", TCL_STATIC);
00080     return TCL_ERROR;
00081   }
00082 
00083   // read min
00084   for (i=0; i<3; i++)
00085     if (Tcl_GetDoubleFromObj(interp, vecmin[i], minmax+i) != TCL_OK)
00086       return TCL_ERROR;
00087     
00088   // read max
00089   for (i=0; i<3; i++)
00090     if (Tcl_GetDoubleFromObj(interp, vecmax[i], minmax+i+3) != TCL_OK)
00091       return TCL_ERROR;
00092     
00093   // Check that range is valid...
00094   if (minmax[0] >= minmax[3] || minmax[1] >= minmax[4] || minmax[2] >= minmax[5]) {
00095     Tcl_SetResult(interp, (char *)"volmap: invalid minmax range (-minmax)", TCL_STATIC);
00096     return TCL_ERROR;
00097   }
00098 
00099   return TCL_OK;
00100 }
00101 
00102 
00103 static int vmd_volmap_ils(VMDApp *app, int argc, Tcl_Obj * const objv[], Tcl_Interp *interp) {
00104   bool bad_usage = false;
00105   bool bailout = false;
00106   double cutoff       = 10.;
00107   double resolution   = 1.;
00108   double minmax[6];
00109   bool pbc = false;
00110   bool pbcbox = false;
00111   float *pbccenter = NULL;
00112 
00113   int maskonly = 0;
00114   bool export_to_file = false;
00115   int molid = -1;
00116   char *filebase = NULL;
00117   char *filename = NULL;
00118 
00119   int    nprobecoor   = 0;
00120   int    nprobevdw    = 0;
00121   int    nprobecharge = 0;
00122   float *probe_vdwrmin = NULL;
00123   float *probe_vdweps  = NULL;
00124   float *probe_coords  = NULL;
00125   float *probe_charge  = NULL;
00126   double temperature = 300.0;
00127   double maxenergy   = 150.0;
00128   int subres = 3;
00129   int num_conf = 0;  // number of ligand rotamers
00130   AtomSel *probesel = NULL;
00131   AtomSel *alignsel = NULL;
00132   Matrix4 *transform = NULL;
00133 
00134   if (argc<3) {
00135     Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<molid> <minmax> [options...]");
00136     return TCL_ERROR;
00137   }
00138 
00139   // Get the molecule ID
00140   if (!strcmp(Tcl_GetStringFromObj(objv[1], NULL), "top"))
00141     molid = app->molecule_top(); 
00142   else 
00143     Tcl_GetIntFromObj(interp, objv[1], &molid);
00144   
00145   if (!app->molecule_valid_id(molid)) {
00146     Tcl_AppendResult(interp, "volmap: molecule specified for ouput is invalid. (-mol)", NULL);
00147     return TCL_ERROR;
00148   }
00149 
00150   // Get the minmax box or the pbcbox keyword
00151   if (!strcmp(Tcl_GetStringFromObj(objv[2], NULL), "pbcbox")) {
00152     pbcbox = true;
00153   }
00154   else if (parse_minmax_args(interp, 2, objv, minmax)!=TCL_OK) {
00155     Tcl_AppendResult(interp, "volmap: no atoms selected.", NULL);
00156   }
00157 
00158   int first = 0;
00159   int nframes = app->molecule_numframes(molid);
00160   int last = nframes-1;
00161 
00162   // Parse optional arguments
00163   int arg;
00164   for (arg=3; arg<argc && !bad_usage && !bailout; arg++) {
00165     // Arguments common to all volmap types
00166     if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-res")) {
00167       if (arg+1>=argc) { bad_usage=true; break; }
00168       Tcl_GetDoubleFromObj(interp, objv[arg+1], &resolution);
00169       if (resolution <= 0.f) {
00170         Tcl_AppendResult(interp, "volmap ils: resolution must be positive. (-res)", NULL);
00171         bailout = true; break;
00172       }
00173       arg++;
00174     }
00175     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-probesel")) {
00176       if (arg+1>=argc) { bad_usage=true; break; }
00177       // Get atom selection for probe
00178       probesel = tcl_commands_get_sel(interp, Tcl_GetStringFromObj(objv[arg+1],NULL));
00179       if (!probesel) {
00180         Tcl_AppendResult(interp, "volmap ils -probesel: no atom selection.", NULL);
00181         bailout = true; break;
00182       }
00183       if (!probesel->selected) {
00184         Tcl_AppendResult(interp, "volmap ils -probesel: no atoms selected.", NULL);
00185         bailout = true; break;
00186       }
00187       if (!app->molecule_valid_id(probesel->molid())) {
00188         Tcl_AppendResult(interp, "volmap ils -probesel: ",
00189                          measure_error(MEASURE_ERR_NOMOLECULE), NULL);
00190         bailout = true; break;
00191       }
00192       arg++;
00193     }
00194     // ILS specific arguments
00195     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-first")) {
00196       if (arg+1>=argc) { bad_usage=true; break; }
00197       Tcl_GetIntFromObj(interp, objv[arg+1], &first);
00198       if (first < 0) {
00199         Tcl_AppendResult(interp, "volmap ils: Frame specified with -first must be positive.", NULL);
00200         bailout = true; break;
00201       }
00202       if (first >= nframes) {
00203         Tcl_AppendResult(interp, "volmap ils: Frame specified with -first exceeds number of existing frames.", NULL);
00204         bailout = true; break;
00205       }
00206       arg++;
00207     }
00208     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-last")) {
00209       if (arg+1>=argc) { bad_usage=true; break; }
00210       Tcl_GetIntFromObj(interp, objv[arg+1], &last);
00211       if (last < 0) {
00212         Tcl_AppendResult(interp, "volmap ils: Frame specified with -last must be positive.", NULL);
00213         bailout = true; break;
00214       }
00215       if (last >= nframes) {
00216         Tcl_AppendResult(interp, "volmap ils: Frame specified with -last exceeds number of existing frames.", NULL);
00217         bailout = true; break;
00218       }
00219       arg++;
00220     }
00221     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-cutoff")) {
00222       if (arg+1 >= argc) { bad_usage=true; break; }
00223       Tcl_GetDoubleFromObj(interp, objv[arg+1], &cutoff);
00224       if (cutoff <= 0.) {
00225         Tcl_AppendResult(interp, "volmap ils: cutoff must be positive. (-cutoff)", NULL);
00226         bailout = true; break;
00227       }
00228       arg++;
00229     }
00230     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-dx") ||
00231              !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-o")) {
00232       if (arg+1>=argc) { bad_usage=true; break; }
00233       const char* outputfilename = Tcl_GetString(objv[arg+1]);
00234       if (outputfilename) {
00235         filebase = new char[strlen(outputfilename)+1];
00236         strcpy(filebase, outputfilename);
00237         export_to_file = true;
00238       }
00239       arg++;
00240     }
00241 
00242     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-probecoor")) {
00243       if (arg+1>=argc) { bad_usage=true; break; }
00244       int i;
00245       double tmp;
00246       Tcl_Obj **listObj;
00247       if (Tcl_ListObjGetElements(interp, objv[arg+1], &nprobecoor, &listObj) != TCL_OK) {
00248         Tcl_AppendResult(interp, " volmap ils: bad syntax in probecoor!", NULL);
00249         bailout = true; break;
00250       }
00251       if (!nprobecoor) {
00252         Tcl_AppendResult(interp, " volmap ils: Empty probecoor list!", NULL);
00253         bailout = true; break;
00254       }
00255 
00256       probe_coords = new float[3L*nprobecoor];
00257 
00258       for (i=0; i<nprobecoor; i++) {
00259         Tcl_Obj **coorObj;
00260         int j, ndim = 0;
00261         if (Tcl_ListObjGetElements(interp, listObj[i], &ndim, &coorObj) != TCL_OK) {
00262           Tcl_AppendResult(interp, " volmap ils: bad syntax in probecoor!", NULL);
00263           bailout = true; break;
00264         }
00265 
00266         if (ndim!=3) {
00267           Tcl_AppendResult(interp, " volmap ils: need three values for each probecoor vector", NULL);
00268           bailout = true; break;
00269         }
00270       
00271         for (j=0; j<3; j++) {
00272           if (Tcl_GetDoubleFromObj(interp, coorObj[j], &tmp) != TCL_OK) {
00273             Tcl_AppendResult(interp, " volmap ils: non-numeric in probecoor", NULL);
00274             bailout = true; break;
00275           }
00276           probe_coords[3L*i+j] = (float)tmp;
00277         }
00278       }
00279       arg++;
00280     }
00281     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-probevdw")) {
00282       if (arg+1>=argc) { bad_usage=true; break; }
00283       double tmp;
00284       Tcl_Obj **listObj;
00285       if (Tcl_ListObjGetElements(interp, objv[arg+1], &nprobevdw, &listObj) != TCL_OK) {
00286         Tcl_AppendResult(interp, " volmap ils: bad syntax in probevdw", NULL);
00287         bailout = true; break;
00288       }
00289 
00290       probe_vdweps  = new float[nprobevdw];
00291       probe_vdwrmin = new float[nprobevdw];
00292 
00293       int i;
00294       for (i=0; i<nprobevdw; i++) {
00295         Tcl_Obj **vdwObj;
00296         int ndim = 0;
00297         if (Tcl_ListObjGetElements(interp, listObj[i], &ndim, &vdwObj) != TCL_OK) {
00298           Tcl_AppendResult(interp, " volmap ils: bad syntax in probevdw", NULL);
00299           bailout = true; break;
00300         }
00301 
00302         if (ndim!=2) {
00303           Tcl_AppendResult(interp, " volmap ils: Need two probevdw values (eps, rmin) for each atom", NULL);
00304           bailout = true; break;
00305         }
00306       
00307         if (Tcl_GetDoubleFromObj(interp, vdwObj[0], &tmp) != TCL_OK) {
00308           Tcl_AppendResult(interp, " volmap ils: Non-numeric in probevdw (eps)", NULL);
00309           bailout = true; break;
00310         }
00311         probe_vdweps[i] = (float)tmp;
00312         
00313         if (Tcl_GetDoubleFromObj(interp, vdwObj[1], &tmp) != TCL_OK) {
00314           Tcl_AppendResult(interp, " volmap ils: Non-numeric in probevdw (rmin)", NULL);
00315           bailout = true; break;
00316         }
00317         probe_vdwrmin[i] = (float)tmp;        
00318       }
00319       arg++;
00320     }
00321 
00322     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-probecharge")) {
00323       if (arg+1>=argc) { bad_usage=true; break; }
00324       int i;
00325       double tmp;
00326       Tcl_Obj **listObj;
00327       if (Tcl_ListObjGetElements(interp, objv[arg+1], &nprobecharge, &listObj) != TCL_OK) {
00328         Tcl_AppendResult(interp, " volmap ils: bad syntax in probecharge", NULL);
00329         bailout = true; break;
00330       }
00331 
00332       probe_charge = new float[nprobecharge];
00333 
00334       for (i=0; i<nprobecharge; i++) {
00335         if (Tcl_GetDoubleFromObj(interp, listObj[0], &tmp) != TCL_OK) {
00336           Tcl_AppendResult(interp, " volmap ils: non-numeric in probecharge", NULL);
00337           bailout = true; break;
00338         }
00339         probe_charge[i] = (float)tmp;
00340       }
00341       arg++;
00342     }
00343 
00344     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-orient") ||
00345              !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-conf")) {
00346       if (arg+1>=argc) { bad_usage=true; break; }
00347       Tcl_GetIntFromObj(interp, objv[arg+1], &num_conf);
00348       if (num_conf < 0) {
00349         Tcl_AppendResult(interp, "volmap ils: invalid -orient parameter", NULL);
00350         bailout = true; break;
00351       }
00352       arg++;
00353     }
00354     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-subres")) {
00355       if (arg+1>=argc) { bad_usage=true; break; }
00356       Tcl_GetIntFromObj(interp, objv[arg+1], &subres);
00357       if (subres < 1) {
00358         Tcl_AppendResult(interp, "volmap ils: invalid -subres parameter", NULL);
00359         bailout = true; break;
00360       }
00361       arg++;
00362     }
00363     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-T")) {
00364       if (arg+1>=argc) { bad_usage=true; break; }
00365       Tcl_GetDoubleFromObj(interp, objv[arg+1], &temperature);
00366       arg++;
00367     }    
00368     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-maxenergy")) {
00369       if (arg+1>=argc) { bad_usage=true; break; }
00370       if (Tcl_GetDoubleFromObj(interp, objv[arg+1], &maxenergy) != TCL_OK) {
00371         Tcl_AppendResult(interp, "volmap ils: invalid -maxenergy parameter", NULL);
00372         bailout = true; break;
00373       }
00374       arg++;
00375     }    
00376     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-alignsel")) {
00377       if (arg+1>=argc) { bad_usage=true; break; }
00378       alignsel = tcl_commands_get_sel(interp, Tcl_GetStringFromObj(objv[arg+1],NULL));
00379       if (!alignsel) {
00380         Tcl_AppendResult(interp, "volmap ils: no atom selection for alignment.", NULL);
00381         bailout = true; break;
00382       }
00383       if (!alignsel->selected) {
00384         Tcl_AppendResult(interp, "volmap ils: no atoms selected for alignment.", NULL);
00385         bailout = true; break;
00386       }
00387       arg++;
00388     }    
00389     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-transform")) {
00390       if (arg+1>=argc) { bad_usage=true; break; }
00391       transform = new Matrix4;
00392       tcl_get_matrix("volmap ils: ", interp, objv[arg+1], transform->mat);
00393       arg++;
00394     }
00395 
00396     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-pbc")) {
00397       pbc = true;
00398     }
00399 
00400     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-pbccenter")) {
00401       if (arg+1>=argc) { bad_usage=true; break; }
00402       int i, ndim = 0;
00403       double tmp;
00404       Tcl_Obj **centerObj;
00405       if (Tcl_ListObjGetElements(interp, objv[arg+1], &ndim, &centerObj) != TCL_OK) {
00406         Tcl_AppendResult(interp, " volmap ils: bad syntax in pbccenter", NULL);
00407         bailout = true; break;
00408       }
00409       
00410       if (ndim!=3) {
00411         Tcl_AppendResult(interp, " volmap ils: need three values for vector pbccenter", NULL);
00412         bailout = true; break;
00413       }
00414       
00415       pbccenter = new float[3];
00416       for (i=0; i<3; i++) {
00417         if (Tcl_GetDoubleFromObj(interp, centerObj[i], &tmp) != TCL_OK) {
00418           Tcl_AppendResult(interp, " volmap ils: non-numeric in pbccenter", NULL);
00419           bailout = true; break;
00420         }
00421         pbccenter[i] = (float)tmp;
00422       }
00423       arg++;
00424       pbc = true;
00425     }
00426 
00427     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-maskonly")) {
00428       maskonly = 1;
00429     }
00430 
00431     else {
00432       // unknown arg
00433       Tcl_AppendResult(interp, " volmap ils: unknown argument ",
00434                        Tcl_GetStringFromObj(objv[arg], NULL), NULL);
00435       bailout = true;
00436     }
00437 
00438   }
00439   
00440   if (bad_usage) {
00441     Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<molid> <minmax> [options...]");
00442     bailout = true;
00443   }
00444 
00445   int num_probe_atoms = 0;
00446   if (!bailout) {
00447     if (probesel) {
00448       if (nprobecoor) {
00449         Tcl_AppendResult(interp, "volmap ils: Must specify either -probesel or -probecoor not both.", NULL);
00450         bailout = true;
00451       }
00452       
00453       // The probe was specified in form of an atomselection
00454       Molecule *probemol = app->moleculeList->mol_from_id(probesel->molid());
00455       const float *radius = probemol->extraflt.data("radius");
00456       if (!radius) {
00457         Tcl_AppendResult(interp, "volmap ils: probe selection contains no VDW radii", NULL);
00458         bailout = true;
00459       }
00460       
00461       const float *occupancy = probemol->extraflt.data("occupancy");
00462       if (!occupancy) {
00463         Tcl_AppendResult(interp, "volmap ils: probe selection contains no VDW epsilon values (in occupancy field)", NULL);
00464         bailout = true;
00465       }
00466       
00467       if (!bailout) {
00468         const float *charge = probemol->extraflt.data("charge");
00469         
00470         num_probe_atoms = probesel->selected;
00471         if (!nprobevdw) {
00472           probe_vdwrmin = new float[num_probe_atoms];
00473           probe_vdweps  = new float[num_probe_atoms];
00474         }
00475         probe_charge  = new float[num_probe_atoms];
00476         probe_coords  = new float[3L*num_probe_atoms];
00477         const float *coords = probesel->coordinates(app->moleculeList);
00478         int i, j=0;
00479         for (i=0; i<probesel->num_atoms; i++) {
00480           if (probesel->on[i]) {
00481             vec_copy(&probe_coords[3L*j], &coords[3L*i]);
00482 
00483             if (!nprobevdw) {
00484               probe_vdweps[j]  = -fabsf(occupancy[i]);
00485               probe_vdwrmin[j] = radius[i];
00486             }
00487             if (!nprobecharge) {
00488               if (charge) probe_charge[j] = charge[i];
00489               else        probe_charge[j] = 0.f;
00490             }
00491             j++;
00492           }
00493         }  
00494       }
00495       
00496     } else {
00497       // The probe was specified through a coordinate list
00498       if (nprobecoor==0 && nprobevdw==1) {
00499         // No need to specify coodinates of monoatomic probe
00500         num_probe_atoms = 1;
00501         probe_coords = new float[3];
00502         probe_coords[0] = probe_coords[1] = probe_coords[2] = 0.f;
00503       } else {
00504         num_probe_atoms = nprobecoor;
00505       }
00506 
00507       if (!nprobevdw) {
00508         Tcl_AppendResult(interp, "volmap ils: No probe VDW parameters specified.", NULL);
00509         bailout = true;      
00510       }
00511 
00512       if (nprobecharge && nprobecharge!=num_probe_atoms && !bailout) {
00513         Tcl_AppendResult(interp, "volmap ils: # probe charges doesn't match # probe atoms", NULL);
00514         bailout = true;
00515       }
00516     }
00517 
00518     if (num_probe_atoms==0 && !bailout) {
00519       Tcl_AppendResult(interp, "volmap: No probe coordinates specified.", NULL);
00520       bailout = true;
00521     }
00522 
00523     if (nprobevdw && nprobevdw!=num_probe_atoms && !bailout) {
00524       Tcl_AppendResult(interp, "volmap ils: # probe VDW params doesn't match # probe atoms", NULL);
00525       bailout = true;
00526     }
00527 
00528     if (pbc && !alignsel) {
00529       Tcl_AppendResult(interp, "volmap ils: You cannot use -pbc without also "
00530                        " providing -alignsel.", NULL);
00531       bailout = true;
00532     }
00533 
00534     //if (num_probe_atoms==1 && num_conf>1 && !bailout) {
00535       //Tcl_AppendResult(interp, "volmap: Specifying -orient for monoatomic probes makes no sense.", NULL);
00536       //bailout = true;
00537     //}
00538   }
00539 
00540   if (bailout) {
00541     if (transform) delete transform;
00542     if (pbccenter) delete [] pbccenter;
00543     if (filebase)  delete [] filebase;
00544     if (probe_vdwrmin) delete [] probe_vdwrmin;
00545     if (probe_vdweps)  delete [] probe_vdweps;
00546     if (probe_charge)  delete [] probe_charge;
00547     if (probe_coords)  delete [] probe_coords;
00548     return TCL_ERROR;
00549   }
00550 
00551   // If the probe was provided in form of an atom selection
00552   // determine the symmetry of the probe. We need to know if
00553   // the probe has a tetrahedral point group, the highest
00554   // rotary axis and any C2 axis orthogonal to it.
00555   // If the probe was specified through parameter list instead
00556   // of a selection then the ILS code will try a simple
00557   // symmetry check itself
00558   int tetrahedral_symm = 0;
00559   int order1=0, order2=0;
00560   float symmaxis1[3];
00561   float symmaxis2[3];
00562   if (probesel) {
00563     msgInfo << "Determining probe symmetry:" << sendmsg;
00564 
00565     // Create Symmetry object, verbosity level = 1
00566     Symmetry sym = Symmetry(probesel, app->moleculeList, 1);
00567     
00568     // Set tolerance for atomic overlapping
00569     sym.set_overlaptol(0.05f);
00570     
00571     // Take bonds into account
00572     sym.set_checkbonds(1);
00573 
00574     // Guess the symmetry
00575     int ret_val = sym.guess(0.05f);
00576     if (ret_val < 0) {
00577       Tcl_AppendResult(interp, "measure symmetry: ", measure_error(ret_val), NULL);
00578       return TCL_ERROR;
00579     }
00580     int pgorder;
00581     char pointgroup[6];
00582     sym.get_pointgroup(pointgroup, &pgorder);
00583 
00584     if (pointgroup[0]=='T') tetrahedral_symm = 1;
00585 
00586     if (sym.numaxes()) {
00587       // First symmetry axis
00588       vec_copy(symmaxis1, sym.axis(0));
00589       order1 = sym.get_axisorder(0);
00590 
00591       int i;
00592       for (i=1; i<sym.numaxes(); i++) {
00593         vec_copy(symmaxis2, sym.axis(i));
00594         if (fabs(dot_prod(symmaxis1, symmaxis2)) < DEGTORAD(1.f)) {
00595           // Orthogonal second axis found
00596           order2 = sym.get_axisorder(i);
00597           break;
00598         }
00599       }
00600     }
00601   }
00602 
00603   // 6. Create the volmap
00604   VolMapCreateILS vol(app, molid, first, last, (float)temperature,
00605                       (float)resolution, subres, (float)cutoff,
00606                       maskonly);
00607 
00608   vol.set_probe(num_probe_atoms, num_conf, probe_coords,
00609                 probe_vdwrmin, probe_vdweps, probe_charge);
00610   vol.set_maxenergy(float(maxenergy));
00611 
00612   if (pbc)       vol.set_pbc(pbccenter, pbcbox);
00613   if (transform) vol.set_transform(transform);
00614   if (alignsel)  vol.set_alignsel(alignsel);
00615   if (!pbcbox) {
00616     vol.set_minmax(float(minmax[0]), float(minmax[1]), float(minmax[2]),
00617                    float(minmax[3]), float(minmax[4]), float(minmax[5]));
00618   }
00619 
00620   if (tetrahedral_symm || order1 || order2) {
00621     // Provide info about probe symmetry
00622     vol.set_probe_symmetry(order1, symmaxis1, order2, symmaxis2, tetrahedral_symm);
00623   }
00624 
00625   // Create map...
00626   int ret_val = vol.compute();
00627 
00628   if (ret_val < 0) {
00629     Tcl_AppendResult(interp, "\nvolmap: ERROR ", measure_error(ret_val), NULL);
00630 
00631     if (transform) delete transform;
00632     if (pbccenter) delete [] pbccenter;
00633     if (filebase)  delete [] filebase;
00634     if (probe_vdwrmin) delete [] probe_vdwrmin;
00635     if (probe_vdweps)  delete [] probe_vdweps;
00636     if (probe_charge)  delete [] probe_charge;
00637     if (probe_coords)  delete [] probe_coords;
00638     return TCL_ERROR;
00639   }
00640 
00641   int numconf, numorient, numrot;
00642   vol.get_statistics(numconf, numorient, numrot);
00643 
00644   // If the probe was specified in form of a selection and a separate
00645   // molecule then we append a frame for each conformer and set the
00646   // probe coordinates accordingly.
00647   if (probesel && probesel->molid()!=molid) {
00648     float *conformers = NULL;
00649     int numconf = vol.get_conformers(conformers);
00650     Molecule *pmol = app->moleculeList->mol_from_id(probesel->molid());
00651     int i, j;
00652     for (i=0; i<numconf; i++) {
00653       if (i>0) {
00654         pmol->duplicate_frame(pmol->current());
00655       }
00656       float *coor = pmol->get_frame(i)->pos;
00657       int k=0;
00658       for (j=0; j<probesel->num_atoms; j++) { 
00659         if (!probesel->on[j]) continue; //atom is not selected
00660 
00661         vec_copy(&coor[3L*j], &conformers[i*3L*num_probe_atoms+3L*k]);
00662         k++;
00663       }
00664     }
00665   }
00666 
00667   // Export volmap to a file or just add it to the molecule:
00668   if (export_to_file) {
00669     // Add .dx suffix to filebase if it is missing
00670     filename = new char[strlen(filebase)+16];
00671     strcpy(filename, filebase);
00672     char *suffix = strrchr(filename, '.'); // beginning of .dx
00673     if (strcmp(suffix, ".dx")) strcat(filename, ".dx");
00674 
00675     // Write tha map into a dx file
00676     if (!vol.write_map(filename)) {
00677       Tcl_AppendResult(interp, "\nvolmap: ERROR Could not write ils map to file", NULL);
00678     }
00679 
00680     delete[] filename;
00681 
00682   } else {
00683     if (!vol.add_map_to_molecule()) {
00684       Tcl_AppendResult(interp, "\nvolmap: ERROR Could not add ils map to molecule", NULL);
00685     }
00686   }
00687     
00688   Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL);
00689   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numconf", -1));
00690   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numconf));
00691   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numorient", -1));
00692   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numorient));
00693   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numrot", -1));
00694   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numrot));
00695   Tcl_SetObjResult(interp, tcl_result);
00696 
00697   if (transform) delete transform;
00698   if (pbccenter) delete [] pbccenter;
00699   if (filebase)  delete [] filebase;
00700   if (probe_vdwrmin) delete [] probe_vdwrmin;
00701   if (probe_vdweps)  delete [] probe_vdweps;
00702   if (probe_charge)  delete [] probe_charge;
00703   if (probe_coords)  delete [] probe_coords;
00704 
00705   return TCL_OK;
00706 }
00707 
00708 
00709 static int vmd_volmap_new_fromtype(VMDApp *app, int argc, Tcl_Obj * const objv[], Tcl_Interp *interp) {
00710 
00711   // 1. Figure out which map type we are dealing with:
00712   enum {UNDEF_MAP, DENS_MAP, INTERP_MAP, DIST_MAP, OCCUP_MAP, MASK_MAP,
00713         CPOTENTIAL_MAP, CPOTENTIALMSM_MAP } maptype=UNDEF_MAP;
00714 
00715   int ret_val = 0;
00716 
00717   char *maptype_string=Tcl_GetString(objv[0]); 
00718 
00719   if      (!strcmp(maptype_string, "density"))    maptype=DENS_MAP;
00720   else if (!strcmp(maptype_string, "interp"))     maptype=INTERP_MAP;
00721   else if (!strcmp(maptype_string, "distance"))   maptype=DIST_MAP;
00722   else if (!strcmp(maptype_string, "occupancy"))  maptype=OCCUP_MAP; 
00723   else if (!strcmp(maptype_string, "mask"))       maptype=MASK_MAP; 
00724   else if (!strcmp(maptype_string, "coulomb"))    maptype=CPOTENTIAL_MAP;
00725   else if (!strcmp(maptype_string, "coulombpotential")) maptype=CPOTENTIAL_MAP;
00726   else if (!strcmp(maptype_string, "coulombmsm"))  maptype=CPOTENTIALMSM_MAP;
00727  
00728   // 2. Get atom selection
00729   if (argc < 2) { 
00730     Tcl_AppendResult(interp, "volmap: no atom selection.", NULL);
00731     return TCL_ERROR;
00732   }
00733 
00734   AtomSel *sel = NULL;
00735   sel = tcl_commands_get_sel(interp, Tcl_GetStringFromObj(objv[1],NULL));
00736   if (!sel) {
00737     Tcl_AppendResult(interp, "volmap: no atom selection.", NULL);
00738     return TCL_ERROR;
00739   }
00740   if (!sel->selected) {
00741     Tcl_AppendResult(interp, "volmap: no atoms selected.", NULL);
00742     return TCL_ERROR;
00743   }
00744   if (!app->molecule_valid_id(sel->molid())) {
00745     Tcl_AppendResult(interp, "volmap: ",
00746                      measure_error(MEASURE_ERR_NOMOLECULE), NULL);
00747     return TCL_ERROR;
00748   }
00749 
00750 
00751   // 3. Define and initialize the optional arguments
00752   bool accept_weight = false; // allow a user-specified weight for each atom
00753   bool accept_cutoff = false; // parse a user-specified cutoff distance
00754   bool accept_radius = false; // allow radius multiplicator for density
00755   bool accept_usepoints = false; // allows use of point particles
00756 
00757   bool use_point_particles = false;  // for MASK map
00758   bool export_to_file = false;
00759   bool use_all_frames = false;
00760   bool bad_usage = false;
00761 
00762   int export_molecule = -1;
00763   double cutoff        = 5.;
00764   double radius_factor = 1.;
00765   double resolution    = 1.;
00766   double minmax[6];
00767   
00768   char *filebase = NULL;
00769   char *filename = NULL;
00770 
00771   
00772   // File export options
00773   int checkpoint_freq = 500;
00774       
00775 
00776   // Specify required/accepted options for each maptype as well as default values.
00777   switch(maptype) {
00778     case DENS_MAP:
00779       accept_weight = true;
00780       accept_radius = true;
00781       break;
00782     case INTERP_MAP:
00783       accept_weight = true; 
00784       break;
00785     case DIST_MAP:
00786       accept_cutoff = true;
00787       cutoff = 3.;
00788       break;
00789     case OCCUP_MAP:
00790       accept_usepoints = true;
00791       break;
00792     case MASK_MAP:
00793       accept_cutoff = true;
00794       cutoff = 4.;
00795       break;
00796     case CPOTENTIAL_MAP:
00797     case CPOTENTIALMSM_MAP:
00798       break; 
00799     case UNDEF_MAP:
00800       bad_usage = true;
00801       break;   
00802   }
00803  
00804 
00805   // 4. Parse the command-line
00806   int arg_weight=0, arg_combine=0, arg_minmax=0;
00807 
00808   // Parse the arguments
00809   for (int arg=2; arg<argc && !bad_usage; arg++) {
00810     if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-res")) {
00811       if (arg+1>=argc) bad_usage=true;
00812       Tcl_GetDoubleFromObj(interp, objv[arg+1], &resolution);
00813       if (resolution <= 0.f) {
00814         Tcl_AppendResult(interp, "volmap: resolution must be positive. (-res)", NULL);
00815         return TCL_ERROR;
00816       }
00817       arg++;
00818     }
00819     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-mol")) { // add volmap to mol
00820       if (arg+1 >= argc) bad_usage=true;
00821       if (!strcmp(Tcl_GetStringFromObj(objv[arg+1], NULL), "top"))
00822         export_molecule = app->molecule_top(); 
00823       else 
00824         Tcl_GetIntFromObj(interp, objv[arg+1], &export_molecule);
00825       
00826       if (!app->molecule_valid_id(export_molecule)) {
00827         Tcl_AppendResult(interp, "volmap: molecule specified for ouput is invalid. (-mol)", NULL);
00828         return TCL_ERROR;
00829       }
00830       arg++;
00831     }
00832     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-minmax")) {
00833       arg_minmax=arg+1;
00834       arg++;
00835       if (arg_minmax>=argc) bad_usage=true;
00836       if (parse_minmax_args(interp, arg_minmax, objv, minmax)!=TCL_OK) {
00837         return TCL_ERROR;
00838       }
00839     }
00840     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-checkpoint")) {
00841       if (arg+1 >= argc) bad_usage=true;
00842       Tcl_GetIntFromObj(interp, objv[arg+1], &checkpoint_freq);
00843       if (checkpoint_freq < 0) {
00844         Tcl_AppendResult(interp, "volmap: invalid -checkpoint parameter", NULL);
00845         return TCL_ERROR;
00846       }
00847       arg++;
00848     }
00849     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-allframes")) {
00850       use_all_frames=true;
00851     }
00852     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-dx") ||
00853              !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-o")) {
00854       if (arg+1>=argc) {bad_usage=true; break;}
00855       const char* outputfilename = Tcl_GetString(objv[arg+1]);
00856       if (outputfilename) {
00857         filebase = new char[strlen(outputfilename)+1];
00858         strcpy(filebase, outputfilename);
00859         export_to_file = true;
00860       }
00861       arg++;
00862     }
00863     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-combine")) {
00864       arg_combine=arg+1;
00865       arg++;
00866       if (arg_combine>=argc) bad_usage=true;
00867     }
00868     else if (accept_usepoints && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-points")) {
00869       use_point_particles=true;
00870     }
00871     else if (accept_cutoff && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-cutoff")) {
00872       if (arg+1 >= argc) bad_usage=true;
00873       Tcl_GetDoubleFromObj(interp, objv[arg+1], &cutoff);
00874       if (cutoff <= 0.) {
00875         Tcl_AppendResult(interp, "volmap: cutoff must be positive. (-cutoff)", NULL);
00876         return TCL_ERROR;
00877       }
00878       arg++;
00879     }
00880     else if (accept_radius && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-radscale")) {
00881       if (arg+1 >= argc) bad_usage=true;
00882       Tcl_GetDoubleFromObj(interp, objv[arg+1], &radius_factor);
00883       if (radius_factor < 0.f) {
00884         Tcl_AppendResult(interp, "volmap: radscale must be positive. (-radscale)", NULL);
00885         return TCL_ERROR;
00886       }
00887       arg++;
00888     }
00889     else if (accept_weight && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-weight")) {
00890       if (arg+1>=argc) bad_usage=true;
00891       arg_weight = arg+1;      
00892       arg++;
00893     }
00894     
00895     else //unknown arg
00896       bad_usage=true; 
00897   }
00898   
00899     
00900   if (bad_usage) {
00901     if (maptype == UNDEF_MAP)
00902       Tcl_AppendResult(interp, "volmap: unknown map type.", NULL);
00903     else
00904       Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<selection> [options...]");
00905 
00906     return TCL_ERROR;
00907   }
00908   
00909   
00910   // 5. Assign some other optional parameters
00911      
00912   // parse map combination type
00913   VolMapCreate::CombineType combine_type=VolMapCreate::COMBINE_AVG;
00914   if (arg_combine) {
00915     char *combine_str=Tcl_GetString(objv[arg_combine]);
00916     if (!strcmp(combine_str, "avg") || !strcmp(combine_str, "average")) 
00917       combine_type=VolMapCreate::COMBINE_AVG;
00918     else if (!strcmp(combine_str, "max") || !strcmp(combine_str, "maximum")) 
00919       combine_type=VolMapCreate::COMBINE_MAX;
00920     else if (!strcmp(combine_str, "min") || !strcmp(combine_str, "minimum")) 
00921       combine_type=VolMapCreate::COMBINE_MIN;
00922     else if (!strcmp(combine_str, "stdev")) 
00923       combine_type=VolMapCreate::COMBINE_STDEV;
00924     else if (!strcmp(combine_str, "pmf")) 
00925       combine_type=VolMapCreate::COMBINE_PMF;
00926     else {
00927       Tcl_AppendResult(interp, "volmap: -combine argument must be: avg, min, \
00928                                 max, stdev, pmf", NULL);
00929       return TCL_ERROR;
00930     }
00931   }
00932  
00933   // parse weights
00934   float *weights = NULL;
00935   char *weight_string = NULL;
00936   int weight_mutable = 1;
00937   if (accept_weight) {
00938     weights = new float[sel->num_atoms];
00939     if (arg_weight) {
00940       weight_string = Tcl_GetStringFromObj(objv[arg_weight], NULL);
00941       if (!weight_string || !strcmp(weight_string, "none")) {
00942         ret_val = atomsel_default_weights(sel, weights);
00943         weight_string = NULL;
00944       } else {
00945         // Check if the argument is a VMD attribute
00946         int fctn = get_attribute_index(app, weight_string);
00947         if (fctn >= 0) {
00948           ret_val = get_weights_from_attribute(app, sel, weight_string,
00949                                                weights);
00950           if (ret_val == MEASURE_ERR_BADWEIGHTPARM) {
00951             Tcl_AppendResult(interp,
00952                              "weight attribute must have floating point values",
00953                              NULL);
00954           }
00955         } else {
00956           ret_val = get_weights_from_tcl_list(interp, app, sel,
00957                                               objv[arg_weight], weights);
00958           weight_string = NULL;
00959           weight_mutable = 0; // The Tcl list will not change
00960         }
00961       }
00962     } else {
00963       ret_val = atomsel_default_weights(sel, weights);
00964     }
00965 
00966     if (ret_val < 0) {
00967       Tcl_AppendResult(interp, "volmap: ", measure_error(ret_val), NULL);
00968       delete [] weights;
00969       return TCL_ERROR;
00970     }
00971   }
00972   
00973 
00974 
00975   // 6. Create the volmap
00976   VolMapCreate *volcreate = NULL;   
00977 
00978   // init the map creator objects and set default filenames
00979   switch(maptype) {
00980     case DENS_MAP: 
00981       volcreate = new VolMapCreateDensity(app, sel, (float)resolution,
00982                                           weights, weight_string,
00983                                           weight_mutable, (float)radius_factor);
00984       if (!filebase) {
00985         filebase = new char[strlen("density_out.dx")+1];
00986         strcpy(filebase, "density_out.dx");
00987       }
00988       break;
00989 
00990     case INTERP_MAP: 
00991       volcreate = new VolMapCreateInterp(app, sel, (float)resolution,
00992                                          weights, weight_string,
00993                                          weight_mutable);
00994       if (!filebase) {
00995         filebase = new char[strlen("interp_out.dx")+1];
00996         strcpy(filebase, "interp_out.dx");
00997       }
00998       break;
00999 
01000     case DIST_MAP:
01001       volcreate = new VolMapCreateDistance(app, sel, (float)resolution, (float)cutoff);
01002       if (!filebase) {
01003         filebase = new char[strlen("distance_out.dx")+1];
01004         strcpy(filebase, "distance_out.dx");
01005       }
01006       break;
01007 
01008     case OCCUP_MAP:
01009       volcreate = new VolMapCreateOccupancy(app, sel, (float)resolution, use_point_particles);
01010       if (!filebase) {
01011         filebase = new char[strlen("occupancy_out.dx")+1];
01012         strcpy(filebase, "occupancy_out.dx");
01013       }
01014       break;
01015 
01016     case MASK_MAP:
01017       volcreate = new VolMapCreateMask(app, sel, (float)resolution, (float)cutoff);
01018       if (!filebase) {
01019         filebase = new char[strlen("mask_out.dx")+1];
01020         strcpy(filebase, "mask_out.dx");
01021       }
01022       break;
01023 
01024     case CPOTENTIAL_MAP:
01025       volcreate = new VolMapCreateCoulombPotential(app, sel, (float)resolution);
01026       if (!filebase) {
01027         filebase = new char[strlen("coulomb_out.dx")+1];
01028         strcpy(filebase, "coulomb_out.dx");
01029       }
01030       break;
01031 
01032     case CPOTENTIALMSM_MAP:
01033       volcreate = new VolMapCreateCoulombPotentialMSM(app, sel, (float)resolution);
01034       if (!filebase) {
01035         filebase = new char[strlen("coulombmsm_out.dx")+1];
01036         strcpy(filebase, "coulombmsm_out.dx");
01037       }
01038       break;
01039 
01040 
01041     default:  // silence compiler warnings
01042       break;  
01043   }
01044 
01045   // generate and write out volmap
01046   if (volcreate) {
01047     // Pass parameters common to all volmap types
01048     if (arg_minmax)
01049       volcreate->set_minmax(float(minmax[0]), float(minmax[1]),
01050                             float(minmax[2]), float(minmax[3]), 
01051                             float(minmax[4]), float(minmax[5]));
01052     
01053     // Setup checkpointing
01054     if (checkpoint_freq) {
01055       char *checkpointname = new char[32+strlen(filebase)+1];
01056 #if defined(_MSC_VER)
01057       char slash = '\\';
01058 #else
01059       char slash = '/';
01060 #endif
01061       char *tailname = strrchr(filebase, slash);
01062       if (!tailname) tailname = filebase;
01063       else tailname = tailname+1;
01064       char *dirname = new char[strlen(filebase)+1];
01065       strcpy(dirname, filebase);
01066       char *sep = strrchr(dirname, slash);
01067 
01068       if (sep) {
01069         *sep = '\0';
01070         sprintf(checkpointname, "%s%ccheckpoint:%s", dirname, slash, tailname);
01071       }
01072       else {
01073         *dirname = '\0';
01074         sprintf(checkpointname, "checkpoint:%s", tailname);
01075       }
01076       delete[] dirname;
01077 
01078       Tcl_AppendResult(interp, "CHECKPOINTNAME = ", checkpointname, NULL);
01079       volcreate->set_checkpoint(checkpoint_freq, checkpointname);
01080       delete[] checkpointname;
01081     }
01082     
01083     // Create map...
01084     ret_val = volcreate->compute_all(use_all_frames, combine_type, NULL);
01085     if (ret_val < 0) {
01086       delete volcreate;
01087       if (weights)  delete [] weights;
01088       if (filebase) delete [] filebase;
01089 
01090       Tcl_AppendResult(interp, "\nvolmap: ERROR ", measure_error(ret_val), NULL);
01091       return TCL_ERROR;
01092     }
01093     
01094     // Export volmap to a DX file:
01095     if (export_to_file || export_molecule < 0) {
01096       // add .dx suffix to filebase if it is missing
01097       filename = new char[strlen(filebase)+16];
01098       strcpy(filename, filebase);
01099       char *suffix = strrchr(filename, '.');
01100       if ((suffix != NULL) && !strcmp(suffix,".dx")) 
01101         *suffix = '\0';
01102       strcat(filename, ".dx");
01103       volcreate->write_map(filename);
01104       delete[] filename;
01105     }
01106     
01107     // Export volmap to a molecule:
01108     if (export_molecule >= 0) {
01109       VolumetricData *volmap = volcreate->volmap;
01110       float origin[3], xaxis[3], yaxis[3], zaxis[3];
01111       int i;
01112       for (i=0; i<3; i++) {
01113         origin[i] = (float) volmap->origin[i];
01114         xaxis[i] = (float) volmap->xaxis[i];
01115         yaxis[i] = (float) volmap->yaxis[i];
01116         zaxis[i] = (float) volmap->zaxis[i];
01117       }
01118       int err = app->molecule_add_volumetric(export_molecule, 
01119          (volmap->name) ? volmap->name : "(no name)",
01120          origin, xaxis, yaxis, zaxis,
01121          volmap->xsize, volmap->ysize, volmap->zsize, volmap->data);
01122       if (err != 1) {
01123         Tcl_AppendResult(interp, "ERROR: export of volmap into molecule was unsuccessful!", NULL);
01124       }
01125       else volmap->data=NULL; // avoid data being deleted by volmap's destructor (it is now owned by the molecule)
01126     }
01127 
01128     delete volcreate;
01129   }
01130   
01131   if (weights) delete [] weights;
01132   if (filebase) delete [] filebase;
01133 
01134   return TCL_OK;
01135 }
01136 
01137 
01138 // vec_sub() from utilities.h works with float* only
01139 // here I needed doubles.
01140 #define DOUBLE_VSUB(D, X, Y) \
01141   D[0] = float(X[0]-Y[0]); \
01142   D[1] = float(X[1]-Y[1]); \
01143   D[2] = float(X[2]-Y[2]); 
01144 
01145 // Compare two volumetric maps:
01146 // volmap compare <molid1> <volid1> <molid2> <volid2>
01147 // The two maps must be specified by their molID and volID.
01148 // Prints the min/max vales, the largest difference, the RMSD,
01149 // the RMSD computed inly for the elements that differ and the
01150 // RMSD weighted by the magnitude of the elements compared so
01151 // that smaller values receive a larger weight.
01152 // (For ILS we are interested mainly in the smaller energies)
01153 static int vmd_volmap_compare(VMDApp *app, int argc, Tcl_Obj * const objv[], Tcl_Interp *interp)
01154 {
01155   int molid1 = -1;
01156   int molid2 = -1;
01157   int mapid1 = -1;
01158   int mapid2 = -1;
01159 
01160   // Get the molecule IDs
01161   if (!strcmp(Tcl_GetStringFromObj(objv[1], NULL), "top"))
01162     molid1 = app->molecule_top(); 
01163   else 
01164     Tcl_GetIntFromObj(interp, objv[1], &molid1);
01165   
01166   if (!strcmp(Tcl_GetStringFromObj(objv[3], NULL), "top"))
01167     molid2 = app->molecule_top(); 
01168   else 
01169     Tcl_GetIntFromObj(interp, objv[3], &molid2);
01170 
01171   if (!app->molecule_valid_id(molid1) || !app->molecule_valid_id(molid2)) {
01172     Tcl_AppendResult(interp, "volmap compare: molecule specified for ouput is invalid. (-mol)", NULL);
01173     return TCL_ERROR;
01174   }
01175 
01176   Molecule *mol1 = app->moleculeList->mol_from_id(molid1);
01177   Molecule *mol2 = app->moleculeList->mol_from_id(molid2);
01178 
01179   // Get volmap IDs
01180   Tcl_GetIntFromObj(interp, objv[2], &mapid1);
01181   Tcl_GetIntFromObj(interp, objv[4], &mapid2);
01182 
01183   if (mapid1<0 || mapid2<0) {
01184     Tcl_AppendResult(interp, "volmap compare: Volmap ID must be positive.", NULL);
01185     return TCL_ERROR;
01186   }
01187   if (mapid1 >= mol1->num_volume_data() ||
01188       mapid2 >= mol2->num_volume_data()) {
01189     Tcl_AppendResult(interp, "volmap compare: Volmap ID does not exist.", NULL);
01190     return TCL_ERROR;
01191   }
01192 
01193   // Parse optional arguments
01194   bool bad_usage = false;
01195   double histinterval = 2.5;
01196   int numbins = 9;
01197   int arg;
01198   for (arg=5; arg<argc && !bad_usage; arg++) {
01199     if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-interval")) {
01200       if (arg+1>=argc) { bad_usage=true; break; }
01201       Tcl_GetDoubleFromObj(interp, objv[arg+1], &histinterval);
01202       if (histinterval <= 0.f) {
01203         Tcl_AppendResult(interp, "volmap compare: histogram interval must be positive. (-interval)", NULL);
01204         return TCL_ERROR;
01205       }
01206       arg++;
01207     }
01208     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-numbins")) {
01209       if (arg+1>=argc) { bad_usage=true; break; }
01210       Tcl_GetIntFromObj(interp, objv[arg+1], &numbins);
01211       if (numbins <= 0) {
01212         Tcl_AppendResult(interp, "volmap compare: histogram bin size must be positive. (-interval)", NULL);
01213         return TCL_ERROR;
01214       }
01215       arg++;
01216     }
01217     else {
01218       // unknown arg
01219       Tcl_AppendResult(interp, " volmap compare: unknown argument ",
01220                        Tcl_GetStringFromObj(objv[arg], NULL), NULL);
01221       return TCL_ERROR;
01222     }
01223 
01224   }
01225   if (bad_usage) {
01226     Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<molid> <minmax> [options...]");
01227     return TCL_ERROR;
01228   }
01229   
01230   const VolumetricData *vol1 = mol1->get_volume_data(mapid1);
01231   const VolumetricData *vol2 = mol2->get_volume_data(mapid2);
01232 
01233   if (vol1->xsize != vol2->xsize ||
01234       vol1->ysize != vol2->ysize ||
01235       vol1->zsize != vol2->zsize) {
01236     Tcl_AppendResult(interp, "volmap compare: maps have different dimensions.", NULL);
01237     return TCL_ERROR;
01238   }
01239 
01240   float vdiff[3];
01241   DOUBLE_VSUB(vdiff, vol1->origin, vol2->origin);
01242   if (norm(vdiff)>1e-6) {
01243     Tcl_AppendResult(interp, "volmap compare: maps have different origin.", NULL);
01244   }
01245 
01246   DOUBLE_VSUB(vdiff, vol1->xaxis, vol2->xaxis);
01247   if (norm(vdiff)>1e-6) {
01248     Tcl_AppendResult(interp, "volmap compare: maps have different x-axis.", NULL);
01249   }
01250   DOUBLE_VSUB(vdiff, vol1->yaxis, vol2->yaxis);
01251   if (norm(vdiff)>1e-6) {
01252     Tcl_AppendResult(interp, "volmap compare: maps have different y-axis.", NULL);
01253   }
01254   DOUBLE_VSUB(vdiff, vol1->zaxis, vol2->zaxis);
01255   if (norm(vdiff)>1e-6) {
01256     Tcl_AppendResult(interp, "volmap compare: maps have different z-axis.", NULL);
01257   }
01258 
01259   int i;
01260   int numdiff = 0;
01261   float sqsum = 0.f;
01262   float sqsumd = 0.f;
01263   float min1 = 0.f, min2 = 0.f;
01264   float max1 = 0.f, max2 = 0.f;
01265   float maxdiff = 0.f;
01266   int indexmaxdiff = 0;
01267 
01268   for (i=0; i<vol1->gridsize(); i++) {
01269     float v1 = vol1->data[i];
01270     float v2 = vol2->data[i];
01271     float diff = v1-v2;
01272     sqsum += diff*diff;
01273     if (v1<min1) min1 = v1;
01274     if (v2<min2) min2 = v2;
01275     if (v1>max1) max1 = v1;
01276     if (v2>max2) max2 = v2;
01277     if (fabsf(diff)>maxdiff) {
01278       maxdiff = fabsf(diff);
01279       indexmaxdiff = i;
01280     }
01281     if (diff) {
01282       //printf("%g - %g = %g\n", v1, v2, diff);
01283       sqsumd += diff*diff;
01284       numdiff++;
01285     }
01286   }
01287   float rmsd = 0.f;
01288   float diffrmsd = 0.f;
01289   if (sqsum)  rmsd     = sqrtf(sqsum/vol1->gridsize());
01290   if (sqsumd) diffrmsd = sqrtf(sqsumd/numdiff);
01291 
01292   char tmpstr[2048];
01293   msgInfo << "volmap compare" << sendmsg;
01294   msgInfo << "--------------" << sendmsg;
01295   msgInfo << "Comparing mol "<<molid1<<" -> map "<<mapid1<<"/"<<mol1->num_volume_data()<<sendmsg;
01296   msgInfo << "       to mol "<<molid2<<" -> map "<<mapid2<<"/"<<mol2->num_volume_data()<<sendmsg;
01297   msgInfo << "Statistics:" << sendmsg;
01298   sprintf(tmpstr, "            %12s  |  %12s", "MAP 1", "MAP 2");
01299   msgInfo << tmpstr << sendmsg;
01300   sprintf(tmpstr, "min value = %12g  |  %12g", min1, min2);
01301   msgInfo << tmpstr << sendmsg;
01302   sprintf(tmpstr, "max value = %12g  |  %12g", max1, max2);
01303   msgInfo << tmpstr << sendmsg;
01304   msgInfo << sendmsg;
01305   sprintf(tmpstr, "# differing elements = %d/%ld", numdiff, vol1->gridsize());
01306   msgInfo << tmpstr << sendmsg;
01307   msgInfo << "max difference:" << sendmsg;
01308   sprintf(tmpstr, "   map1[%d] = %g   map2[%d] = %g   diff = %g",
01309       indexmaxdiff, vol1->data[indexmaxdiff],
01310       indexmaxdiff, vol2->data[indexmaxdiff], maxdiff);
01311   msgInfo << tmpstr << sendmsg;
01312 
01313   // Statistics for the differing elements only:
01314   msgInfo << sendmsg;
01315   sprintf(tmpstr, "         RMSD = %12.6f", rmsd);
01316   msgInfo << tmpstr << sendmsg;
01317   sprintf(tmpstr, "     diffRMSD = %12.6f  (for the set of differing elements)", diffrmsd);
01318   msgInfo << tmpstr << sendmsg;
01319 
01320   // Get weighted RMSD where the differences of smaller values
01321   // are weighted more because the low enegy values are what is 
01322   // of interest in ILS free energy maps.
01323   float wsum = 0.f;
01324   float range = max2-min2;
01325   float wdiffrmsd = 0.f;
01326   if (range) {
01327     sqsum = 0.f;
01328     for (i=0; i<vol1->gridsize(); i++) {
01329       float diff = vol1->data[i]-vol2->data[i];
01330       if (diff) {
01331         float weight = 1.f-(vol2->data[i]-min2)/range;
01332         wsum += weight;
01333         sqsum += diff*diff*weight;
01334       }
01335     }
01336     if (sqsum) wdiffrmsd = sqrtf(sqsum/wsum);
01337   }
01338  
01339 
01340   sprintf(tmpstr, "weighted RMSD = %12.6f  (for the set of differing elements)", wdiffrmsd);
01341   msgInfo << tmpstr << sendmsg;
01342   msgInfo <<      "     weight factor w = 1-(E_i-E_min)/(E_max-E_min)" << sendmsg;
01343   msgInfo << sendmsg;
01344 
01345   // Compare error of map 1 relative to map 2, create histogram of error:
01346   //   | E_approx - E_exact | / ( E_exact - E_exact_min + 1 ),
01347   // where map 1 is considered the approximation and map 2 is considered exact.
01348   //
01349   // Since energy is arbitrary, we shift from the minimum value 
01350   // (usually around -11 to -6) so that the dominator is always
01351   // greater than or equal to 1.  This weights the lower values
01352   // more heavily than the upper values, which is intentional.
01353   //
01354   // The histogram is summed for the intervals
01355   // (-\inf,10) [10,20) [20,30) [30,40) [40,+\inf)
01356 
01357 
01358   // total accumulated error for each bin
01359   float *histo = new float[numbins*sizeof(float)];
01360   // count number of samples per bin
01361   int *num = new int[numbins*sizeof(float)];
01362   // max error for each bin
01363   float *maxEntry = new float[numbins*sizeof(float)];
01364   float *binrmsd = new float[numbins*sizeof(float)];
01365   memset(histo,    0, numbins*sizeof(float));
01366   memset(num,      0, numbins*sizeof(int));
01367   memset(maxEntry, 0, numbins*sizeof(float));
01368   memset(binrmsd,  0, numbins*sizeof(float));
01369 
01370   for (i = 0;  i < vol1->gridsize();  i++) {
01371     float e1 = vol1->data[i];
01372     float e2 = vol2->data[i];
01373     float err = fabsf(e1 - e2) / (e2 - min2 + 1);
01374     int index = (int) floorf((e2 - min2) / float(histinterval));
01375     if      (index < 0)        index = 0;
01376     else if (index >= numbins) index = numbins - 1;
01377 
01378     // check to see if we need to update the max for this bin
01379     if (err > maxEntry[index]) { 
01380        maxEntry[index] = err; 
01381     }
01382     histo[index] += err;
01383     num[index]++;
01384     binrmsd[index] += (e2-e1)*(e2-e1);
01385   }
01386   for (i=0; i<numbins; i++) {
01387     if (binrmsd[i]) binrmsd[i] = sqrtf(binrmsd[i]/num[i]);
01388   }
01389 
01390   // lower boundary of the first bin
01391   float firstbin = floorf(min2/float(histinterval))*float(histinterval);
01392   Tcl_Obj *caption = Tcl_NewListObj(0, NULL);
01393   Tcl_Obj *numEntries = Tcl_NewListObj(0, NULL);
01394   Tcl_Obj *objHisto   = Tcl_NewListObj(0, NULL);
01395   Tcl_Obj *objAverage = Tcl_NewListObj(0, NULL);
01396   Tcl_Obj *objMax     = Tcl_NewListObj(0, NULL);
01397   Tcl_Obj *objBinRMSD = Tcl_NewListObj(0, NULL);
01398   char label[64];
01399   msgInfo << "Histogram of error in map 1 relative to map 2 " << sendmsg;
01400   msgInfo << sendmsg;
01401   msgInfo << "     interval   # samples    total error      avg error"
01402           << "      max error           rmsd" << sendmsg;
01403   msgInfo << "---------------------------------------------------------"
01404           << "----------------------------" << sendmsg;
01405 
01406   sprintf(label, "[%g,%g)", (double) firstbin, (double) (firstbin+histinterval));
01407   sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[0],
01408           (double) histo[0], (double) (!num[0]?0:histo[0]/num[0]),
01409           (double) maxEntry[0], (double) binrmsd[0]);
01410   msgInfo << tmpstr << sendmsg;
01411   Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01412   Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[0]));
01413   Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[0]));
01414   Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[0]?0:histo[0]/num[0]));
01415   Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[0]));
01416   Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[0]));
01417   for (i = 1;  i < numbins-1;  i++) {
01418     sprintf(label, "[%g,%g)", (double)(firstbin+i*histinterval), (double)(firstbin+(i+1)*histinterval));
01419     sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[i],
01420             (double) histo[i], (double) (!num[i]?0:histo[i]/num[i]),
01421             (double) maxEntry[i], (double) binrmsd[i]);
01422     Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01423     Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[i]));
01424     Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[i]));
01425     Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[i]?0:histo[i]/num[i]));
01426     Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[i]));
01427     Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[i]));
01428     msgInfo << tmpstr << sendmsg;
01429   }
01430   sprintf(label, "[%g,+infty)", (double)(firstbin+i*histinterval));
01431   sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[i],
01432           (double) histo[i], (double) (!num[i]?0:histo[i]/num[i]),
01433           (double) maxEntry[i], (double) binrmsd[i]);
01434   Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01435   Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[i]));
01436   Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[i]));
01437   Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[i]?0:histo[i]/num[i]));
01438   Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[i]));
01439   Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[i]));
01440   msgInfo << tmpstr << sendmsg;
01441   msgInfo << sendmsg;
01442 
01443   Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL);
01444   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("rmsd", -1));
01445   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(rmsd));
01446   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("diffrmsd", -1));
01447   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(diffrmsd));
01448   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("weightedrmsd", -1));
01449   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(wdiffrmsd));
01450   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("maxdiff", -1));
01451   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(maxdiff));
01452   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numdiff", -1));
01453   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewIntObj(numdiff));
01454   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("caption", -1));
01455   Tcl_ListObjAppendElement(interp, tcl_result, caption);
01456   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numEntries", -1));
01457   Tcl_ListObjAppendElement(interp, tcl_result, numEntries);
01458   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("histo", -1));
01459   Tcl_ListObjAppendElement(interp, tcl_result, objHisto);
01460   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("avgErr", -1));
01461   Tcl_ListObjAppendElement(interp, tcl_result, objAverage);
01462   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("maxError", -1));
01463   Tcl_ListObjAppendElement(interp, tcl_result, objMax);
01464   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("binRMSD", -1));
01465   Tcl_ListObjAppendElement(interp, tcl_result, objBinRMSD);
01466   Tcl_SetObjResult(interp, tcl_result);
01467 
01468   delete [] histo;
01469   delete [] num;
01470   delete [] maxEntry;
01471   delete [] binrmsd;
01472   return TCL_OK;
01473 }
01474 
01475 int obj_volmap(ClientData cd, Tcl_Interp *interp, int argc, Tcl_Obj * const objv[]) {
01476     
01477   if (argc < 2) {
01478     Tcl_SetResult(interp, (char *)
01479       "usage: volmap <command> <args...>\n"
01480       "\nVolmap Creation:\n"
01481       " volmap <maptype> <selection> [opts...]   -- create a new volmap file\n"
01482       " maptypes:\n"
01483       "   density    -- arbitrary-weight density map [atoms/A^3]\n"
01484       "   interp     -- arbitrary-weight interpolation map [atoms/A^3]\n"
01485       "   distance   -- distance nearest atom surface [A]\n"
01486       "   occupancy  -- percent atomic occupancy of gridpoints [%]\n"
01487       "   mask       -- binary mask by painting spheres around atoms\n"
01488       "   coulomb    -- Coulomb electrostatic potential [kT/e] (slow)\n"
01489       "   coulombmsm -- Coulomb electrostatic potential [kT/e] (fast)\n"
01490       "   ils        -- free energy map [kT] computed by implicit ligand sampling\n"
01491       " options common to all maptypes:\n"
01492       "   -o <filename>           -- output DX format file name (use .dx extension)\n"
01493       "   -mol <molid>            -- export volmap into the specified mol\n"
01494       "   -res <float>            -- resolution in A of smallest cube\n"
01495       "   -allframes              -- compute for all frames of the trajectory\n"
01496       "   -combine <arg>          -- rule for combining the different frames\n"
01497       "                              <arg> = avg, min, max, stdev or pmf\n"
01498       "   -minmax <list of 2 vectors>   -- specify boundary of output grid\n"
01499       " options specific to certain maptypes:\n"
01500       "   -points                 -- use point particles for occupancy\n"
01501       "   -cutoff <float>         -- distance cutoff for calculations [A]\n"
01502       "   -radscale <float>       -- premultiply all atomic radii by a factor\n"
01503       "   -weight <str/list>      -- per atom weights for calculation\n"
01504       " options for ils:\n"
01505       "   see documentation\n", NULL);
01506     return TCL_ERROR;
01507   }
01508 
01509   VMDApp *app = (VMDApp *)cd;
01510   char *arg1 = Tcl_GetStringFromObj(objv[1],NULL);
01511 
01512   // If maptype is recognized, proceed with the map creation (vs. yet-unimplemented map operations)...
01513   if (argc > 1 && !strupncmp(arg1, "occupancy", CMDLEN))
01514     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01515   if (argc > 1 && !strupncmp(arg1, "density", CMDLEN))
01516     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01517   if (argc > 1 && !strupncmp(arg1, "interp", CMDLEN))
01518     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01519   if (argc > 1 && !strupncmp(arg1, "distance", CMDLEN))
01520     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01521   if (argc > 1 && !strupncmp(arg1, "mask", CMDLEN))
01522     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01523   if (argc > 1 && (!strupncmp(arg1, "coulombpotential", CMDLEN) || 
01524                    !strupncmp(arg1, "coulomb", CMDLEN) ||
01525                    !strupncmp(arg1, "coulombmsm", CMDLEN)))
01526     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);   
01527 
01528   if (argc > 1 && !strupncmp(arg1, "compare", CMDLEN))
01529     return vmd_volmap_compare(app, argc-1, objv+1, interp);
01530 
01531   if (argc > 1 && !strupncmp(arg1, "ils", CMDLEN))
01532     return vmd_volmap_ils(app, argc-1, objv+1, interp);
01533   if (argc > 1 && !strupncmp(arg1, "ligand", CMDLEN))
01534     return vmd_volmap_ils(app, argc-1, objv+1, interp);
01535 
01536   Tcl_SetResult(interp, (char *)"Type 'volmap' for summary of usage\n",NULL);
01537   return TCL_ERROR;
01538 }

Generated on Sun May 12 04:20:57 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002