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

VolMapCreate.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  * RCS INFORMATION:
00010  *
00011  *      $RCSfile: VolMapCreate.C,v $
00012  *      $Author: johns $        $Locker:  $             $State: Exp $
00013  *      $Revision: 1.127 $      $Date: 2024/03/01 02:39:38 $
00014  *
00015  ***************************************************************************/
00016 
00017 /* Functions for creating useful volumetric maps based on the 3-D molecular structure */
00018 
00019 // Todo List: 
00020 // - Document!
00021 // - Don't just output to a DX file... give user more control (use plugins)
00022 // - Allow a framerange param, don't just use all available frames (and get rid
00023 // of the VMDApp dependency). Also, VMD needs a general FrameRange object...
00024 
00025 // Note:
00026 // All functions in here loop over x fastest and z slowest and also create
00027 // maps with that order of data. This matches the order used in
00028 // VolumetricData which is ultimately dictated by the way graphics hardware 
00029 // works.
00030 
00031 // XXX VolMapCreate provides its own dx file writer.
00032 // Actualy the maps should be generated in memory only and only dumped
00033 // to files using the molfile_plugin interface. This is currently
00034 // not yet possible but will hopefully be enabled soon.
00035 
00036 #include <math.h>
00037 #include <stdlib.h>
00038 #include <stdio.h>
00039 #include <string.h>
00040 #include <errno.h> // only for write_dx_file()
00041 #include <tcl.h>
00042 
00043 #include "VMDApp.h"
00044 #include "MoleculeList.h"
00045 #include "Molecule.h"
00046 #include "Timestep.h"
00047 #include "Measure.h"
00048 #include "SpatialSearch.h"
00049 #include "VolCPotential.h"
00050 #include "VolumetricData.h"
00051 #include "VolMapCreate.h"
00052 #include "utilities.h"
00053 #include "ResizeArray.h"
00054 #include "Inform.h"
00055 #include "WKFUtils.h"
00056 #include "TclCommands.h"
00057 
00058 #if defined(VMDUSEMSMPOT)
00059 #include "msmpot.h"
00060 #endif
00061 
00062 // Conversion factor between raw units (e^2 / A) and kT/e
00063 #define POT_CONV 560.47254
00064 
00065 #define MIN(X,Y) (((X)<(Y))? (X) : (Y))
00066 #define MAX(X,Y) (((X)>(Y))? (X) : (Y))
00067 
00070 static const float MAX_ENERGY = 150.f; 
00071 
00072 
00073 
00075 
00076 VolMapCreate::VolMapCreate(VMDApp *the_app, AtomSel *the_sel, float resolution) {
00077   volmap = NULL;
00078   app = the_app;
00079   sel = the_sel;
00080   delta = resolution;
00081   computed_frames = 0;
00082   checkpoint_freq = 0;
00083   checkpoint_name = NULL;
00084 
00085   char dataname[1];
00086   strcpy(dataname, ""); // null-terminated empty string
00087   float zerovec[3];
00088   memset(zerovec, 0, 3L*sizeof(float));
00089   volmap = new VolumetricData(dataname, zerovec,
00090                               zerovec, zerovec, zerovec, 0, 0, 0, NULL);
00091   user_minmax = false;
00092 }
00093 
00094 
00095 VolMapCreate::~VolMapCreate() {
00096   if (volmap) delete volmap;
00097   if (checkpoint_name) delete[] checkpoint_name;
00098 }
00099 
00100 
00101 void VolMapCreate::set_minmax (float minx, float miny, float minz, float maxx, float maxy, float maxz) {
00102   user_minmax = true;
00103   min_coord[0] = minx;
00104   min_coord[1] = miny;
00105   min_coord[2] = minz;
00106   max_coord[0] = maxx;
00107   max_coord[1] = maxy;
00108   max_coord[2] = maxz;
00109 }
00110 
00111 
00112 void VolMapCreate::set_checkpoint (int checkpointfreq_tmp, char *checkpointname_tmp) {
00113   if (checkpointfreq_tmp > -1) checkpoint_freq = checkpointfreq_tmp;
00114   if (!checkpointname_tmp) return;
00115   
00116   if (checkpoint_name) delete[] checkpoint_name;
00117   checkpoint_name = new char[strlen(checkpointname_tmp)+1];
00118   strcpy(checkpoint_name, checkpointname_tmp);
00119 }
00120 
00121 
00124 int VolMapCreate::calculate_minmax (float *my_min_coord, float *my_max_coord) {
00125   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00126   int numframes = app->molecule_numframes(sel->molid()); // XXX need a frame selection object
00127   
00128   float frame_min_coord[3], frame_max_coord[3], *coords;
00129   
00130   msgInfo << "volmap: Computing bounding box coordinates" << sendmsg;
00131 
00132   int save_frame = sel->which_frame;
00133   int frame;
00134   for (frame=0; frame<numframes; frame++) {
00135     sel->which_frame=frame;
00136     sel->change(NULL,mol);
00137     coords = sel->coordinates(app->moleculeList);
00138     if (!coords) continue;
00139 
00140     int err = measure_minmax(sel->num_atoms, sel->on, coords, NULL, 
00141                              frame_min_coord, frame_max_coord);
00142     if (err != MEASURE_NOERR) {
00143       sel->which_frame = save_frame;
00144       return err;
00145     }
00146     
00147     int i;
00148     for (i=0; i<3; i++) {
00149       if (!frame || frame_min_coord[i] < my_min_coord[i]) my_min_coord[i] = frame_min_coord[i];
00150       if (!frame || frame_max_coord[i] > my_max_coord[i]) my_max_coord[i] = frame_max_coord[i];
00151     }
00152   }
00153   sel->which_frame = save_frame;
00154   
00155   return 0;
00156 }
00157 
00158 
00160 int VolMapCreate::calculate_max_radius (float &max_rad) {
00161   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00162   if (!mol) return -1;
00163   const float *radius = mol->extraflt.data("radius");
00164   if (!radius) return MEASURE_ERR_NORADII;
00165   
00166   max_rad = 0.f;
00167   int i;
00168   for (i=sel->firstsel; i<=sel->lastsel; i++) 
00169     if (sel->on[i] && radius[i] > max_rad) max_rad = radius[i];
00170   
00171   return 0;
00172 }
00173 
00174 // Combo routines are used to combine the different frame maps together into a
00175 // final entity
00176 
00177 // Initialize the frame combination buffer
00178 void VolMapCreate::combo_begin(CombineType method, void **customptr, void *params) {
00179   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00180   
00181   *customptr = NULL;
00182   memset(volmap->data, 0, sizeof(float)*gridsize);
00183   computed_frames = 0;
00184   
00185   // these combine types need additional storage
00186   if (method == COMBINE_STDEV) {
00187     float *voldata2 = new float[gridsize];
00188     memset(voldata2, 0, gridsize*sizeof(float));
00189     *customptr = (void*) voldata2;
00190   }
00191 }
00192 
00193 // Add a frame to the combination buffer
00194 void VolMapCreate::combo_addframe(CombineType method, float *voldata, void *customptr, float *frame_voldata) {
00195   float *voldata2 = (float*) customptr;
00196   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00197   int n;
00198   
00199   computed_frames++;
00200      
00201   if (computed_frames == 1) { // FIRST FRAME
00202     switch (method) {
00203     case COMBINE_AVG:
00204     case COMBINE_MAX:    
00205     case COMBINE_MIN:    
00206       memcpy(voldata, frame_voldata, gridsize*sizeof(float));
00207       break;
00208     case COMBINE_PMF:
00209       memcpy(voldata, frame_voldata, gridsize*sizeof(float));
00210       break;
00211     case COMBINE_STDEV:    
00212       memcpy(voldata, frame_voldata, gridsize*sizeof(float));
00213       for (n=0; n<gridsize; n++) voldata2[n] = frame_voldata[n]*frame_voldata[n];
00214       break;
00215     }
00216     
00217     return;
00218   }
00219 
00220   // THE FOLLOWING ONLY APPLIES TO OTHER FRAMES THAN FIRST
00221   switch (method) {
00222     case COMBINE_AVG:
00223       for (n=0; n<gridsize; n++) voldata[n] += frame_voldata[n];
00224       break;
00225     case COMBINE_PMF:
00226       for (n=0; n<gridsize; n++) voldata[n] = (float) -log(exp(-voldata[n]) + exp(-frame_voldata[n]));
00227       break;
00228     case COMBINE_MAX:    
00229       for (n=0; n<gridsize; n++) voldata[n] = MAX(voldata[n], frame_voldata[n]);
00230       break;
00231     case COMBINE_MIN:    
00232       for (n=0; n<gridsize; n++) voldata[n] = MIN(voldata[n], frame_voldata[n]);
00233       break;
00234     case COMBINE_STDEV:    
00235       for (n=0; n<gridsize; n++) voldata[n] += frame_voldata[n];
00236       for (n=0; n<gridsize; n++) voldata2[n] += frame_voldata[n]*frame_voldata[n];
00237       break;
00238   }
00239 }
00240 
00241 
00246 void VolMapCreate::combo_export(CombineType method, float *voldata, void *customptr) {
00247   float *voldata2 = (float*) customptr;
00248   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00249   int n;
00250   
00251   switch (method) {
00252   case COMBINE_AVG:
00253     for (n=0; n<gridsize; n++)
00254       volmap->data[n] = voldata[n]/computed_frames;
00255     break;
00256   case COMBINE_PMF:
00257     for (n=0; n<gridsize; n++) {
00258       float val = voldata[n] + logf((float) computed_frames);
00259       if (val > MAX_ENERGY) val = MAX_ENERGY;  // weed out outlying data
00260       volmap->data[n] = val;
00261     }
00262     break;
00263   case COMBINE_MAX:
00264   case COMBINE_MIN:    
00265     memcpy(volmap->data, voldata, gridsize*sizeof(float));    
00266     break;
00267   case COMBINE_STDEV:    
00268     for (n=0; n<gridsize; n++) {
00269       volmap->data[n] = voldata[n]/computed_frames;
00270       volmap->data[n] = sqrtf(voldata2[n]/computed_frames - volmap->data[n]*volmap->data[n]); 
00271     }
00272     break;
00273   }
00274 }
00275 
00276 
00278 void VolMapCreate::combo_end(CombineType method, void *customptr) {
00279   if (method == COMBINE_STDEV) {
00280     float *voldata2 = (float*) customptr;
00281     delete[] voldata2;
00282   }
00283 }
00284 
00285 
00290 int VolMapCreate::compute_all (bool allframes, CombineType method, void *params) {
00291   int err = this->compute_init();
00292   if (err) return err;
00293   
00294   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00295 
00296   // Special case: if only have one frame do it here the fast way
00297   if (!allframes) {
00298     if (volmap->data) delete[] volmap->data;
00299     volmap->data = new float[gridsize];         // final exported voldata
00300   
00301     msgInfo << "volmap: grid size = " << volmap->xsize
00302             <<"x"<< volmap->ysize <<"x"<< volmap->zsize;
00303     char tmp[64];
00304     sprintf(tmp, " (%.1f MB)", sizeof(float)*gridsize/(1024.*1024.));
00305     msgInfo << tmp << sendmsg;
00306 
00307     // only compute the current frame of the given selection
00308     this->compute_frame(sel->which_frame, volmap->data); 
00309     
00310     //err = this->compute_end();
00311     //if (err) return err;
00312     return 0; // no error
00313   }
00314   
00315   
00316   msgInfo << "volmap: grid size    = " << volmap->xsize
00317           <<"x"<< volmap->ysize <<"x"<< volmap->zsize;
00318   char tmp[64];
00319   sprintf(tmp, " (%.1f MB)", sizeof(float)*gridsize/(1024.*1024.));
00320   msgInfo << tmp << sendmsg;
00321 
00322   int numframes = app->molecule_numframes(sel->molid());
00323   msgInfo << "volmap: Computing " << numframes << " frames in total..." << sendmsg;
00324 
00325   if (volmap->data) delete[] volmap->data;
00326   volmap->data = new float[gridsize];         // final exported voldata
00327   float *frame_voldata = new float[gridsize]; // individual frame voldata
00328   float *voldata = new float[gridsize];       // combo cache voldata
00329   
00330   void *customptr = NULL;
00331   combo_begin(method, &customptr, params);
00332   wkf_timerhandle timer = wkf_timer_create();
00333 
00334   // Combine frame_voldata into voldata, one frame at a time, starting with 1st frame
00335   int frame;
00336   for (frame=0; frame<numframes; frame++) { 
00337     // XXX to-do, only take frames from a frame selection
00338     msgInfo << "volmap: frame " << frame << "/" << numframes;
00339 #ifdef TIMING
00340     msgInfo << sendmsg;
00341 #else
00342     msgInfo << "   ";
00343 #endif
00344 
00345     wkf_timer_start(timer);
00346 
00347     this->compute_frame(frame, frame_voldata);
00348     wkf_timer_stop(timer);
00349     msgInfo << "Total time = " << wkf_timer_time(timer) << " s" << sendmsg;
00350 
00351     combo_addframe(method, voldata, customptr, frame_voldata);
00352     if (checkpoint_freq && computed_frames && !(computed_frames%checkpoint_freq)) {
00353       combo_export(method, voldata, customptr);
00354       const char *filename;
00355       if (checkpoint_name) filename=checkpoint_name;
00356       else filename = "checkpoint.dx";
00357       write_map(filename);
00358     }
00359   }
00360     
00361   wkf_timer_destroy(timer);
00362 
00363   delete[] frame_voldata;
00364   
00365   // All frames have been combined, perform finishing steps here
00366   combo_export(method, voldata, customptr);
00367   combo_end (method, customptr);
00368   delete[] voldata;
00369        
00370   return 0; // no error
00371 }
00372 
00373 
00374 
00375 // compute_init() sets up the grid coordinate system and dimensions
00376 // If the user did not specify the grid's minmax boundary, it is
00377 // defaulted to the trajectory's minmax coordinates, to which "padding"
00378 // is added in all dimensions. 
00379 int VolMapCreate::compute_init (float padding) {
00380   if (!sel) return MEASURE_ERR_NOSEL;
00381   if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00382   
00383   int err, i;
00384   
00385   if (!volmap) return -1;
00386   
00387   if (user_minmax)
00388     padding = 0.;  // don't want to pad user's defaults
00389   else {
00390     // The minmax coordinates over all frames
00391     err = calculate_minmax(min_coord, max_coord);
00392     if (err) return err;
00393   }
00394   
00395   // Depending on the volmap type we are computing we add some padding
00396   // to the dimensions of the grid. This function is called by the 
00397   // compute_init() methods of the VolMapCreate<type> subclasses. 
00398   // The caller provides a reasonable map type specific padding value.
00399   // The padding can for example be the radius of the largest atom or
00400   // an interaction distance cutoff.
00401   // After padding we align the grid with integer coordinates.
00402   for (i=0; i<3; i++) {
00403     //adjust padding and ensure that different maps are properly aligned
00404     min_coord[i] = (float) floor((min_coord[i] - padding)/delta)*delta;    
00405     max_coord[i] = (float)  ceil((max_coord[i] + padding)/delta)*delta;
00406   }
00407   
00408   volmap->xsize = MAX((int)((max_coord[0] - min_coord[0])/delta), 0);
00409   volmap->ysize = MAX((int)((max_coord[1] - min_coord[1])/delta), 0);
00410   volmap->zsize = MAX((int)((max_coord[2] - min_coord[2])/delta), 0);
00411 
00412   char tmpstr[256] = { 0 };
00413   sprintf(tmpstr, "{%g %g %g} {%g %g %g}\n", min_coord[0], min_coord[1], min_coord[2], max_coord[0], max_coord[1], max_coord[2]);
00414   msgInfo << "volmap: grid minmax = " << tmpstr << sendmsg; 
00415   
00416   float cellx[3], celly[3], cellz[3];
00417   cellx[0] = delta;
00418   cellx[1] = 0.f;
00419   cellx[2] = 0.f;
00420   celly[0] = 0.f;
00421   celly[1] = delta;
00422   celly[2] = 0.f;
00423   cellz[0] = 0.f;
00424   cellz[1] = 0.f;
00425   cellz[2] = delta;
00426 
00427   // define origin by shifting to middle of each cell,
00428   // compute_frame() needs to take this into account
00429   for (i=0; i<3; i++) 
00430     volmap->origin[i] = min_coord[i] + \
00431                  0.5f*(cellx[i] + celly[i] + cellz[i]);
00432   int d;
00433   for (d=0; d<3; d++) {
00434     volmap->xaxis[d] = cellx[d]*(volmap->xsize-1);
00435     volmap->yaxis[d] = celly[d]*(volmap->ysize-1);
00436     volmap->zaxis[d] = cellz[d]*(volmap->zsize-1);
00437   }
00438   
00439   if ((volmap->xsize*volmap->ysize*volmap->zsize) == 0)
00440     return MEASURE_ERR_ZEROGRIDSIZE;
00441 
00442   return 0; // no error
00443 }
00444 
00445 
00446 
00448 
00453 
00454 int VolMapCreateMask::compute_init() {
00455   char tmpstr[255] = { 0 };
00456   sprintf(tmpstr, "mask (%s.200)", sel->cmdStr);
00457   volmap->set_name(tmpstr);
00458     
00459   return VolMapCreate::compute_init(atomradius+0.5f);
00460 }
00461 
00462 
00463 int VolMapCreateMask::compute_frame (int frame, float *voldata) {
00464   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00465   if (!mol) return -1;
00466   
00467   int i;
00468   int GRIDSIZEX = volmap->xsize;
00469   int GRIDSIZEY = volmap->ysize;
00470   int GRIDSIZEZ = volmap->zsize;
00471   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00472   
00473   //create volumetric mask grid
00474   memset(voldata, 0, gridsize*sizeof(float));
00475   int save_frame = sel->which_frame;
00476   sel->which_frame=frame;
00477   sel->change(NULL,mol);
00478   
00479   const float *coords = sel->coordinates(app->moleculeList);
00480   if (!coords) {
00481     sel->which_frame = save_frame;
00482     return -1;
00483   }
00484   
00485   float cellx[3], celly[3], cellz[3];
00486   volmap->cell_axes(cellx, celly, cellz);
00487 
00488   float min_coords[3];
00489   for (i=0; i<3; i++)
00490     min_coords[i] = float(volmap->origin[i] - 0.5f*(cellx[i] + celly[i] + cellz[i]));
00491   
00492   // paint atomic spheres on map
00493   int gx, gy, gz;
00494   for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00495     if (!sel->on[i]) continue; //atom is not selected
00496 
00497     gx = (int) ((coords[3L*i  ] - min_coords[0])/delta);
00498     gy = (int) ((coords[3L*i+1] - min_coords[1])/delta);
00499     gz = (int) ((coords[3L*i+2] - min_coords[2])/delta);
00500       
00501     int steps = (int)(atomradius/delta)+1;
00502     int iz, iy, ix;
00503     for (iz=MAX(gz-steps,0); iz<=MIN(gz+steps,GRIDSIZEZ-1); iz++)
00504     for (iy=MAX(gy-steps,0); iy<=MIN(gy+steps,GRIDSIZEY-1); iy++)
00505     for (ix=MAX(gx-steps,0); ix<=MIN(gx+steps,GRIDSIZEX-1); ix++) {
00506       int n = ix + iy*GRIDSIZEX + iz*GRIDSIZEY*GRIDSIZEX;
00507       float dx = float(coords[3L*i  ] - volmap->origin[0] - ix*delta);
00508       float dy = float(coords[3L*i+1] - volmap->origin[1] - iy*delta);
00509       float dz = float(coords[3L*i+2] - volmap->origin[2] - iz*delta);
00510       float dist2 = dx*dx+dy*dy+dz*dz;
00511       if (dist2 <= atomradius*atomradius) voldata[n] = 1.f;
00512     }
00513   }
00514   
00515   sel->which_frame = save_frame;
00516   
00517   return 0;
00518 }  
00519 
00520 
00521 
00523 
00531 
00532 int VolMapCreateDensity::compute_init () {
00533   char tmpstr[255] = { 0 };
00534   sprintf(tmpstr, "density (%.200s) [A^-3]", sel->cmdStr);
00535   volmap->set_name(tmpstr);
00536   
00537   float max_rad=0.f;
00538   calculate_max_radius(max_rad);
00539     
00540   return VolMapCreate::compute_init(MAX(3.f*radius_scale*max_rad,10.f));
00541 }
00542 
00543 
00544 int VolMapCreateDensity::compute_frame (int frame, float *voldata) {
00545   if (!weight) return MEASURE_ERR_NOWEIGHT;
00546     
00547   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00548   if (!mol) return -1;
00549     int i;
00550     
00551   const float *radius = mol->extraflt.data("radius");
00552   if (!radius) return MEASURE_ERR_NORADII;
00553   
00554   int GRIDSIZEX = volmap->xsize;
00555   int GRIDSIZEY = volmap->ysize;
00556   int GRIDSIZEZ = volmap->zsize;
00557   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00558 
00559   //create volumetric density grid
00560   memset(voldata, 0, gridsize*sizeof(float));
00561   int save_frame = sel->which_frame;
00562   sel->which_frame = frame;
00563   sel->change(NULL,mol);
00564   const float *coords = sel->coordinates(app->moleculeList);
00565   if (!coords) {
00566     sel->which_frame = save_frame;
00567     return -1;
00568   }
00569 
00570   if (weight_mutable) {
00571     if (weight_string) {
00572       get_weights_from_attribute(app, sel, weight_string, weight);
00573     } else {
00574       atomsel_default_weights(sel, weight);
00575     }
00576   }
00577   
00578   float cellx[3], celly[3], cellz[3];
00579   volmap->cell_axes(cellx, celly, cellz);
00580 
00581   float min_coords[3];
00582   for (i=0; i<3; i++) 
00583     min_coords[i] = float(volmap->origin[i] - 0.5f*(cellx[i] + celly[i] + cellz[i]));
00584   
00585   int gx, gy, gz;   // grid coord indices
00586   for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00587     if (!sel->on[i]) continue; //atom is not selected
00588 
00589     gx = (int) ((coords[3L*i  ] - min_coords[0])/delta);
00590     gy = (int) ((coords[3L*i+1] - min_coords[1])/delta);
00591     gz = (int) ((coords[3L*i+2] - min_coords[2])/delta);
00592       
00593     float scaled_radius = 0.5f*radius_scale*radius[i];
00594     float exp_factor = 1.0f/(2.0f*scaled_radius*scaled_radius);
00595     float norm = weight[i]/(sqrtf((float) (8.0f*VMD_PI*VMD_PI*VMD_PI))*scaled_radius*scaled_radius*scaled_radius);
00596                   
00597     int steps = (int)(4.1f*scaled_radius/delta);
00598     int iz, iy, ix;
00599     for (iz=MAX(gz-steps,0); iz<=MIN(gz+steps,GRIDSIZEZ-1); iz++)
00600     for (iy=MAX(gy-steps,0); iy<=MIN(gy+steps,GRIDSIZEY-1); iy++)
00601     for (ix=MAX(gx-steps,0); ix<=MIN(gx+steps,GRIDSIZEX-1); ix++) {
00602       int n = ix + iy*GRIDSIZEX + iz*GRIDSIZEY*GRIDSIZEX;
00603       float dx = float(coords[3L*i  ] - volmap->origin[0] - ix*delta);
00604       float dy = float(coords[3L*i+1] - volmap->origin[1] - iy*delta);
00605       float dz = float(coords[3L*i+2] - volmap->origin[2] - iz*delta);
00606       float dist2 = dx*dx+dy*dy+dz*dz;
00607       voldata[n] += norm * expf(-dist2*exp_factor);
00608       // Uncomment the following line for a much faster implementation
00609       // This is useful is all you care about is the smooth visual appearance
00610       // voldata[n] += exp_factor/(dist2+10.f);
00611     }
00612   }
00613 
00614   sel->which_frame = save_frame;
00615     
00616   return 0;
00617 }  
00618 
00619 
00620 
00621 
00623   
00627   
00628 int VolMapCreateInterp::compute_init () {
00629   char tmpstr[255] = { 0 };
00630   sprintf(tmpstr, "interp (%.200s) [A^-3]", sel->cmdStr);
00631   volmap->set_name(tmpstr);
00632   
00633   return VolMapCreate::compute_init(delta+0.5f);
00634 }
00635 
00636 
00637 int VolMapCreateInterp::compute_frame (int frame, float *voldata) {
00638   if (!weight) return MEASURE_ERR_NOWEIGHT;
00639     
00640   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00641   if (!mol) return -1;
00642     int i;
00643     
00644   int GRIDSIZEX = volmap->xsize;
00645   int GRIDSIZEY = volmap->ysize;
00646   int GRIDSIZEXY = GRIDSIZEX * GRIDSIZEY;
00647   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00648 
00649   // create volumetric density grid
00650   memset(voldata, 0, gridsize*sizeof(float));
00651   int save_frame = sel->which_frame;
00652   sel->which_frame = frame;
00653   sel->change(NULL,mol);
00654   const float *coords = sel->coordinates(app->moleculeList);
00655   if (!coords) {
00656     sel->which_frame = save_frame;
00657     return -1;
00658   }
00659 
00660   if (weight_mutable) {
00661     if (weight_string) {
00662       get_weights_from_attribute(app, sel, weight_string, weight);
00663     } else {
00664       atomsel_default_weights(sel, weight);
00665     }
00666   }
00667   
00668   int gx, gy, gz;      // grid coord indices
00669   float fgx, fgy, fgz; // fractional grid coord indices
00670   float dx, dy, dz;    // to measure distances
00671   for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00672     if (!sel->on[i]) continue; //atom is not selected
00673 
00674     // Find position of the atom within the map ("fractional indices")
00675     fgx = float(coords[3L*i  ] - volmap->origin[0])/delta;
00676     fgy = float(coords[3L*i+1] - volmap->origin[1])/delta;
00677     fgz = float(coords[3L*i+2] - volmap->origin[2])/delta;
00678 
00679     // Find nearest voxel with lowest indices
00680     gx = (int) fgx;
00681     gy = (int) fgy;
00682     gz = (int) fgz;
00683 
00684     // Calculate distance between atom and each voxel
00685     dx = fgx - gx;
00686     dy = fgy - gy;
00687     dz = fgz - gz;
00688 
00689     // Perform trilinear interpolation
00690 
00691     voldata[ gx + gy*GRIDSIZEX + gz*GRIDSIZEXY ] \
00692       += (1.0f - dx) * (1.0f - dy) * (1.0f - dz) * weight[i];
00693 
00694     voldata[ (gx+1) + (gy+1)*GRIDSIZEX + (gz+1)*GRIDSIZEXY ] \
00695       += dx * dy * dz * weight[i];
00696 
00697     voldata[ (gx+1) + (gy+1)*GRIDSIZEX + gz*GRIDSIZEXY ] \
00698       += dx * dy * (1.0f - dz) * weight[i];
00699 
00700     voldata[ gx + gy*GRIDSIZEX + (gz+1)*GRIDSIZEXY ] \
00701       += (1.0f - dx) * (1.0f - dy) * dz * weight[i];
00702 
00703     voldata[ (gx+1) + gy*GRIDSIZEX + gz*GRIDSIZEXY ] \
00704       += dx * (1.0f - dy) * (1.0f - dz) * weight[i];
00705 
00706     voldata[ gx + (gy+1)*GRIDSIZEX + (gz+1)*GRIDSIZEXY ] \
00707       += (1.0f - dx) * dy * dz * weight[i];
00708 
00709     voldata[ gx + (gy+1)*GRIDSIZEX + gz*GRIDSIZEXY ] \
00710       += (1.0f - dx) * dy * (1.0f - dz) * weight[i];
00711 
00712     voldata[ (gx+1) + gy*GRIDSIZEX + (gz+1)*GRIDSIZEXY ] \
00713       += dx * (1.0f - dy) * dz * weight[i];
00714   }
00715 
00716   sel->which_frame = save_frame;
00717       
00718   return 0;
00719 }  
00720 
00721 
00722 
00723 
00724   
00726 
00732 
00733 int VolMapCreateOccupancy::compute_init () {
00734   char tmpstr[255] = { 0 };
00735   sprintf(tmpstr, "occupancy (%.200s)", sel->cmdStr);
00736   volmap->set_name(tmpstr);
00737   
00738   float max_rad=0.f;  
00739   if (use_points)
00740     max_rad = 1.f;
00741   else
00742     calculate_max_radius(max_rad);
00743   
00744   return VolMapCreate::compute_init(max_rad);
00745 }
00746 
00747 
00748 int VolMapCreateOccupancy::compute_frame(int frame, float *voldata) { 
00749   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00750   if (!mol) return -1;
00751   
00752   int GRIDSIZEX = volmap->xsize;
00753   int GRIDSIZEY = volmap->ysize;
00754   int GRIDSIZEZ = volmap->zsize;
00755   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00756   int i;
00757   
00758   //create volumetric density grid
00759   memset(voldata, 0, gridsize*sizeof(float));
00760   int save_frame = sel->which_frame;
00761   sel->which_frame=frame;
00762   sel->change(NULL,mol);
00763   const float *coords = sel->coordinates(app->moleculeList);
00764 
00765   if (!coords) {
00766     sel->which_frame = save_frame;
00767     return -1;
00768   }
00769 
00770   float cellx[3], celly[3], cellz[3];
00771   volmap->cell_axes(cellx, celly, cellz);
00772 
00773   float min_coords[3];
00774   for (i=0; i<3; i++) 
00775     min_coords[i] = float(volmap->origin[i] - 0.5f*(cellx[i] + celly[i] + cellz[i]));
00776 
00777   int gx, gy, gz;
00778   
00779   if (use_points) { // draw single points
00780     for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00781       if (!sel->on[i]) continue; //atom is not selected
00782 
00783       gx = (int) ((coords[3L*i  ] - min_coords[0])/delta);
00784       if (gx<0 || gx>=GRIDSIZEX) continue;
00785       gy = (int) ((coords[3L*i+1] - min_coords[1])/delta);
00786       if (gy<0 || gy>=GRIDSIZEY) continue;
00787       gz = (int) ((coords[3L*i+2] - min_coords[2])/delta);
00788       if (gz<0 || gz>=GRIDSIZEZ) continue;
00789 
00790       voldata[gx+GRIDSIZEX*gy+GRIDSIZEX*GRIDSIZEY*gz] = 1.f; 
00791     }
00792   }
00793   else { // paint atomic spheres on map
00794     const float *radius = mol->extraflt.data("radius");
00795     if (!radius) {
00796       sel->which_frame = save_frame;
00797       return MEASURE_ERR_NORADII;
00798     }
00799   
00800     for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00801       if (!sel->on[i]) continue; //atom is not selected
00802 
00803       gx = (int) ((coords[3L*i  ] - min_coords[0])/delta);
00804       gy = (int) ((coords[3L*i+1] - min_coords[1])/delta);
00805       gz = (int) ((coords[3L*i+2] - min_coords[2])/delta);
00806       
00807       int steps = (int)(radius[i]/delta)+1;
00808       int iz, iy, ix;
00809       for (iz=MAX(gz-steps,0); iz<=MIN(gz+steps,GRIDSIZEZ-1); iz++)
00810       for (iy=MAX(gy-steps,0); iy<=MIN(gy+steps,GRIDSIZEY-1); iy++)
00811       for (ix=MAX(gx-steps,0); ix<=MIN(gx+steps,GRIDSIZEX-1); ix++) {
00812         int n = ix + iy*GRIDSIZEX + iz*GRIDSIZEY*GRIDSIZEX;
00813         float dx = float(coords[3L*i  ] - volmap->origin[0] - ix*delta);
00814         float dy = float(coords[3L*i+1] - volmap->origin[1] - iy*delta);
00815         float dz = float(coords[3L*i+2] - volmap->origin[2] - iz*delta);
00816         float dist2 = dx*dx+dy*dy+dz*dz;
00817         if (dist2 <= radius[i]*radius[i]) voldata[n] = 1.f;
00818       }
00819     }
00820   }
00821   
00822   sel->which_frame = save_frame;
00823     
00824   return 0;
00825 }
00826 
00827 
00828 
00830 
00836 
00837 int VolMapCreateDistance::compute_init () {
00838   char tmpstr[255] = { 0 };
00839   sprintf(tmpstr, "distance (%.200s) [A]", sel->cmdStr);
00840   volmap->set_name(tmpstr);
00841   
00842   float max_rad=0.f;
00843   calculate_max_radius(max_rad);
00844   
00845   return VolMapCreate::compute_init(max_rad+max_dist);
00846 }
00847  
00848 
00851 int VolMapCreateDistance::compute_frame(int frame, float *voldata) { 
00852   int i, n;  
00853   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00854   if (!mol) return -1;
00855   const float *radius = mol->extraflt.data("radius");
00856   if (!radius) return MEASURE_ERR_NORADII;
00857   
00858   int GRIDSIZEX = volmap->xsize;
00859   int GRIDSIZEY = volmap->ysize;
00860   int gridsize = volmap->xsize*volmap->ysize*volmap->zsize;
00861 
00862   float dx, dy, dz;
00863   float dist, mindist, r;
00864   
00865   float max_rad=0.f;
00866   calculate_max_radius(max_rad);
00867   
00868   // 1. Create a fake "molecule" containing all of the grid points
00869   //    this is quite memory intensive but _MUCH_ faster doing it point-by point!
00870   
00871   float *gridpos = new float[3L*gridsize]; 
00872   int *gridon = new int[gridsize]; 
00873   for (n=0; n<gridsize; n++) {
00874     gridpos[3L*n  ] = float((n%GRIDSIZEX)*delta + volmap->origin[0]); //position of grid cell's center
00875     gridpos[3L*n+1] = float(((n/GRIDSIZEX)%GRIDSIZEY)*delta + volmap->origin[1]);
00876     gridpos[3L*n+2] = float((n/(GRIDSIZEX*GRIDSIZEY))*delta + volmap->origin[2]); 
00877     gridon[n] = 1;
00878   }
00879 
00880   GridSearchPair *pairlist, *p;
00881 
00882   int save_frame = sel->which_frame;
00883   sel->which_frame = frame;
00884   sel->change(NULL,mol);
00885   const float *coords = sel->coordinates(app->moleculeList);
00886   if (!coords) {
00887     sel->which_frame = save_frame;
00888     return -1;
00889   }
00890   
00891   // initialize all grid points to be the maximal allowed distance = cutoff
00892   for (n=0; n<gridsize; n++) voldata[n] = max_dist;
00893   
00894   // 2. Create a list of all bonds between the grid and the real molecule
00895   //    which are within the user-set cutoff distance 
00896   //    (the use of a cutoff is purely to speed this up tremendously)
00897   
00898   pairlist = vmd_gridsearch3(gridpos, gridsize, gridon, coords,
00899                              sel->num_atoms, sel->on, max_dist+max_rad, true, -1);
00900   for (p=pairlist; p; p=p->next) {
00901     n = p->ind1;
00902     // if a grid point is already known to be inside an atom, skip it and save some time
00903     if ((mindist = voldata[n]) == 0.f) continue;
00904     i = p->ind2;
00905     r = radius[i];
00906     dx = gridpos[3L*n  ] - coords[3L*i];
00907     dy = gridpos[3L*n+1] - coords[3L*i+1];
00908     dz = gridpos[3L*n+2] - coords[3L*i+2];
00909     
00910     // 3. At each grid point, store the _smallest_ recorded distance
00911     //    to a nearby atomic surface
00912       
00913     dist = sqrtf(dx*dx+dy*dy+dz*dz) - r;
00914     if (dist < 0) dist = 0.f;
00915     if (dist < mindist) voldata[n] = dist;
00916   }
00917   
00918   // delete pairlist
00919   for (p=pairlist; p;) {
00920     GridSearchPair *tmp = p;
00921     p = p->next;
00922     free(tmp);
00923   }  
00924 
00925   delete [] gridpos; 
00926   delete [] gridon; 
00927 
00928   sel->which_frame = save_frame;
00929 
00930   return MEASURE_NOERR; 
00931 }
00932 
00933 
00934 
00935 
00937   
00938 int VolMapCreateCoulombPotential::compute_init () {
00939   char tmpstr[255] = { 0 };
00940   sprintf(tmpstr, "Potential (kT/e at 298.15K) (%.200s)", sel->cmdStr);
00941   volmap->set_name(tmpstr);
00942   
00943   float max_rad;
00944   calculate_max_radius(max_rad);
00945     
00946   // init object, no extra padding by default  
00947   return VolMapCreate::compute_init(0.f);
00948 }
00949 
00950 
00951 int VolMapCreateCoulombPotential::compute_frame(int frame, float *voldata) {
00952   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
00953   if (!mol) return -1;
00954     int i;
00955     
00956   const float *charge = mol->extraflt.data("charge");
00957   if (!charge) return MEASURE_ERR_NORADII; // XXX fix this later
00958 
00959   int gridsize=volmap->xsize*volmap->ysize*volmap->zsize;
00960 
00961   // create volumetric density grid
00962   memset(voldata, 0, gridsize*sizeof(float));
00963   int save_frame = sel->which_frame;
00964   sel->which_frame=frame;
00965   sel->change(NULL,mol);
00966   const float *coords = sel->coordinates(app->moleculeList);
00967   if (!coords) {
00968     sel->which_frame = save_frame;
00969     return -1;
00970   }
00971  
00972   float cellx[3], celly[3], cellz[3];
00973   volmap->cell_axes(cellx, celly, cellz);
00974 
00975   float min_coords[3];
00976   for (i=0; i<3; i++) 
00977     min_coords[i] = float(volmap->origin[i] - 0.5f*(cellx[i] + celly[i] + cellz[i]));
00978 
00979   // copy selected atom coordinates and charges to a contiguous memory
00980   // buffer and translate them to the starting corner of the map.
00981   float *xyzq = (float *) malloc(sel->selected * 4L * sizeof(float));
00982   float *curatom = xyzq;
00983   for (i=sel->firstsel; i<=sel->lastsel; i++) { 
00984     if (sel->on[i]) {
00985       curatom[0] = coords[3L*i  ] - min_coords[0];
00986       curatom[1] = coords[3L*i+1] - min_coords[1];
00987       curatom[2] = coords[3L*i+2] - min_coords[2];
00988       curatom[3] = charge[i] * float(POT_CONV);
00989       curatom += 4;
00990     }
00991   }
00992 
00993   vol_cpotential(sel->selected, xyzq, voldata, 
00994                  volmap->zsize, volmap->ysize, volmap->xsize, delta);
00995 
00996   free(xyzq);
00997 
00998   sel->which_frame = save_frame;
00999  
01000   return 0;
01001 }  
01002 
01004 
01005 #if defined(VMDUSEMSMPOT)
01006 int VolMapCreateCoulombPotentialMSM::compute_init () {
01007   char tmpstr[255] = { 0 };
01008   sprintf(tmpstr, "Potential (kT/e at 298.15K) (%.200s)", sel->cmdStr);
01009   volmap->set_name(tmpstr);
01010   
01011   float max_rad;
01012   calculate_max_radius(max_rad);
01013   
01014   // init object, no extra padding by default
01015   // Note: padding would create serious problems for the periodic case 
01016   return VolMapCreate::compute_init(0.f);
01017 }
01018 
01019 
01020 int VolMapCreateCoulombPotentialMSM::compute_frame(int frame, float *voldata) {
01021   DrawMolecule *mol = app->moleculeList->mol_from_id(sel->molid());
01022   if (!mol) return -1;
01023     int i;
01024 
01025   int usepbc = 0;
01026     
01027   const float *charge = mol->extraflt.data("charge");
01028   if (!charge) return MEASURE_ERR_NORADII; // XXX fix this later
01029 
01030   int gridsize=volmap->xsize*volmap->ysize*volmap->zsize;
01031 
01032   // create volumetric density grid
01033   memset(voldata, 0, gridsize*sizeof(float));
01034   int save_frame = sel->which_frame;
01035   sel->which_frame=frame;
01036   sel->change(NULL,mol);
01037   const float *coords = sel->coordinates(app->moleculeList);
01038   const Timestep *ts = sel->timestep(app->moleculeList); 
01039   if (!coords) {
01040     sel->which_frame = save_frame;
01041     return -1;
01042   }
01043   if (!ts) {
01044     return -1;
01045   }
01046  
01047   float cellx[3], celly[3], cellz[3];
01048   volmap->cell_axes(cellx, celly, cellz);
01049 
01050   float min_coords[3];
01051   for (i=0; i<3; i++) 
01052     min_coords[i] = float(volmap->origin[i] - 0.5f*(cellx[i] + celly[i] + cellz[i]));
01053 
01054   // copy selected atom coordinates and charges to a contiguous memory
01055   // buffer and translate them to the starting corner of the map.
01056   float *xyzq = (float *) malloc(sel->selected * 4L * sizeof(float));
01057   float *curatom = xyzq;
01058   for (i=sel->firstsel; i<=sel->lastsel; i++) { 
01059     if (sel->on[i]) {
01060       curatom[0] = coords[3L*i  ] - min_coords[0];
01061       curatom[1] = coords[3L*i+1] - min_coords[1];
01062       curatom[2] = coords[3L*i+2] - min_coords[2];
01063       curatom[3] = charge[i] * float(POT_CONV);
01064       curatom += 4;
01065     }
01066   }
01067 
01068   Msmpot *msm = Msmpot_create(); // create a multilevel summation object
01069 #if 0
01070   int msmrc;
01071   int mx = volmap->xsize;  /* map lattice dimensions */
01072   int my = volmap->ysize;
01073   int mz = volmap->zsize;
01074   float lx = delta*mx;     /* map lattice lengths */
01075   float ly = delta*my;
01076   float lz = delta*mz;
01077   float x0=0, y0=0, z0=0;  /* map origin */
01078   float vx=0, vy=0, vz=0;  /* periodic domain lengths (0 for nonperiodic) */
01079 
01080   if (getenv("MSMPOT_NOCUDA")) {
01081     /* turn off use of CUDA (with 0 in last parameter) */
01082     Msmpot_configure(msm, 0, 0, 0, 0, 0, 0, 0, 0, 0);
01083   }
01084 
01085   if (getenv("MSMPOT_PBCON")) {
01086     vx = lx, vy = ly, vz = lz;  /* use periodic boundary conditions */
01087   }
01088 
01089   if (getenv("MSMPOT_EXACT")) { 
01090     msmrc = Msmpot_compute_exact(msm, voldata, 
01091         mx, my, mz, lx, ly, lz, x0, y0, z0, vx, vy, vz,
01092         xyzq, sel->selected);
01093   }
01094   else {
01095     msmrc = Msmpot_compute(msm, voldata, 
01096         mx, my, mz, lx, ly, lz, x0, y0, z0, vx, vy, vz,
01097         xyzq, sel->selected);
01098   }
01099   if (msmrc != MSMPOT_SUCCESS) {
01100     printf("MSM return code: %d\n", msmrc);
01101     printf("MSM error string: '%s'\n", Msmpot_error_string(msmrc));
01102   } 
01103 #endif
01104 #if 1
01105   // New MSM API: both non-periodic and periodic MSM calcs
01106   int msmrc;
01107 
01108   // XXX hack for ease of initial testing
01109   if (getenv("VMDMSMUSEPBC"))
01110     usepbc = 1;
01111 
01112   if (usepbc) {
01113     // get periodic cell information for current frame
01114     float a, b, c, alpha, beta, gamma;
01115     a = ts->a_length;
01116     b = ts->b_length;
01117     c = ts->c_length;
01118     alpha = ts->alpha;
01119     beta = ts->beta;
01120     gamma = ts->gamma;
01121 
01122     // check validity of PBC cell side lengths
01123     if (fabsf(a*b*c) < 0.0001) {
01124       msgErr << "volmap coulombmsm: unit cell volume is zero." << sendmsg;
01125       return -1;
01126     }
01127 
01128     // check PBC unit cell shape to select proper low level algorithm.
01129     if ((alpha != 90.0) || (beta != 90.0) || (gamma != 90.0)) {
01130       msgErr << "volmap coulombmsm: unit cell is non-orthogonal." << sendmsg;
01131       return -1;
01132     }
01133 
01134 #ifdef MSMPOT_COMPUTE_EXACT
01135   if (getenv("MSMPOT_EXACT")) {
01136     // XXX the current PBC code will currently use the initially specified 
01137     //     map dimensions and coordinates for all frames in a time-averaged
01138     //     calculation.  In the case that one would prefer the map to cover
01139     //     a fixed region of the unit cell in reciprocal space, we will need
01140     //     to change this code to update the effective map geometry on-the-fly.
01141     msgInfo << "Running EXACT periodic MSM calculation..." << sendmsg;
01142     msmrc = Msmpot_compute_exact(msm, voldata, 
01143                            volmap->xsize, volmap->ysize, volmap->zsize,
01144                            volmap->xsize * delta, 
01145                            volmap->ysize * delta, 
01146                            volmap->zsize * delta, 
01147                            0, 0, 0, // origin, already translated to min 
01148                            a, b, c, // pbc cell length 0 == nonperiodic calc
01149                            xyzq, sel->selected);
01150   } else {
01151 #endif
01152     // XXX the current PBC code will currently use the initially specified 
01153     //     map dimensions and coordinates for all frames in a time-averaged
01154     //     calculation.  In the case that one would prefer the map to cover
01155     //     a fixed region of the unit cell in reciprocal space, we will need
01156     //     to change this code to update the effective map geometry on-the-fly.
01157     msgInfo << "Running periodic MSM calculation..." << sendmsg;
01158     msmrc = Msmpot_compute(msm, voldata, 
01159                            volmap->xsize, volmap->ysize, volmap->zsize,
01160                            volmap->xsize * delta, 
01161                            volmap->ysize * delta, 
01162                            volmap->zsize * delta, 
01163                            0, 0, 0, // origin, already translated to min 
01164                            a, b, c, // pbc cell length 0 == nonperiodic calc
01165                            xyzq, sel->selected);
01166 #ifdef MSMPOT_COMPUTE_EXACT
01167   }
01168 #endif
01169 
01170   } else {
01171 
01172 #ifdef MSMPOT_COMPUTE_EXACT
01173   if (getenv("MSMPOT_EXACT")) {
01174     msgInfo << "Running EXACT non-periodic MSM calculation..." << sendmsg;
01175     msmrc = Msmpot_compute_exact(msm, voldata, 
01176                            volmap->xsize, volmap->ysize, volmap->zsize,
01177                            volmap->xsize * delta, 
01178                            volmap->ysize * delta, 
01179                            volmap->zsize * delta, 
01180                            0, 0, 0, // origin, already translated to min 
01181                            0, 0, 0, // pbc cell length 0 == nonperiodic calc
01182                            xyzq, sel->selected);
01183   } else {
01184 #endif
01185     msgInfo << "Running non-periodic MSM calculation..." << sendmsg;
01186     msmrc = Msmpot_compute(msm, voldata, 
01187                            volmap->xsize, volmap->ysize, volmap->zsize,
01188                            volmap->xsize * delta, 
01189                            volmap->ysize * delta, 
01190                            volmap->zsize * delta, 
01191                            0, 0, 0, // origin, already translated to min 
01192                            0, 0, 0, // pbc cell length 0 == nonperiodic calc
01193                            xyzq, sel->selected);
01194 #ifdef MSMPOT_COMPUTE_EXACT
01195   }
01196 #endif
01197 
01198   }
01199 
01200   if (msmrc != MSMPOT_SUCCESS) {
01201     printf("MSM return code: %d\n", msmrc);
01202     printf("MSM error string: '%s'\n", Msmpot_error_string(msmrc));
01203   } 
01204 #else
01205   // old MSM API: non-periodic MSM calcs only
01206   int msmrc = Msmpot_compute(msm, voldata, 
01207                              volmap->xsize, volmap->ysize, volmap->zsize,
01208                              delta, delta, delta, 
01209                              0, 0, 0,
01210                              0, 0, 0, // origin, already translated to min 
01211                              xyzq, sel->selected);
01212   if (msmrc != MSMPOT_ERROR_NONE) {
01213     printf("MSM return code: %d\n", msmrc);
01214     printf("MSM error string: '%s'\n", Msmpot_error_string(msmrc));
01215   } 
01216 #endif
01217   Msmpot_destroy(msm);
01218 
01219   free(xyzq);
01220 
01221   sel->which_frame = save_frame;
01222  
01223   return 0;
01224 }  
01225 
01226 #endif
01227 
01228 
01229 
01230 
01231 
01232 // Write the map as a DX file.
01233 // This is the default base class function which can be
01234 // overridden by the derived classes. 
01235 // E.g. VolMapCreateFastEnergy defines its own write_map().
01236 void VolMapCreate::write_map(const char *filename) {
01237   volmap_write_dx_file(volmap, filename);
01238 }
01239 
01240 
01241 int volmap_write_dx_file (VolumetricData *volmap, const char *filename) {
01242   if (!volmap->data) return -1; // XXX is this a good random error code?
01243   int i;
01244   int xsize = volmap->xsize;
01245   int ysize = volmap->ysize;
01246   int zsize = volmap->zsize;
01247   int gridsize = xsize*ysize*zsize;
01248 
01249   float cellx[3], celly[3], cellz[3];
01250   volmap->cell_axes(cellx, celly, cellz);
01251 
01252   
01253   msgInfo << "volmap: writing file \"" << filename << "\"." << sendmsg;
01254   
01255   FILE *fout = fopen(filename, "w");
01256   if (!fout) {
01257     msgErr << "volmap: Cannot open file \"" << filename
01258            << "\" for writing." << sendmsg;
01259     return errno;
01260   };
01261     
01262   fprintf(fout, "# Data calculated by the VMD volmap function\n");
01263 
01264   // Since the data origin and the grid origin are aligned we have
01265   // grid centered data, even though we were thinking in terms of
01266   // voxels centered in datapoints. VMD treats all dx file maps as
01267   // grid centered data, so this is right.
01268   fprintf(fout, "object 1 class gridpositions counts %d %d %d\n", xsize, ysize, zsize);
01269   fprintf(fout, "origin %g %g %g\n", volmap->origin[0], volmap->origin[1], volmap->origin[2]);
01270   fprintf(fout, "delta %g %g %g\n", cellx[0], cellx[1], cellx[2]);
01271   fprintf(fout, "delta %g %g %g\n", celly[0], celly[1], celly[2]);
01272   fprintf(fout, "delta %g %g %g\n", cellz[0], cellz[1], cellz[2]);
01273   fprintf(fout, "object 2 class gridconnections counts %d %d %d\n", xsize, ysize, zsize);
01274   fprintf(fout, "object 3 class array type double rank 0 items %d data follows\n", gridsize);
01275   
01276   // This reverses the ordering from x fastest to z fastest changing variable
01277   float val1,val2,val3;
01278   int gx=0, gy=0, gz=-1;
01279   for (i=0; i < (gridsize/3)*3; i+=3)  {
01280     if (++gz >= zsize) {
01281       gz=0;
01282       if (++gy >= ysize) {gy=0; gx++;}
01283     }
01284     val1 = volmap->voxel_value(gx,gy,gz);
01285     if (++gz >= zsize) {
01286       gz=0;
01287       if (++gy >= ysize) {gy=0; gx++;}
01288     }
01289     val2 = volmap->voxel_value(gx,gy,gz);
01290     if (++gz >= zsize) {
01291       gz=0;
01292       if (++gy >= ysize) {gy=0; gx++;}
01293     }
01294     val3 = volmap->voxel_value(gx,gy,gz);    
01295     fprintf(fout, "%g %g %g\n", val1, val2, val3);
01296   }
01297   for (i=(gridsize/3)*3; i < gridsize; i++) {
01298     if (++gz >= zsize) {
01299       gz=0;
01300       if (++gy >= ysize) {gy=0; gx++;}
01301     }
01302     fprintf(fout, "%g ", volmap->voxel_value(gx,gy,gz));
01303   }
01304   if (gridsize%3) fprintf(fout, "\n");
01305   fprintf(fout, "\n");
01306   
01307   // Replace any double quotes (") by single quotes (') in the 
01308   // dataname string to make sure that we don't prematurely
01309   // terminate the string in the dx file.
01310   char *squotes = new char[strlen(volmap->name)+1];
01311   strcpy(squotes, volmap->name);
01312   char *s = squotes;
01313   while((s=strchr(s, '"'))) *s = '\'';
01314 
01315   if (volmap->name) {
01316     fprintf(fout, "object \"%s\" class field\n", squotes);
01317   } else {
01318     char dataname[10];
01319     strcpy(dataname, "(no name)");
01320     fprintf(fout, "object \"%s\" class field\n", dataname);
01321   }
01322 
01323   delete [] squotes;
01324 
01325   fclose(fout);
01326   return 0;
01327 }

Generated on Thu Apr 18 02:45:49 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002