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

TclVolMap.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 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: saam $ $Locker:  $             $State: Exp $
00014  *      $Revision: 1.115 $      $Date: 2011/03/05 21:32:15 $
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[3*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[3*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.",
00450                          NULL);
00451         bailout = true;
00452       }
00453       
00454       // The probe was specified in form of an atomselection
00455       Molecule *probemol = app->moleculeList->mol_from_id(probesel->molid());
00456       const float *radius = probemol->extraflt.data("radius");
00457       if (!radius) {
00458         Tcl_AppendResult(interp, "volmap ils: probe selection contains no VDW radii", NULL);
00459         bailout = true;
00460       }
00461       
00462       const float *occupancy = probemol->extraflt.data("occupancy");
00463       if (!occupancy) {
00464         Tcl_AppendResult(interp, "volmap ils: probe selection contains no VDW epsilon values (in occupancy field)", NULL);
00465         bailout = true;
00466       }
00467       
00468       if (!bailout) {
00469         const float *charge = probemol->extraflt.data("charge");
00470         
00471         num_probe_atoms = probesel->selected;
00472         if (!nprobevdw) {
00473           probe_vdwrmin = new float[num_probe_atoms];
00474           probe_vdweps  = new float[num_probe_atoms];
00475         }
00476         probe_charge  = new float[num_probe_atoms];
00477         probe_coords  = new float[3*num_probe_atoms];
00478         const float *coords = probesel->coordinates(app->moleculeList);
00479         int i, j=0;
00480         for (i=0; i<probesel->num_atoms; i++) {
00481           if (probesel->on[i]) {
00482             vec_copy(&probe_coords[3*j], &coords[3*i]);
00483 
00484             if (!nprobevdw) {
00485               probe_vdweps[j]  = -fabsf(occupancy[i]);
00486               probe_vdwrmin[j] = radius[i];
00487             }
00488             if (!nprobecharge) {
00489               if (charge) probe_charge[j] = charge[i];
00490               else        probe_charge[j] = 0.f;
00491             }
00492             j++;
00493           }
00494         }  
00495       }
00496       
00497     } else {
00498       // The probe was specified through a coordinate list
00499       if (nprobecoor==0 && nprobevdw==1) {
00500         // No need to specify coodinates of monoatomic probe
00501         num_probe_atoms = 1;
00502         probe_coords = new float[3];
00503         probe_coords[0] = probe_coords[1] = probe_coords[2] = 0.f;
00504       } else {
00505         num_probe_atoms = nprobecoor;
00506       }
00507 
00508       if (!nprobevdw) {
00509         Tcl_AppendResult(interp, "volmap ils: No probe VDW parameters specified.", NULL);
00510         bailout = true;      
00511       }
00512 
00513       if (nprobecharge && nprobecharge!=num_probe_atoms && !bailout) {
00514         Tcl_AppendResult(interp, "volmap ils: # probe charges doesn't match # probe atoms", NULL);
00515         bailout = true;
00516       }
00517     }
00518 
00519     if (num_probe_atoms==0 && !bailout) {
00520       Tcl_AppendResult(interp, "volmap: No probe coordinates specified.", NULL);
00521       bailout = true;
00522     }
00523 
00524     if (nprobevdw && nprobevdw!=num_probe_atoms && !bailout) {
00525       Tcl_AppendResult(interp, "volmap ils: # probe VDW params doesn't match # probe atoms", NULL);
00526       bailout = true;
00527     }
00528 
00529     if (pbc && !alignsel) {
00530       Tcl_AppendResult(interp, "volmap ils: You cannot use -pbc without also "
00531                        " providing -alignsel.", NULL);
00532       bailout = true;
00533     }
00534 
00535     //if (num_probe_atoms==1 && num_conf>1 && !bailout) {
00536       //Tcl_AppendResult(interp, "volmap: Specifying -orient for monoatomic probes makes no sense.", NULL);
00537       //bailout = true;
00538     //}
00539   }
00540 
00541   if (bailout) {
00542     if (transform) delete transform;
00543     if (pbccenter) delete [] pbccenter;
00544     if (filebase)  delete [] filebase;
00545     if (probe_vdwrmin) delete [] probe_vdwrmin;
00546     if (probe_vdweps)  delete [] probe_vdweps;
00547     if (probe_charge)  delete [] probe_charge;
00548     if (probe_coords)  delete [] probe_coords;
00549     return TCL_ERROR;
00550   }
00551 
00552   // If the probe was provided in form of an atom selection
00553   // determine the symmetry of the probe. We need to know if
00554   // the probe has a tetrahedral point group, the highest
00555   // rotary axis and any C2 axis orthogonal to it.
00556   // If the probe was specified through parameter list instead
00557   // of a selection then the ILS code will try a simple
00558   // symmetry check itself
00559   int tetrahedral_symm = 0;
00560   int order1=0, order2=0;
00561   float symmaxis1[3];
00562   float symmaxis2[3];
00563   if (probesel) {
00564     msgInfo << "Determining probe symmetry:" << sendmsg;
00565 
00566     // Create Symmetry object, verbosity level = 1
00567     Symmetry sym = Symmetry(probesel, app->moleculeList, 1);
00568     
00569     // Set tolerance for atomic overlapping
00570     sym.set_overlaptol(0.05f);
00571     
00572     // Take bonds into account
00573     sym.set_checkbonds(1);
00574 
00575     // Guess the symmetry
00576     int ret_val = sym.guess(0.05f);
00577     if (ret_val < 0) {
00578       Tcl_AppendResult(interp, "measure symmetry: ", measure_error(ret_val), NULL);
00579       return TCL_ERROR;
00580     }
00581     int pgorder;
00582     char pointgroup[6];
00583     sym.get_pointgroup(pointgroup, &pgorder);
00584 
00585     if (pointgroup[0]=='T') tetrahedral_symm = 1;
00586 
00587     if (sym.numaxes()) {
00588       // First symmetry axis
00589       vec_copy(symmaxis1, sym.axis(0));
00590       order1 = sym.get_axisorder(0);
00591 
00592       int i;
00593       for (i=1; i<sym.numaxes(); i++) {
00594         vec_copy(symmaxis2, sym.axis(i));
00595         if (fabs(dot_prod(symmaxis1, symmaxis2)) < DEGTORAD(1.f)) {
00596           // Orthogonal second axis found
00597           order2 = sym.get_axisorder(i);
00598           break;
00599         }
00600       }
00601     }
00602   }
00603 
00604   // 6. Create the volmap
00605   VolMapCreateILS vol(app, molid, first, last, (float)temperature,
00606                       (float)resolution, subres, (float)cutoff,
00607                       maskonly);
00608 
00609   vol.set_probe(num_probe_atoms, num_conf, probe_coords,
00610                 probe_vdwrmin, probe_vdweps, probe_charge);
00611   vol.set_maxenergy(float(maxenergy));
00612 
00613   if (pbc)       vol.set_pbc(pbccenter, pbcbox);
00614   if (transform) vol.set_transform(transform);
00615   if (alignsel)  vol.set_alignsel(alignsel);
00616   if (!pbcbox) {
00617     vol.set_minmax(float(minmax[0]), float(minmax[1]), float(minmax[2]),
00618                    float(minmax[3]), float(minmax[4]), float(minmax[5]));
00619   }
00620 
00621   if (tetrahedral_symm || order1 || order2) {
00622     // Provide info about probe symmetry
00623     vol.set_probe_symmetry(order1, symmaxis1, order2, symmaxis2, tetrahedral_symm);
00624   }
00625 
00626   // Create map...
00627   int ret_val = vol.compute();
00628 
00629   if (ret_val < 0) {
00630     Tcl_AppendResult(interp, "\nvolmap: ERROR ", measure_error(ret_val), NULL);
00631 
00632     if (transform) delete transform;
00633     if (pbccenter) delete [] pbccenter;
00634     if (filebase)  delete [] filebase;
00635     if (probe_vdwrmin) delete [] probe_vdwrmin;
00636     if (probe_vdweps)  delete [] probe_vdweps;
00637     if (probe_charge)  delete [] probe_charge;
00638     if (probe_coords)  delete [] probe_coords;
00639     return TCL_ERROR;
00640   }
00641 
00642   int numconf, numorient, numrot;
00643   vol.get_statistics(numconf, numorient, numrot);
00644 
00645   // If the probe was specified in form of a selection and a separate
00646   // molecule then we append a frame for each conformer and set the
00647   // probe coordinates accordingly.
00648   if (probesel && probesel->molid()!=molid) {
00649     float *conformers = NULL;
00650     int numconf = vol.get_conformers(conformers);
00651     Molecule *pmol = app->moleculeList->mol_from_id(probesel->molid());
00652     int i, j;
00653     for (i=0; i<numconf; i++) {
00654       if (i>0) {
00655         pmol->duplicate_frame(pmol->current());
00656       }
00657       float *coor = pmol->get_frame(i)->pos;
00658       int k=0;
00659       for (j=0; j<probesel->num_atoms; j++) { 
00660         if (!probesel->on[j]) continue; //atom is not selected
00661 
00662         vec_copy(&coor[3*j], &conformers[i*3*num_probe_atoms+3*k]);
00663         k++;
00664       }
00665     }
00666   }
00667 
00668   // Export volmap to a file or just add it to the molecule:
00669   if (export_to_file) {
00670     // Add .dx suffix to filebase if it is missing
00671     filename = new char[strlen(filebase)+16];
00672     strcpy(filename, filebase);
00673     char *suffix = strrchr(filename, '.'); // beginning of .dx
00674     if (strcmp(suffix, ".dx")) strcat(filename, ".dx");
00675 
00676     // Write tha map into a dx file
00677     if (!vol.write_map(filename)) {
00678       Tcl_AppendResult(interp, "\nvolmap: ERROR Could not write ils map to file", NULL);
00679     }
00680 
00681     delete[] filename;
00682 
00683   } else {
00684     if (!vol.add_map_to_molecule()) {
00685       Tcl_AppendResult(interp, "\nvolmap: ERROR Could not add ils map to molecule", NULL);
00686     }
00687   }
00688     
00689   Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL);
00690   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numconf", -1));
00691   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numconf));
00692   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numorient", -1));
00693   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numorient));
00694   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numrot", -1));
00695   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(numrot));
00696   Tcl_SetObjResult(interp, tcl_result);
00697 
00698   if (transform) delete transform;
00699   if (pbccenter) delete [] pbccenter;
00700   if (filebase)  delete [] filebase;
00701   if (probe_vdwrmin) delete [] probe_vdwrmin;
00702   if (probe_vdweps)  delete [] probe_vdweps;
00703   if (probe_charge)  delete [] probe_charge;
00704   if (probe_coords)  delete [] probe_coords;
00705 
00706   return TCL_OK;
00707 }
00708 
00709 
00710 static int vmd_volmap_new_fromtype(VMDApp *app, int argc, Tcl_Obj * const objv[], Tcl_Interp *interp) {
00711 
00712   // 1. Figure out which map type we are dealing with:
00713   enum {UNDEF_MAP, DENS_MAP, INTERP_MAP, DIST_MAP, OCCUP_MAP, MASK_MAP,
00714         CPOTENTIAL_MAP, CPOTENTIALMSM_MAP } maptype=UNDEF_MAP;
00715 
00716   char *maptype_string=Tcl_GetString(objv[0]); 
00717 
00718   if      (!strcmp(maptype_string, "density"))    maptype=DENS_MAP;
00719   else if (!strcmp(maptype_string, "interp"))     maptype=INTERP_MAP;
00720   else if (!strcmp(maptype_string, "distance"))   maptype=DIST_MAP;
00721   else if (!strcmp(maptype_string, "occupancy"))  maptype=OCCUP_MAP; 
00722   else if (!strcmp(maptype_string, "mask"))       maptype=MASK_MAP; 
00723   else if (!strcmp(maptype_string, "coulomb"))    maptype=CPOTENTIAL_MAP;
00724   else if (!strcmp(maptype_string, "coulombpotential")) maptype=CPOTENTIAL_MAP;
00725   else if (!strcmp(maptype_string, "coulombmsm"))  maptype=CPOTENTIALMSM_MAP;
00726  
00727   // 2. Get atom selection
00728   if (argc < 2) { 
00729     Tcl_AppendResult(interp, "volmap: no atom selection.", NULL);
00730     return TCL_ERROR;
00731   }
00732 
00733   AtomSel *sel = NULL;
00734   sel = tcl_commands_get_sel(interp, Tcl_GetStringFromObj(objv[1],NULL));
00735   if (!sel) {
00736     Tcl_AppendResult(interp, "volmap: no atom selection.", NULL);
00737     return TCL_ERROR;
00738   }
00739   if (!sel->selected) {
00740     Tcl_AppendResult(interp, "volmap: no atoms selected.", NULL);
00741     return TCL_ERROR;
00742   }
00743   if (!app->molecule_valid_id(sel->molid())) {
00744     Tcl_AppendResult(interp, "volmap: ",
00745                      measure_error(MEASURE_ERR_NOMOLECULE), NULL);
00746     return TCL_ERROR;
00747   }
00748 
00749 
00750   // 3. Define and initialize the optional arguments
00751   bool accept_weight = false; // allow a user-specified weight for each atom
00752   bool accept_cutoff = false; // parse a user-specified cutoff distance
00753   bool accept_radius = false; // allow radius multiplicator for density
00754   bool accept_usepoints = false; // allows use of point particles
00755 
00756   bool use_point_particles = false;  // for MASK map
00757   bool export_to_file = false;
00758   bool use_all_frames = false;
00759   bool bad_usage = false;
00760 
00761   int export_molecule = -1;
00762   double cutoff        = 5.;
00763   double radius_factor = 1.;
00764   double resolution    = 1.;
00765   double minmax[6];
00766   
00767   char *filebase = NULL;
00768   char *filename = NULL;
00769 
00770   
00771   // File export options
00772   int checkpoint_freq = 500;
00773       
00774 
00775   // Specify required/accepted options for each maptype as well as default values.
00776   switch(maptype) {
00777     case DENS_MAP:
00778       accept_weight = true;
00779       accept_radius = true;
00780       break;
00781     case INTERP_MAP:
00782       accept_weight = true; 
00783       break;
00784     case DIST_MAP:
00785       accept_cutoff = true;
00786       cutoff = 3.;
00787       break;
00788     case OCCUP_MAP:
00789       accept_usepoints = true;
00790       break;
00791     case MASK_MAP:
00792       accept_cutoff = true;
00793       cutoff = 4.;
00794       break;
00795     case CPOTENTIAL_MAP:
00796     case CPOTENTIALMSM_MAP:
00797       break; 
00798     case UNDEF_MAP:
00799       bad_usage = true;
00800       break;   
00801   }
00802  
00803 
00804   // 4. Parse the command-line
00805   int arg_weight=0, arg_combine=0, arg_minmax=0;
00806 
00807   // Parse the arguments
00808   for (int arg=2; arg<argc && !bad_usage; arg++) {
00809     if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-res")) {
00810       if (arg+1>=argc) bad_usage=true;
00811       Tcl_GetDoubleFromObj(interp, objv[arg+1], &resolution);
00812       if (resolution <= 0.f) {
00813         Tcl_AppendResult(interp, "volmap: resolution must be positive. (-res)", NULL);
00814         return TCL_ERROR;
00815       }
00816       arg++;
00817     }
00818     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-mol")) { // add volmap to mol
00819       if (arg+1 >= argc) bad_usage=true;
00820       if (!strcmp(Tcl_GetStringFromObj(objv[arg+1], NULL), "top"))
00821         export_molecule = app->molecule_top(); 
00822       else 
00823         Tcl_GetIntFromObj(interp, objv[arg+1], &export_molecule);
00824       
00825       if (!app->molecule_valid_id(export_molecule)) {
00826         Tcl_AppendResult(interp, "volmap: molecule specified for ouput is invalid. (-mol)", NULL);
00827         return TCL_ERROR;
00828       }
00829       arg++;
00830     }
00831     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-minmax")) {
00832       arg_minmax=arg+1;
00833       arg++;
00834       if (arg_minmax>=argc) bad_usage=true;
00835       if (parse_minmax_args(interp, arg_minmax, objv, minmax)!=TCL_OK) {
00836         return TCL_ERROR;
00837       }
00838     }
00839     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-checkpoint")) {
00840       if (arg+1 >= argc) bad_usage=true;
00841       Tcl_GetIntFromObj(interp, objv[arg+1], &checkpoint_freq);
00842       if (checkpoint_freq < 0) {
00843         Tcl_AppendResult(interp, "volmap: invalid -checkpoint parameter", NULL);
00844         return TCL_ERROR;
00845       }
00846       arg++;
00847     }
00848     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-allframes")) {
00849       use_all_frames=true;
00850     }
00851     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-dx") ||
00852              !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-o")) {
00853       if (arg+1>=argc) {bad_usage=true; break;}
00854       const char* outputfilename = Tcl_GetString(objv[arg+1]);
00855       if (outputfilename) {
00856         filebase = new char[strlen(outputfilename)+1];
00857         strcpy(filebase, outputfilename);
00858         export_to_file = true;
00859       }
00860       arg++;
00861     }
00862     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-combine")) {
00863       arg_combine=arg+1;
00864       arg++;
00865       if (arg_combine>=argc) bad_usage=true;
00866     }
00867     else if (accept_usepoints && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-points")) {
00868       use_point_particles=true;
00869     }
00870     else if (accept_cutoff && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-cutoff")) {
00871       if (arg+1 >= argc) bad_usage=true;
00872       Tcl_GetDoubleFromObj(interp, objv[arg+1], &cutoff);
00873       if (cutoff <= 0.) {
00874         Tcl_AppendResult(interp, "volmap: cutoff must be positive. (-cutoff)", NULL);
00875         return TCL_ERROR;
00876       }
00877       arg++;
00878     }
00879     else if (accept_radius && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-radscale")) {
00880       if (arg+1 >= argc) bad_usage=true;
00881       Tcl_GetDoubleFromObj(interp, objv[arg+1], &radius_factor);
00882       if (radius_factor < 0.f) {
00883         Tcl_AppendResult(interp, "volmap: radscale must be positive. (-radscale)", NULL);
00884         return TCL_ERROR;
00885       }
00886       arg++;
00887     }
00888     else if (accept_weight && !strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-weight")) {
00889       if (arg+1>=argc) bad_usage=true;
00890       arg_weight = arg+1;      
00891       arg++;
00892     }
00893     
00894     else //unknown arg
00895       bad_usage=true; 
00896   }
00897   
00898     
00899   if (bad_usage) {
00900     if (maptype == UNDEF_MAP)
00901       Tcl_AppendResult(interp, "volmap: unknown map type.", NULL);
00902     else
00903       Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<selection> [options...]");
00904 
00905     return TCL_ERROR;
00906   }
00907   
00908   
00909   // 5. Assign some other optional parameters
00910      
00911   // parse map combination type
00912   VolMapCreate::CombineType combine_type=VolMapCreate::COMBINE_AVG;
00913   if (arg_combine) {
00914     char *combine_str=Tcl_GetString(objv[arg_combine]);
00915     if (!strcmp(combine_str, "avg") || !strcmp(combine_str, "average")) 
00916       combine_type=VolMapCreate::COMBINE_AVG;
00917     else if (!strcmp(combine_str, "max") || !strcmp(combine_str, "maximum")) 
00918       combine_type=VolMapCreate::COMBINE_MAX;
00919     else if (!strcmp(combine_str, "min") || !strcmp(combine_str, "minimum")) 
00920       combine_type=VolMapCreate::COMBINE_MIN;
00921     else if (!strcmp(combine_str, "stdev")) 
00922       combine_type=VolMapCreate::COMBINE_STDEV;
00923     else if (!strcmp(combine_str, "pmf")) 
00924       combine_type=VolMapCreate::COMBINE_PMF;
00925     else {
00926       Tcl_AppendResult(interp, "volmap: -combine argument must be: avg, min, \
00927                                 max, stdev, pmf", NULL);
00928       return TCL_ERROR;
00929     }
00930   }
00931  
00932   // parse weights
00933   int ret_val=0;
00934   float *weights = NULL;
00935   if (accept_weight) {
00936     weights = new float[sel->selected];
00937 
00938     if (arg_weight) 
00939       ret_val = tcl_get_weights(interp, app, sel, objv[arg_weight], weights);
00940     else
00941       ret_val = tcl_get_weights(interp, app, sel, NULL, weights);
00942     
00943     if (ret_val < 0) {
00944       Tcl_AppendResult(interp, "volmap: ", measure_error(ret_val), NULL);
00945       delete [] weights;
00946       return TCL_ERROR;
00947     }
00948   }
00949   
00950 
00951 
00952   // 6. Create the volmap
00953   VolMapCreate *volcreate = NULL;   
00954 
00955   // init the map creator objects and set default filenames
00956   switch(maptype) {
00957     case DENS_MAP: 
00958       volcreate = new VolMapCreateDensity(app, sel, (float)resolution, weights, (float)radius_factor);
00959       if (!filebase) {
00960         filebase = new char[strlen("density_out.dx")+1];
00961         strcpy(filebase, "density_out.dx");
00962       }
00963       break;
00964 
00965     case INTERP_MAP: 
00966       volcreate = new VolMapCreateInterp(app, sel, (float)resolution, weights);
00967       if (!filebase) {
00968         filebase = new char[strlen("interp_out.dx")+1];
00969         strcpy(filebase, "interp_out.dx");
00970       }
00971       break;
00972 
00973     case DIST_MAP:
00974       volcreate = new VolMapCreateDistance(app, sel, (float)resolution, (float)cutoff);
00975       if (!filebase) {
00976         filebase = new char[strlen("distance_out.dx")+1];
00977         strcpy(filebase, "distance_out.dx");
00978       }
00979       break;
00980 
00981     case OCCUP_MAP:
00982       volcreate = new VolMapCreateOccupancy(app, sel, (float)resolution, use_point_particles);
00983       if (!filebase) {
00984         filebase = new char[strlen("occupancy_out.dx")+1];
00985         strcpy(filebase, "occupancy_out.dx");
00986       }
00987       break;
00988 
00989     case MASK_MAP:
00990       volcreate = new VolMapCreateMask(app, sel, (float)resolution, (float)cutoff);
00991       if (!filebase) {
00992         filebase = new char[strlen("mask_out.dx")+1];
00993         strcpy(filebase, "mask_out.dx");
00994       }
00995       break;
00996 
00997     case CPOTENTIAL_MAP:
00998       volcreate = new VolMapCreateCoulombPotential(app, sel, (float)resolution);
00999       if (!filebase) {
01000         filebase = new char[strlen("coulomb_out.dx")+1];
01001         strcpy(filebase, "coulomb_out.dx");
01002       }
01003       break;
01004 
01005     case CPOTENTIALMSM_MAP:
01006       volcreate = new VolMapCreateCoulombPotentialMSM(app, sel, (float)resolution);
01007       if (!filebase) {
01008         filebase = new char[strlen("coulombmsm_out.dx")+1];
01009         strcpy(filebase, "coulombmsm_out.dx");
01010       }
01011       break;
01012 
01013 
01014     default:  // silence compiler warnings
01015       break;  
01016   }
01017 
01018   // generate and write out volmap
01019   if (volcreate) {
01020     // Pass parameters common to all volmap types
01021     if (arg_minmax)
01022       volcreate->set_minmax(float(minmax[0]), float(minmax[1]),
01023                             float(minmax[2]), float(minmax[3]), 
01024                             float(minmax[4]), float(minmax[5]));
01025     
01026     // Setup checkpointing
01027     if (checkpoint_freq) {
01028       char *checkpointname = new char[32+strlen(filebase)+1];
01029 #if defined(_MSC_VER)
01030       char slash = '\\';
01031 #else
01032       char slash = '/';
01033 #endif
01034       char *tailname = strrchr(filebase, slash);
01035       if (!tailname) tailname = filebase;
01036       else tailname = tailname+1;
01037       char *dirname = new char[strlen(filebase)+1];
01038       strcpy(dirname, filebase);
01039       char *sep = strrchr(dirname, slash);
01040 
01041       if (sep) {
01042         *sep = '\0';
01043         sprintf(checkpointname, "%s%ccheckpoint:%s", dirname, slash, tailname);
01044       }
01045       else {
01046         *dirname = '\0';
01047         sprintf(checkpointname, "checkpoint:%s", tailname);
01048       }
01049       delete[] dirname;
01050 
01051       Tcl_AppendResult(interp, "CHECKPOINTNAME = ", checkpointname, NULL);
01052       volcreate->set_checkpoint(checkpoint_freq, checkpointname);
01053       delete[] checkpointname;
01054     }
01055     
01056     // Create map...
01057     ret_val = volcreate->compute_all(use_all_frames, combine_type, NULL);
01058     if (ret_val < 0) {
01059       delete volcreate;
01060       if (weights)  delete [] weights;
01061       if (filebase) delete [] filebase;
01062 
01063       Tcl_AppendResult(interp, "\nvolmap: ERROR ", measure_error(ret_val), NULL);
01064       return TCL_ERROR;
01065     }
01066     
01067     // Export volmap to a file:
01068     if (export_to_file || export_molecule < 0) {
01069       // add .dx suffix to filebase if it is missing
01070       filename = new char[strlen(filebase)+16];
01071       strcpy(filename,filebase);
01072       char *suffix = strrchr(filename, '.');
01073       if (!strcmp(suffix,".dx")) *suffix = '\0';
01074       strcat(filename, ".dx");
01075       volcreate->write_map(filename);
01076       delete[] filename;
01077     }
01078     
01079     // Export volmap to a molecule:
01080     if (export_molecule >= 0) {
01081       VolumetricData *volmap = volcreate->volmap;
01082       float origin[3], xaxis[3], yaxis[3], zaxis[3];
01083       int i;
01084       for (i=0; i<3; i++) {
01085         origin[i] = (float) volmap->origin[i];
01086         xaxis[i] = (float) volmap->xaxis[i];
01087         yaxis[i] = (float) volmap->yaxis[i];
01088         zaxis[i] = (float) volmap->zaxis[i];
01089       }
01090       int err = app->molecule_add_volumetric(export_molecule, 
01091          (volmap->name) ? volmap->name : "(no name)",
01092          origin, xaxis, yaxis, zaxis,
01093          volmap->xsize, volmap->ysize, volmap->zsize, volmap->data);
01094       if (err != 1) {
01095         Tcl_AppendResult(interp, "ERROR: export of volmap into molecule was unsuccessful!", NULL);
01096       }
01097       else volmap->data=NULL; // avoid data being deleted by volmap's destructor (it is now owned by the molecule)
01098     }
01099 
01100     delete volcreate;
01101   }
01102   
01103   if (weights) delete [] weights;
01104   if (filebase) delete [] filebase;
01105 
01106   return TCL_OK;
01107 }
01108 
01109 
01110 // vec_sub() from utilities.h works with float* only
01111 // here I needed doubles.
01112 #define DOUBLE_VSUB(D, X, Y) \
01113   D[0] = float(X[0]-Y[0]); \
01114   D[1] = float(X[1]-Y[1]); \
01115   D[2] = float(X[2]-Y[2]); 
01116 
01117 // Compare two volumetric maps:
01118 // volmap compare <molid1> <volid1> <molid2> <volid2>
01119 // The two maps must be specified by their molID and volID.
01120 // Prints the min/max vales, the largest difference, the RMSD,
01121 // the RMSD computed inly for the elements that differ and the
01122 // RMSD weighted by the magnitude of the elements compared so
01123 // that smaller values receive a larger weight.
01124 // (For ILS we are interested mainly in the smaller energies)
01125 static int vmd_volmap_compare(VMDApp *app, int argc, Tcl_Obj * const objv[], Tcl_Interp *interp)
01126 {
01127   int molid1 = -1;
01128   int molid2 = -1;
01129   int mapid1 = -1;
01130   int mapid2 = -1;
01131 
01132   // Get the molecule IDs
01133   if (!strcmp(Tcl_GetStringFromObj(objv[1], NULL), "top"))
01134     molid1 = app->molecule_top(); 
01135   else 
01136     Tcl_GetIntFromObj(interp, objv[1], &molid1);
01137   
01138   if (!strcmp(Tcl_GetStringFromObj(objv[3], NULL), "top"))
01139     molid2 = app->molecule_top(); 
01140   else 
01141     Tcl_GetIntFromObj(interp, objv[3], &molid2);
01142 
01143   if (!app->molecule_valid_id(molid1) || !app->molecule_valid_id(molid2)) {
01144     Tcl_AppendResult(interp, "volmap compare: molecule specified for ouput is invalid. (-mol)", NULL);
01145     return TCL_ERROR;
01146   }
01147 
01148   Molecule *mol1 = app->moleculeList->mol_from_id(molid1);
01149   Molecule *mol2 = app->moleculeList->mol_from_id(molid2);
01150 
01151   // Get volmap IDs
01152   Tcl_GetIntFromObj(interp, objv[2], &mapid1);
01153   Tcl_GetIntFromObj(interp, objv[4], &mapid2);
01154 
01155   if (mapid1<0 || mapid2<0) {
01156     Tcl_AppendResult(interp, "volmap compare: Volmap ID must be positive.", NULL);
01157     return TCL_ERROR;
01158   }
01159   if (mapid1 >= mol1->num_volume_data() ||
01160       mapid2 >= mol2->num_volume_data()) {
01161     Tcl_AppendResult(interp, "volmap compare: Volmap ID does not exist.", NULL);
01162     return TCL_ERROR;
01163   }
01164 
01165   // Parse optional arguments
01166   bool bad_usage = false;
01167   double histinterval = 2.5;
01168   int numbins = 9;
01169   int arg;
01170   for (arg=5; arg<argc && !bad_usage; arg++) {
01171     if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-interval")) {
01172       if (arg+1>=argc) { bad_usage=true; break; }
01173       Tcl_GetDoubleFromObj(interp, objv[arg+1], &histinterval);
01174       if (histinterval <= 0.f) {
01175         Tcl_AppendResult(interp, "volmap compare: histogram interval must be positive. (-interval)", NULL);
01176         return TCL_ERROR;
01177       }
01178       arg++;
01179     }
01180     else if (!strcmp(Tcl_GetStringFromObj(objv[arg], NULL), "-numbins")) {
01181       if (arg+1>=argc) { bad_usage=true; break; }
01182       Tcl_GetIntFromObj(interp, objv[arg+1], &numbins);
01183       if (numbins <= 0) {
01184         Tcl_AppendResult(interp, "volmap compare: histogram bin size must be positive. (-interval)", NULL);
01185         return TCL_ERROR;
01186       }
01187       arg++;
01188     }
01189     else {
01190       // unknown arg
01191       Tcl_AppendResult(interp, " volmap compare: unknown argument ",
01192                        Tcl_GetStringFromObj(objv[arg], NULL), NULL);
01193       return TCL_ERROR;
01194     }
01195 
01196   }
01197   if (bad_usage) {
01198     Tcl_WrongNumArgs(interp, 2, objv-1, (char *)"<molid> <minmax> [options...]");
01199     return TCL_ERROR;
01200   }
01201   
01202   const VolumetricData *vol1 = mol1->get_volume_data(mapid1);
01203   const VolumetricData *vol2 = mol2->get_volume_data(mapid2);
01204 
01205   if (vol1->xsize != vol2->xsize ||
01206       vol1->ysize != vol2->ysize ||
01207       vol1->zsize != vol2->zsize) {
01208     Tcl_AppendResult(interp, "volmap compare: maps have different dimensions.", NULL);
01209     return TCL_ERROR;
01210   }
01211 
01212   float vdiff[3];
01213   DOUBLE_VSUB(vdiff, vol1->origin, vol2->origin);
01214   if (norm(vdiff)>1e-6) {
01215     Tcl_AppendResult(interp, "volmap compare: maps have different origin.", NULL);
01216   }
01217 
01218   DOUBLE_VSUB(vdiff, vol1->xaxis, vol2->xaxis);
01219   if (norm(vdiff)>1e-6) {
01220     Tcl_AppendResult(interp, "volmap compare: maps have different x-axis.", NULL);
01221   }
01222   DOUBLE_VSUB(vdiff, vol1->yaxis, vol2->yaxis);
01223   if (norm(vdiff)>1e-6) {
01224     Tcl_AppendResult(interp, "volmap compare: maps have different y-axis.", NULL);
01225   }
01226   DOUBLE_VSUB(vdiff, vol1->zaxis, vol2->zaxis);
01227   if (norm(vdiff)>1e-6) {
01228     Tcl_AppendResult(interp, "volmap compare: maps have different z-axis.", NULL);
01229   }
01230 
01231   int i;
01232   int numdiff = 0;
01233   float sqsum = 0.f;
01234   float sqsumd = 0.f;
01235   float min1 = 0.f, min2 = 0.f;
01236   float max1 = 0.f, max2 = 0.f;
01237   float maxdiff = 0.f;
01238   int indexmaxdiff = 0;
01239 
01240   for (i=0; i<vol1->gridsize(); i++) {
01241     float v1 = vol1->data[i];
01242     float v2 = vol2->data[i];
01243     float diff = v1-v2;
01244     sqsum += diff*diff;
01245     if (v1<min1) min1 = v1;
01246     if (v2<min2) min2 = v2;
01247     if (v1>max1) max1 = v1;
01248     if (v2>max2) max2 = v2;
01249     if (fabsf(diff)>maxdiff) {
01250       maxdiff = fabsf(diff);
01251       indexmaxdiff = i;
01252     }
01253     if (diff) {
01254       //printf("%g - %g = %g\n", v1, v2, diff);
01255       sqsumd += diff*diff;
01256       numdiff++;
01257     }
01258   }
01259   float rmsd = 0.f;
01260   float diffrmsd = 0.f;
01261   if (sqsum)  rmsd     = sqrtf(sqsum/vol1->gridsize());
01262   if (sqsumd) diffrmsd = sqrtf(sqsumd/numdiff);
01263 
01264   char tmpstr[128];
01265   msgInfo << "volmap compare" << sendmsg;
01266   msgInfo << "--------------" << sendmsg;
01267   msgInfo << "Comparing mol "<<molid1<<" -> map "<<mapid1<<"/"<<mol1->num_volume_data()<<sendmsg;
01268   msgInfo << "       to mol "<<molid2<<" -> map "<<mapid2<<"/"<<mol2->num_volume_data()<<sendmsg;
01269   msgInfo << "Statistics:" << sendmsg;
01270   sprintf(tmpstr, "            %12s  |  %12s", "MAP 1", "MAP 2");
01271   msgInfo << tmpstr << sendmsg;
01272   sprintf(tmpstr, "min value = %12g  |  %12g", min1, min2);
01273   msgInfo << tmpstr << sendmsg;
01274   sprintf(tmpstr, "max value = %12g  |  %12g", max1, max2);
01275   msgInfo << tmpstr << sendmsg;
01276   msgInfo << sendmsg;
01277   sprintf(tmpstr, "# differing elements = %d/%d", numdiff, vol1->gridsize());
01278   msgInfo << tmpstr << sendmsg;
01279   msgInfo << "max difference:" << sendmsg;
01280   sprintf(tmpstr, "   map1[%d] = %g   map2[%d] = %g   diff = %g",
01281       indexmaxdiff, vol1->data[indexmaxdiff],
01282       indexmaxdiff, vol2->data[indexmaxdiff], maxdiff);
01283   msgInfo << tmpstr << sendmsg;
01284 
01285   // Statistics for the differing elements only:
01286   msgInfo << sendmsg;
01287   sprintf(tmpstr, "         RMSD = %12.6f", rmsd);
01288   msgInfo << tmpstr << sendmsg;
01289   sprintf(tmpstr, "     diffRMSD = %12.6f  (for the set of differing elements)", diffrmsd);
01290   msgInfo << tmpstr << sendmsg;
01291 
01292   // Get weighted RMSD where the differences of smaller values
01293   // are weighted more because the low enegy values are what is 
01294   // of interest in ILS free energy maps.
01295   float wsum = 0.f;
01296   float range = max2-min2;
01297   float wdiffrmsd = 0.f;
01298   if (range) {
01299     sqsum = 0.f;
01300     for (i=0; i<vol1->gridsize(); i++) {
01301       float diff = vol1->data[i]-vol2->data[i];
01302       if (diff) {
01303         float weight = 1.f-(vol2->data[i]-min2)/range;
01304         wsum += weight;
01305         sqsum += diff*diff*weight;
01306       }
01307     }
01308     if (sqsum) wdiffrmsd = sqrtf(sqsum/wsum);
01309   }
01310  
01311 
01312   sprintf(tmpstr, "weighted RMSD = %12.6f  (for the set of differing elements)", wdiffrmsd);
01313   msgInfo << tmpstr << sendmsg;
01314   msgInfo <<      "     weight factor w = 1-(E_i-E_min)/(E_max-E_min)" << sendmsg;
01315   msgInfo << sendmsg;
01316 
01317   // Compare error of map 1 relative to map 2, create histogram of error:
01318   //   | E_approx - E_exact | / ( E_exact - E_exact_min + 1 ),
01319   // where map 1 is considered the approximation and map 2 is considered exact.
01320   //
01321   // Since energy is arbitrary, we shift from the minimum value 
01322   // (usually around -11 to -6) so that the dominator is always
01323   // greater than or equal to 1.  This weights the lower values
01324   // more heavily than the upper values, which is intentional.
01325   //
01326   // The histogram is summed for the intervals
01327   // (-\inf,10) [10,20) [20,30) [30,40) [40,+\inf)
01328 
01329 
01330   // total accumulated error for each bin
01331   float *histo = new float[numbins*sizeof(float)];
01332   // count number of samples per bin
01333   int *num = new int[numbins*sizeof(float)];
01334   // max error for each bin
01335   float *maxEntry = new float[numbins*sizeof(float)];
01336   float *binrmsd = new float[numbins*sizeof(float)];
01337   memset(histo,    0, numbins*sizeof(float));
01338   memset(num,      0, numbins*sizeof(int));
01339   memset(maxEntry, 0, numbins*sizeof(float));
01340   memset(binrmsd,  0, numbins*sizeof(float));
01341 
01342   for (i = 0;  i < vol1->gridsize();  i++) {
01343     float e1 = vol1->data[i];
01344     float e2 = vol2->data[i];
01345     float err = fabsf(e1 - e2) / (e2 - min2 + 1);
01346     int index = (int) floorf((e2 - min2) / float(histinterval));
01347     if      (index < 0)        index = 0;
01348     else if (index >= numbins) index = numbins - 1;
01349 
01350     // check to see if we need to update the max for this bin
01351     if (err > maxEntry[index]) { 
01352        maxEntry[index] = err; 
01353     }
01354     histo[index] += err;
01355     num[index]++;
01356     binrmsd[index] += (e2-e1)*(e2-e1);
01357   }
01358   for (i=0; i<numbins; i++) {
01359     if (binrmsd[i]) binrmsd[i] = sqrtf(binrmsd[i]/num[i]);
01360   }
01361 
01362   // lower boundary of the first bin
01363   float firstbin = floorf(min2/float(histinterval))*float(histinterval);
01364   Tcl_Obj *caption = Tcl_NewListObj(0, NULL);
01365   Tcl_Obj *numEntries = Tcl_NewListObj(0, NULL);
01366   Tcl_Obj *objHisto   = Tcl_NewListObj(0, NULL);
01367   Tcl_Obj *objAverage = Tcl_NewListObj(0, NULL);
01368   Tcl_Obj *objMax     = Tcl_NewListObj(0, NULL);
01369   Tcl_Obj *objBinRMSD = Tcl_NewListObj(0, NULL);
01370   char label[64];
01371   msgInfo << "Histogram of error in map 1 relative to map 2 " << sendmsg;
01372   msgInfo << sendmsg;
01373   msgInfo << "     interval   # samples    total error      avg error"
01374           << "      max error           rmsd" << sendmsg;
01375   msgInfo << "---------------------------------------------------------"
01376           << "----------------------------" << sendmsg;
01377 
01378   sprintf(label, "[%g,%g)", (double) firstbin, (double) (firstbin+histinterval));
01379   sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[0],
01380           (double) histo[0], (double) (!num[0]?0:histo[0]/num[0]),
01381           (double) maxEntry[0], (double) binrmsd[0]);
01382   msgInfo << tmpstr << sendmsg;
01383   Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01384   Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[0]));
01385   Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[0]));
01386   Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[0]?0:histo[0]/num[0]));
01387   Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[0]));
01388   Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[0]));
01389   for (i = 1;  i < numbins-1;  i++) {
01390     sprintf(label, "[%g,%g)", (double)(firstbin+i*histinterval), (double)(firstbin+(i+1)*histinterval));
01391     sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[i],
01392             (double) histo[i], (double) (!num[i]?0:histo[i]/num[i]),
01393             (double) maxEntry[i], (double) binrmsd[i]);
01394     Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01395     Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[i]));
01396     Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[i]));
01397     Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[i]?0:histo[i]/num[i]));
01398     Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[i]));
01399     Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[i]));
01400     msgInfo << tmpstr << sendmsg;
01401   }
01402   sprintf(label, "[%g,+infty)", (double)(firstbin+i*histinterval));
01403   sprintf(tmpstr, "%14s %10d %14.6f %14.6f %14.6f %14.6f", label, num[i],
01404           (double) histo[i], (double) (!num[i]?0:histo[i]/num[i]),
01405           (double) maxEntry[i], (double) binrmsd[i]);
01406   Tcl_ListObjAppendElement(interp, caption,    Tcl_NewStringObj(label, -1));
01407   Tcl_ListObjAppendElement(interp, numEntries, Tcl_NewIntObj(num[i]));
01408   Tcl_ListObjAppendElement(interp, objHisto,   Tcl_NewDoubleObj(histo[i]));
01409   Tcl_ListObjAppendElement(interp, objAverage, Tcl_NewDoubleObj(!num[i]?0:histo[i]/num[i]));
01410   Tcl_ListObjAppendElement(interp, objMax,     Tcl_NewDoubleObj(maxEntry[i]));
01411   Tcl_ListObjAppendElement(interp, objBinRMSD, Tcl_NewDoubleObj(binrmsd[i]));
01412   msgInfo << tmpstr << sendmsg;
01413   msgInfo << sendmsg;
01414 
01415   Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL);
01416   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("rmsd", -1));
01417   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(rmsd));
01418   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("diffrmsd", -1));
01419   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(diffrmsd));
01420   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("weightedrmsd", -1));
01421   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(wdiffrmsd));
01422   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("maxdiff", -1));
01423   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewDoubleObj(maxdiff));
01424   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numdiff", -1));
01425   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewIntObj(numdiff));
01426   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("caption", -1));
01427   Tcl_ListObjAppendElement(interp, tcl_result, caption);
01428   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("numEntries", -1));
01429   Tcl_ListObjAppendElement(interp, tcl_result, numEntries);
01430   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("histo", -1));
01431   Tcl_ListObjAppendElement(interp, tcl_result, objHisto);
01432   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("avgErr", -1));
01433   Tcl_ListObjAppendElement(interp, tcl_result, objAverage);
01434   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("maxError", -1));
01435   Tcl_ListObjAppendElement(interp, tcl_result, objMax);
01436   Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj("binRMSD", -1));
01437   Tcl_ListObjAppendElement(interp, tcl_result, objBinRMSD);
01438   Tcl_SetObjResult(interp, tcl_result);
01439 
01440   delete [] histo;
01441   delete [] num;
01442   delete [] maxEntry;
01443   delete [] binrmsd;
01444   return TCL_OK;
01445 }
01446 
01447 int obj_volmap(ClientData cd, Tcl_Interp *interp, int argc, Tcl_Obj * const objv[]) {
01448     
01449   if (argc < 2) {
01450     Tcl_SetResult(interp, (char *)
01451       "usage: volmap <command> <args...>\n"
01452       "\nVolmap Creation:\n"
01453       " volmap <maptype> <selection> [opts...]   -- create a new volmap file\n"
01454       " maptypes:\n"
01455       "   density    -- arbitrary-weight density map [atoms/A^3]\n"
01456       "   interp     -- arbitrary-weight interpolation map [atoms/A^3]\n"
01457       "   distance   -- distance nearest atom surface [A]\n"
01458       "   occupancy  -- percent atomic occupancy of gridpoints [%]\n"
01459       "   mask       -- binary mask by painting spheres around atoms\n"
01460       "   coulomb    -- Coulomb electrostatic potential [kT/e] (slow)\n"
01461       "   coulombmsm -- Coulomb electrostatic potential [kT/e] (fast)\n"
01462       "   ils        -- free energy map [kT] computed by implicit ligand sampling\n"
01463       " options common to all maptypes:\n"
01464       "   -o <filename>           -- output DX format file name (use .dx extension)\n"
01465       "   -mol <molid>            -- export volmap into the specified mol\n"
01466       "   -res <float>            -- resolution in A of smallest cube\n"
01467       "   -allframes              -- compute for all frames of the trajectory\n"
01468       "   -combine <arg>          -- rule for combining the different frames\n"
01469       "                              <arg> = avg, min, max, stdev or pmf\n"
01470       "   -minmax <list of 2 vectors>   -- specify boundary of output grid\n"
01471       " options specific to certain maptypes:\n"
01472       "   -points                 -- use point particles for occupancy\n"
01473       "   -cutoff <float>         -- distance cutoff for calculations [A]\n"
01474       "   -radscale <float>       -- premultiply all atomic radii by a factor\n"
01475       "   -weight <str/list>      -- per atom weights for calculation\n"
01476       " options for ils:\n"
01477       "   see documentation\n", NULL);
01478     return TCL_ERROR;
01479   }
01480 
01481   VMDApp *app = (VMDApp *)cd;
01482   char *arg1 = Tcl_GetStringFromObj(objv[1],NULL);
01483 
01484   // If maptype is recognized, proceed with the map creation (vs. yet-unimplemented map operations)...
01485   if (argc > 1 && !strupncmp(arg1, "occupancy", CMDLEN))
01486     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01487   if (argc > 1 && !strupncmp(arg1, "density", CMDLEN))
01488     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01489   if (argc > 1 && !strupncmp(arg1, "interp", CMDLEN))
01490     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01491   if (argc > 1 && !strupncmp(arg1, "distance", CMDLEN))
01492     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01493   if (argc > 1 && !strupncmp(arg1, "mask", CMDLEN))
01494     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);
01495   if (argc > 1 && (!strupncmp(arg1, "coulombpotential", CMDLEN) || 
01496                    !strupncmp(arg1, "coulomb", CMDLEN) ||
01497                    !strupncmp(arg1, "coulombmsm", CMDLEN)))
01498     return vmd_volmap_new_fromtype(app, argc-1, objv+1, interp);   
01499 
01500   if (argc > 1 && !strupncmp(arg1, "compare", CMDLEN))
01501     return vmd_volmap_compare(app, argc-1, objv+1, interp);
01502 
01503   if (argc > 1 && !strupncmp(arg1, "ils", CMDLEN))
01504     return vmd_volmap_ils(app, argc-1, objv+1, interp);
01505   if (argc > 1 && !strupncmp(arg1, "ligand", CMDLEN))
01506     return vmd_volmap_ils(app, argc-1, objv+1, interp);
01507 
01508   Tcl_SetResult(interp, (char *)"Type 'volmap' for summary of usage\n",NULL);
01509   return TCL_ERROR;
01510 }

Generated on Tue May 22 01:48:16 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002