00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <math.h>
00018 #include <stdio.h>
00019 #include "VolMapCreate.h"
00020 #include "MoleculeList.h"
00021 #include "VolumetricData.h"
00022 #include "utilities.h"
00023 #include "WKFUtils.h"
00024
00025
00026 #undef hz
00027
00028
00029 #include "VMDApp.h"
00030 #if defined(DEBUG)
00031 #include "MoleculeGraphics.h"
00032 #endif
00033
00034 #include "Measure.h"
00035 #include "Inform.h"
00036
00037 #if defined(VMDCUDA)
00038 #include "CUDAKernels.h"
00039 #endif
00040
00041 #define TIMING
00042
00043 typedef union flint_t {
00044 float f;
00045 int i;
00046 char c[4];
00047 } flint;
00048
00049 #define BIN_DEPTH 8 // number of slots per bin
00050 #define BIN_SLOTSIZE 4 // slot permits x, y, z, vdwtype (4 elements)
00051 #define BIN_SIZE (BIN_DEPTH * BIN_SLOTSIZE) // size given in "flints"
00052
00053
00054 #define BIN_DEPTH 8
00055
00056
00057 struct AtomPosType {
00058 float x, y, z;
00059 int vdwtype;
00060 };
00061
00062
00063 struct BinOfAtoms {
00064 AtomPosType atom[BIN_DEPTH];
00065 };
00066
00067
00068 typedef struct ComputeOccupancyMap_t {
00069
00070
00071
00072 float *map;
00073 int mx, my, mz;
00074 float lx, ly, lz;
00075 float x0, y0, z0;
00076 float ax[3], ay[3], az[3];
00077 float alignmat[16];
00078 int num_coords;
00079 const float *coords;
00080
00081 const int *vdw_type;
00082
00083 const float *vdw_params;
00084
00085
00086 const float *probe_vdw_params;
00087
00088
00089
00090 const float *conformers;
00091
00092
00093
00094 int num_probes;
00095 int num_conformers;
00096
00097 float cutoff;
00098 float extcutoff;
00099
00100 float excl_dist;
00101 float excl_energy;
00102
00103 int kstart, kstop;
00104
00105
00106
00107
00108
00109
00110 float hx, hy, hz;
00111 float bx, by, bz;
00112 float bx_1, by_1, bz_1;
00113 int mpblx, mpbly, mpblz;
00114 int cpu_only;
00115
00116 BinOfAtoms *bin;
00117 BinOfAtoms *bin_zero;
00118 char *bincnt;
00119 char *bincnt_zero;
00120
00121 int nbx, nby, nbz;
00122 int padx, pady, padz;
00123
00124 char *bin_offsets;
00125 int num_bin_offsets;
00126
00127 AtomPosType *extra;
00128 int num_extras;
00129
00130 char *exclusions;
00131
00132
00133
00134 } ComputeOccupancyMap;
00135
00136
00137 #define DEFAULT_EXCL_DIST 1.f
00138 #define DEFAULT_EXCL_ENERGY 87.f
00139
00140 #define DEFAULT_BIN_LENGTH 3.f
00141 #define MAX_BIN_VOLUME 27.f
00142 #define MIN_BIN_VOLUME 8.f
00143
00144
00145
00146
00147
00148 static int ComputeOccupancyMap_setup(ComputeOccupancyMap *);
00149
00150
00151
00152
00153 static int ComputeOccupancyMap_calculate_slab(ComputeOccupancyMap *);
00154
00155
00156 static void ComputeOccupancyMap_cleanup(ComputeOccupancyMap *);
00157
00158
00159
00160 static void write_bin_histogram_map(
00161 const ComputeOccupancyMap *,
00162 const char *filename
00163 );
00164
00165 static void atom_bin_stats(const ComputeOccupancyMap *);
00166
00167
00168
00169
00170
00171 static void compute_allatoms(
00172 float *map,
00173 int mx, int my, int mz,
00174 float lx, float ly, float lz,
00175 const float origin[3],
00176 const float axes[9],
00177 const float alignmat[16],
00178 int num_coords,
00179 const float *coords,
00180 const int *vdw_type,
00181 const float *vdw_params,
00182 float cutoff,
00183 const float *probe_vdw_params,
00184 int num_probe_atoms,
00185 int num_conformers,
00186 const float *conformers,
00187 float excl_energy
00188 );
00189
00190
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 VolMapCreateILS::VolMapCreateILS(VMDApp *_app,
00218 int mol, int firstframe, int lastframe,
00219 float T, float res, int nsub,
00220 float cut, int mask) :
00221 app(_app), molid(mol), cutoff(cut),
00222 temperature(T), first(firstframe), last(lastframe),
00223 maskonly(mask)
00224 {
00225 compute_elec = false;
00226
00227 num_probe_atoms = 0;
00228 num_conformers = 0;
00229 conformer_freq = 1;
00230 conformers = NULL;
00231 probe_coords = NULL;
00232 probe_vdw = NULL;
00233 probe_charge = NULL;
00234 probe_axisorder1 = 1;
00235 probe_axisorder2 = 1;
00236 probe_tetrahedralsymm = 0;
00237 probe_effsize = 0.f;
00238 extcutoff = cutoff;
00239
00240 max_energy = DEFAULT_EXCL_ENERGY;
00241 min_occup = expf(-max_energy);
00242
00243 nsubsamp = 1;
00244 if (nsub>1) nsubsamp = nsub;
00245 delta = res/float(nsubsamp);
00246
00247 alignsel = NULL;
00248 pbc = false;
00249 pbcbox = false;
00250 pbccenter[0] = pbccenter[1] = pbccenter[2] = 0.f;
00251
00252 num_unique_types = 0;
00253 vdwparams = NULL;
00254 atomtypes = NULL;
00255
00256 minmax[0] = 0.f;
00257 minmax[1] = 0.f;
00258 minmax[2] = 0.f;
00259 minmax[3] = 0.f;
00260 minmax[4] = 0.f;
00261 minmax[5] = 0.f;
00262
00263 volmap = NULL;
00264 volmask = NULL;
00265 }
00266
00267
00268 VolMapCreateILS::~VolMapCreateILS() {
00269 if (probe_coords) delete [] probe_coords;
00270 if (probe_vdw) delete [] probe_vdw;
00271 if (probe_charge) delete [] probe_charge;
00272
00273 if (conformers) delete [] conformers;
00274 if (vdwparams) delete [] vdwparams;
00275 if (atomtypes) delete [] atomtypes;
00276
00277 if (volmap) delete volmap;
00278
00279
00280 }
00281
00282
00285 int VolMapCreateILS::write_map(const char *filename) {
00286
00287
00288
00289
00290
00291 char tmpstr[256];
00292 if (maskonly) {
00293 sprintf(tmpstr, "ligand pmf mask, %i frames, cutoff = %.2fA",
00294 computed_frames, cutoff);
00295 } else {
00296 sprintf(tmpstr, "ligand pmf [kT], %i frames, T = %.2f Kelvin, maxenergy = %g, cutoff = %.2fA",
00297 computed_frames, temperature, max_energy, cutoff);
00298 }
00299 volmap->set_name(tmpstr);
00300
00301
00302
00303
00304 if (!add_map_to_molecule()) return 0;
00305
00306 Molecule *mol = app->moleculeList->mol_from_id(molid);
00307 FileSpec spec;
00308 spec.nvolsets = 1;
00309 spec.setids = new int[1];
00310 spec.setids[0] = mol->num_volume_data()-1;
00311
00312 if (!app->molecule_savetrajectory(molid, filename, "dx", &spec)) {
00313 msgErr << "Couldn't write dx file!" << sendmsg;
00314 }
00315
00316 return 1;
00317 }
00318
00319
00320
00321 int VolMapCreateILS::add_map_to_molecule() {
00322 Molecule *mol = app->moleculeList->mol_from_id(molid);
00323 float origin[3], xaxis[3], yaxis[3], zaxis[3];
00324 int i;
00325 for (i=0; i<3; i++) {
00326 origin[i] = (float) volmap->origin[i];
00327 xaxis[i] = (float) volmap->xaxis[i];
00328 yaxis[i] = (float) volmap->yaxis[i];
00329 zaxis[i] = (float) volmap->zaxis[i];
00330 }
00331 float *voldata = volmap->data;
00332
00333 int err = app->molecule_add_volumetric(molid,
00334 volmap->name, origin, xaxis, yaxis, zaxis,
00335 volmap->xsize, volmap->ysize, volmap->zsize,
00336 voldata);
00337 if (err != 1) {
00338 msgErr << "ERROR: Adding volmap " << mol->num_volume_data()-1
00339 << " to molecule " << molid << " was unsuccessful!"
00340 << sendmsg;
00341 return 0;
00342 }
00343
00344
00345
00346
00347 volmap->data = NULL;
00348
00349 msgInfo << "Added volmap " << mol->num_volume_data()-1
00350 << " to molecule " << molid << "." << sendmsg;
00351
00352 return 1;
00353 }
00354
00355
00356
00357
00358 void VolMapCreateILS::set_probe(int numatoms, int num_conf,
00359 const float *pcoords,
00360 const float *vdwrmin,
00361 const float *vdweps,
00362 const float *charge) {
00363 if (numatoms<=0) return;
00364 if (numatoms==1 && num_conf>0) num_conf = 0;
00365
00366 conformer_freq = num_conf;
00367 num_probe_atoms = numatoms;
00368 probe_coords = new float[3*numatoms];
00369 probe_vdw = new float[2*numatoms];
00370 probe_charge = new float[numatoms];
00371
00372
00373
00374 const float beta = 503.2206f/temperature;
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 int i;
00396 for (i=0; i<num_probe_atoms; i++) {
00397 probe_vdw[2*i ] = beta*sqrtf(-vdweps[i]);
00398 probe_vdw[2*i+1] = vdwrmin[i];
00399 }
00400
00401 if (charge) {
00402 memcpy(probe_charge, charge, numatoms*sizeof(float));
00403 } else {
00404 memset(probe_charge, 0, numatoms*sizeof(float));
00405 }
00406
00407
00408 float cgeom[3];
00409 vec_zero(cgeom);
00410
00411 for (i=0; i<num_probe_atoms; i++) {
00412 vec_add(cgeom, cgeom, &pcoords[3*i]);
00413 }
00414 vec_scale(cgeom, 1.f/(float)num_probe_atoms, cgeom);
00415
00416
00417 for (i=0; i<num_probe_atoms; i++) {
00418 vec_sub(&probe_coords[3*i], &pcoords[3*i], cgeom);
00419 }
00420 }
00421
00422
00423
00424
00425 void VolMapCreateILS::set_probe_symmetry(
00426 int order1, const float *axis1,
00427 int order2, const float *axis2,
00428 int tetrahedral) {
00429 probe_tetrahedralsymm = tetrahedral;
00430
00431 if (axis1 && order1>1) {
00432 probe_axisorder1 = order1;
00433 vec_copy(probe_symmaxis1, axis1);
00434 vec_normalize(probe_symmaxis1);
00435 }
00436 if (axis2 && order2>1) {
00437 probe_axisorder2 = order2;
00438 vec_copy(probe_symmaxis2, axis2);
00439 vec_normalize(probe_symmaxis2);
00440 }
00441 if (!tetrahedral && probe_axisorder1>1 && probe_axisorder2>1 &&
00442 dot_prod(probe_symmaxis1, probe_symmaxis2) > 0.05) {
00443
00444 if (probe_axisorder1<probe_axisorder2) {
00445 probe_axisorder1 = probe_axisorder2;
00446 }
00447 probe_axisorder2 = 1;
00448 }
00449 }
00450
00451
00452
00453 void VolMapCreateILS::set_minmax (float minx, float miny, float minz,
00454 float maxx, float maxy, float maxz) {
00455 minmax[0] = minx;
00456 minmax[1] = miny;
00457 minmax[2] = minz;
00458 minmax[3] = maxx;
00459 minmax[4] = maxy;
00460 minmax[5] = maxz;
00461 }
00462
00463
00464
00465
00466
00467
00468
00469
00470 void VolMapCreateILS::set_pbc(float center[3], int bbox) {
00471 pbc = 1;
00472 pbcbox = bbox;
00473 if (center) vec_copy(pbccenter, center);
00474 }
00475
00476
00477
00478 void VolMapCreateILS::set_maxenergy(float maxenergy) {
00479 max_energy = maxenergy;
00480 if (max_energy>DEFAULT_EXCL_ENERGY) {
00481 max_energy = DEFAULT_EXCL_ENERGY;
00482 }
00483 }
00484
00485
00486
00487 void VolMapCreateILS::set_alignsel(AtomSel *asel) {
00488 if (asel) alignsel = asel;
00489 }
00490
00491
00492
00493
00494 void VolMapCreateILS::set_transform(const Matrix4 *mat) {
00495 transform = *mat;
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 int VolMapCreateILS::set_grid() {
00522
00523 int nx = (int) ceilf((minmax[3]-minmax[0])/(delta*nsubsamp));
00524 int ny = (int) ceilf((minmax[4]-minmax[1])/(delta*nsubsamp));
00525 int nz = (int) ceilf((minmax[5]-minmax[2])/(delta*nsubsamp));
00526
00527
00528 nsampx = nx*nsubsamp;
00529 nsampy = ny*nsubsamp;
00530 nsampz = nz*nsubsamp;
00531
00532
00533
00534
00535
00536
00537 float origin[3];
00538 origin[0] = minmax[0] + 0.5f*delta*nsubsamp;
00539 origin[1] = minmax[1] + 0.5f*delta*nsubsamp;
00540 origin[2] = minmax[2] + 0.5f*delta*nsubsamp;
00541
00542
00543 gridorigin[0] = minmax[0] + 0.5f*delta;
00544 gridorigin[1] = minmax[1] + 0.5f*delta;
00545 gridorigin[2] = minmax[2] + 0.5f*delta;
00546
00547
00548
00549
00550 float cellx[3], celly[3], cellz[3];
00551 cellx[0] = delta*nsubsamp;
00552 cellx[1] = 0.f;
00553 cellx[2] = 0.f;
00554 celly[0] = 0.f;
00555 celly[1] = delta*nsubsamp;
00556 celly[2] = 0.f;
00557 cellz[0] = 0.f;
00558 cellz[1] = 0.f;
00559 cellz[2] = delta*nsubsamp;
00560
00561
00562
00563
00564 float xaxis[3], yaxis[3], zaxis[3];
00565 int i;
00566 for (i=0; i<3; i++) {
00567 xaxis[i] = cellx[i]*(nx-1);
00568 yaxis[i] = celly[i]*(ny-1);
00569 zaxis[i] = cellz[i]*(nz-1);
00570 }
00571
00572
00573 float *data = new float[nx*ny*nz];
00574 if (maskonly) {
00575
00576 for (i=0; i<nx*ny*nz; i++) {
00577 data[i] = 1.f;
00578 }
00579 } else {
00580 memset(data, 0, nx*ny*nz*sizeof(float));
00581 }
00582
00583 volmap = new VolumetricData("\0", origin,
00584 xaxis, yaxis, zaxis, nx, ny, nz, data);
00585
00586 if (!volmap->gridsize())
00587 return MEASURE_ERR_ZEROGRIDSIZE;
00588
00589 return 0;
00590 }
00591
00592
00593
00594 int VolMapCreateILS::initialize() {
00595 if (!app->molecule_numframes(molid))
00596 return MEASURE_ERR_NOFRAMES;
00597
00598 msgInfo << "\n-- Implicit Ligand Sampling --\n\n"
00599 << "This computes the potential of mean force (free energy) over\n"
00600 << "a 3-D grid, for a small ligand.\n\n" << sendmsg;
00601
00602
00603
00604
00605 char tmpstr[256];
00606 sprintf(tmpstr, "Temperature: %g K", temperature);
00607 msgInfo << tmpstr << sendmsg;
00608 sprintf(tmpstr, "Energy cutoff: %g kT", max_energy);
00609 msgInfo << tmpstr << sendmsg;
00610
00611
00612 if (compute_elec && probe_charge[0]==0.0 && probe_charge[1]==0.0) {
00613 compute_elec = 0;
00614 }
00615 msgInfo << "Electrostatics: ";
00616 if (compute_elec) msgInfo << "on" << sendmsg;
00617 else msgInfo << "off" << sendmsg;
00618
00619 sprintf(tmpstr, "Map resolution: %g Angstrom", delta);
00620 msgInfo << tmpstr << sendmsg;
00621 sprintf(tmpstr, "Subgrid res: %d points", nsubsamp);
00622 msgInfo << tmpstr << sendmsg;
00623
00624
00625 if (num_probe_atoms==1) {
00626 sprintf(tmpstr, "VDW cutoff: %6.3f Angstrom", cutoff);
00627 msgInfo << tmpstr << sendmsg;
00628 }
00629 else {
00630
00631
00632
00633 float max_proberad = 0.f;
00634 int i;
00635 for (i=0; i<num_probe_atoms; i++) {
00636 float dist = norm(&probe_coords[3*i]);
00637 if (dist>max_proberad) max_proberad = dist;
00638 }
00639
00640 sprintf(tmpstr, "VDW cutoff: %6.3f Angstrom (%6.3f + probe radius)",
00641 cutoff+max_proberad, cutoff);
00642 msgInfo << tmpstr << sendmsg;
00643
00644 extcutoff = cutoff + max_proberad;
00645 }
00646
00647 if (alignsel) {
00648
00649 alignrefpos = alignsel->coordinates(app->moleculeList);
00650
00651 } else if (!alignsel && last-first>1) {
00652 msgWarn << sendmsg;
00653 msgWarn << "Use of periodic boundaries requested (-pbc) but" << sendmsg;
00654 msgWarn << "no alignment matrix specified (you didn't use -alignsel)." << sendmsg;
00655 msgWarn << "Have you aligned your structure prior to this calculation?" << sendmsg;
00656 msgWarn << "Hopefully not, since it will have totally messed" << sendmsg;
00657 msgWarn << "up the definition of your PBC cells. Instead you" << sendmsg;
00658 msgWarn << "should use the -alignsel option and let volmap handle" << sendmsg;
00659 msgWarn << "the alignment." << sendmsg;
00660 }
00661
00662 if (pbc && pbcbox) {
00663
00664
00665
00666 int err = compute_pbcminmax(app->moleculeList, molid, first,
00667 pbccenter, &transform, &minmax[0], &minmax[3]);
00668 if (err) return err;
00669 }
00670
00671 sprintf(tmpstr, "{%g %g %g} {%g %g %g}\n", minmax[0], minmax[1], minmax[2], minmax[3], minmax[4], minmax[5]);
00672 msgInfo << "Grid minmax = " << tmpstr << sendmsg;
00673
00674
00675 float ffcutoff[3];
00676 ffcutoff[0] = ffcutoff[1] = ffcutoff[2] = extcutoff;
00677 float cutminmax[6];
00678 vec_sub(cutminmax, minmax, ffcutoff);
00679 vec_add(cutminmax+3, minmax+3, ffcutoff);
00680
00681 if (!box_inside_pbccell(first, minmax)) {
00682 if (!pbc) {
00683 msgWarn << sendmsg;
00684 msgWarn << "Selected grid exceeds periodic cell boundaries." << sendmsg;
00685 msgWarn << "Parts of the map will be undefined!" << sendmsg;
00686 msgWarn << "(Consider using -pbc flag to ensure map is valid over entire grid.)"
00687 << sendmsg << sendmsg;
00688 } else {
00689 msgInfo << "Selected grid exceeds periodic cell boundaries." << sendmsg;
00690 msgInfo << "Using PBC image atoms to ensure map is valid over entire grid."
00691 << sendmsg;
00692 }
00693 } else if (!box_inside_pbccell(first, cutminmax)) {
00694 if (!pbc) {
00695 msgWarn << sendmsg;
00696 msgWarn << "Nonbonded interaction cutoff region needed around" << sendmsg;
00697 msgWarn << "selected grid exceeds periodic cell boundaries." << sendmsg;
00698 msgWarn << "Parts of the map will be ill-defined!" << sendmsg;
00699 msgWarn << "(Consider using -pbc flag to ensure map is valid over entire grid.)"
00700 << sendmsg << sendmsg;;
00701 } else {
00702 msgInfo << "Nonbonded interaction cutoff region needed around" << sendmsg;
00703 msgInfo << "selected grid exceeds periodic cell boundaries." << sendmsg;
00704 msgInfo << "Using PBC image atoms to ensure map is valid over entire grid."
00705 << sendmsg;
00706 }
00707 }
00708
00709
00710 set_grid();
00711 msgInfo << "Grid origin = {"
00712 << volmap->origin[0] << " "
00713 << volmap->origin[1] << " "
00714 << volmap->origin[2] << "}" << sendmsg;
00715
00716 char tmp[64];
00717 sprintf(tmp, "Grid size = %dx%dx%d (%.1f MB)",
00718 nsampx, nsampy, nsampz,
00719 sizeof(float)*nsampx*nsampy*nsampz/(1024.*1024.));
00720 msgInfo << tmp << sendmsg;
00721
00722 if (nsubsamp>1) {
00723 sprintf(tmp, "Downsampling final map to %dx%dx%d (%.1f MB)",
00724 volmap->xsize, volmap->ysize, volmap->zsize,
00725 sizeof(float)*volmap->gridsize()/(1024.*1024.));
00726 msgInfo << tmp << sendmsg;
00727 }
00728
00729 Molecule *mol = app->moleculeList->mol_from_id(molid);
00730 num_atoms = mol->nAtoms;
00731
00732 msgInfo << "Global transformation for all frames:" << sendmsg;
00733 print_Matrix4(&transform);
00734
00735 if (alignsel) msgInfo << "Aligning all frames to the first one." << sendmsg;
00736 else msgInfo << "Assuming all frames are aligned." << sendmsg;
00737
00738 if (maskonly) {
00739 msgInfo << sendmsg << "Masking mode:" << sendmsg
00740 << "Generating a mask map containing 1 for grid points that" << sendmsg
00741 << "have a valid contribution from each frame and 0 otherwise."
00742 << sendmsg << sendmsg;
00743 return MEASURE_NOERR;
00744 }
00745
00746
00747
00748
00749 create_unique_paramlist();
00750
00751
00752 float min_sysrmin = vdwparams[1];
00753 int i;
00754 for (i=1; i<num_unique_types; i++) {
00755 if (vdwparams[2*i+1]<min_sysrmin) min_sysrmin = vdwparams[2*i+1];
00756 }
00757
00758
00759 float min_probermin = probe_vdw[1];
00760 for (i=1; i<num_probe_atoms; i++) {
00761 if (probe_vdw[2*i+1]<min_probermin) min_probermin = probe_vdw[2*i+1];
00762 }
00763
00764
00765 const float invbeta = temperature/503.2206f;
00766 msgInfo << "Probe with "<<num_probe_atoms<<" atoms:" << sendmsg;
00767 for (i=0; i<num_probe_atoms; i++) {
00768 sprintf(tmpstr, " atom %d: epsilon = %g, rmin/2 = %g, charge = % .3f",
00769 i, -pow(invbeta*probe_vdw[2*i],2),
00770 probe_vdw[2*i+1], probe_charge[i]);
00771 msgInfo << tmpstr << sendmsg;
00772 }
00773
00774
00775 if (conformer_freq && num_probe_atoms>1) {
00776 initialize_probe();
00777 } else {
00778 msgInfo << "Ignoring orientations for monoatomic probe." << sendmsg;
00779 }
00780
00781 get_eff_proberadius();
00782
00783
00784
00785 sprintf(tmpstr, "Clash exclusion distance: %.3f Angstrom", excl_dist);
00786 msgInfo << tmpstr << sendmsg;
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798 return MEASURE_NOERR;
00799 }
00800
00801
00802 void VolMapCreateILS::get_eff_proberadius() {
00803 int numconf, numorient, numrot;
00804 float *conf;
00805 if (probe_tetrahedralsymm) {
00806 numconf = gen_conf_tetrahedral(conf, 6, numorient, numrot);
00807 } else {
00808 numconf = gen_conf(conf, 8, numorient, numrot);
00809 }
00810
00811 int t, i, j, k;
00812 float max_proberad = 0.f;
00813 for (k=0; k<num_probe_atoms; k++) {
00814 float dist = norm(&probe_coords[3*k]);
00815 float rmin = probe_vdw[2*k+1];
00816 if (dist+rmin>max_proberad) max_proberad = dist+rmin;
00817 }
00818
00819 float stepsize = 0.01f;
00820 float *effrad = new float[num_unique_types];
00821 excl_dist = 999999.f;
00822
00823 for (t=0; t<num_unique_types; t++) {
00824 float vdweps = vdwparams[2*t ];
00825 float vdwrmin = vdwparams[2*t+1];
00826
00827 float begin = max_proberad + vdwrmin;
00828 int maxnumstep = int(0.5+begin/stepsize);
00829
00830 float Wmin = 0.f;
00831 float Ropt = 0.f;
00832
00833 for (i=0; i<maxnumstep; i++) {
00834 float dist = begin - float(i)*stepsize;
00835 if (dist<=0.0f) break;
00836
00837 float avgocc = 0.f;
00838 for (j=0; j<numconf; j++) {
00839 float *coor = &conf[3*num_probe_atoms*j];
00840 float u = 0.f;
00841 for (k=0; k<num_probe_atoms; k++) {
00842 float dx = dist-coor[3*k];
00843 float dy = coor[3*k+1];
00844 float dz = coor[3*k+2];
00845 float r2 = dx*dx + dy*dy + dz*dz;
00846 float epsilon = vdweps * probe_vdw[2*k];
00847 float rmin = vdwrmin + probe_vdw[2*k+1];
00848 float rm6 = rmin*rmin / r2;
00849 rm6 = rm6 * rm6 * rm6;
00850 u += epsilon * rm6 * (rm6 - 2.f);
00851
00852 }
00853
00854
00855 float occ = expf(-float(u));
00856
00857 avgocc += occ;
00858 }
00859 avgocc /= float(numconf);
00860 float W = -logf(avgocc);
00861
00862 if (W<Wmin) { Wmin = W; Ropt = dist; }
00863 if (W>max_energy+5.f) {
00864 effrad[t] = dist;
00865 break;
00866 }
00867 }
00868
00869
00870 if (effrad[t]<excl_dist) excl_dist = effrad[t];
00871 }
00872
00873 delete [] effrad;
00874 delete [] conf;
00875 }
00876
00877
00878
00879
00880 static bool collinear(const float *axis1, const float *axis2, float tol) {
00881 if (fabs(dot_prod(axis1, axis2)) > 1.f-DEGTORAD(tol)) return 1;
00882 return 0;
00883 }
00884
00885
00886
00887
00888 int VolMapCreateILS::is_probe_linear(float *axis) {
00889 if (num_probe_atoms==1) return 0;
00890
00891 float vec0[3], vec1[3];
00892 vec_sub(vec0, &probe_coords[3], &probe_coords[0]);
00893 vec_copy(axis, vec0);
00894 if (num_probe_atoms==2) return 1;
00895
00896 float norm0 = norm(vec0);
00897 int i;
00898 for (i=2; i<num_probe_atoms; i++) {
00899 vec_sub(vec1, &probe_coords[3*i], &probe_coords[0]);
00900 float dot = dot_prod(vec0, vec1)/(norm0*norm(vec1));
00901 if (fabs(dot) < 0.95f) return 0;
00902
00903 if (dot>0.f) vec_add(axis, axis, vec1);
00904 else vec_sub(axis, axis, vec1);
00905 }
00906 vec_normalize(axis);
00907 return 1;
00908 }
00909
00910
00911
00912
00913
00914
00915 static int triangulate(const float *pole, const float *eq1,
00916 const float *eq2, int freq, float *v) {
00917 if (freq==0) {
00918 vec_copy(v, pole);
00919 return 1;
00920 }
00921
00922 float meridian[3], parallel[3];
00923 vec_sub(meridian, eq1, pole);
00924 vec_sub(parallel, eq2, eq1);
00925 float mlen = norm(meridian);
00926 float plen = norm(parallel);
00927 vec_normalize(meridian);
00928 vec_normalize(parallel);
00929 int i, k = 0;
00930 for (i=0; i<=freq; i++) {
00931 float latitude = float(i)/float(freq)*mlen;
00932 float p[3], p0[3];
00933 vec_copy(p0, pole);
00934 vec_scaled_add(p0, latitude, meridian);
00935 int j;
00936 for (j=0; j<=i; j++) {
00937 float longitude = float(j)/float(freq)*plen;
00938 vec_copy(p, p0);
00939 vec_scaled_add(p, longitude, parallel);
00940 vec_copy(&v[3*k], p);
00941 k++;
00942 }
00943 }
00944 return k;
00945 }
00946
00947
00948
00949
00950 static void octahedron(float *vertices, int C2symm) {
00951 const float v[] = {1.f, 0.f, 0.f,
00952 0.f, 1.f, 0.f,
00953 0.f, 0.f, 1.f};
00954 memcpy(vertices, v, 9*sizeof(float));
00955 if (!C2symm) {
00956 int i;
00957 for (i=0; i<3; i++) {
00958 vec_negate(&vertices[9+3*i], &vertices[3*i]);
00959 }
00960 }
00961 }
00962
00963
00964
00965 static void hexahedron(float *vertices, int C2symm) {
00966 const float v[] = {1.f, 1.f, 1.f,
00967 1.f, -1.f, 1.f,
00968 1.f, 1.f, -1.f,
00969 1.f, -1.f, -1.f};
00970 memcpy(vertices, v, 12*sizeof(float));
00971
00972 if (!C2symm) {
00973 int i;
00974 for (i=0; i<4; i++) {
00975 vec_negate(&vertices[12+3*i], &vertices[3*i]);
00976 }
00977 }
00978 }
00979
00980
00981
00982
00983
00984
00985
00986 static void dodecahedron(float *faces, float *vertices, int C2symm) {
00987
00988 const float dihedral = float(180.f-RADTODEG(acos(-1.f/sqrtf(5.f))));
00989
00990
00991 float x[3];
00992 vec_zero(x); x[0] = 1.f;
00993 vec_copy(&faces[0], x);
00994
00995 Matrix4 rot;
00996 rot.rot(dihedral, 'z');
00997 rot.multpoint3d(&faces[0], &faces[3]);
00998
00999 int i;
01000 for (i=1; i<5; i++) {
01001 rot.identity();
01002 rot.rot(float(i)*72.f, 'x');
01003 rot.multpoint3d(&faces[3], &faces[3+3*i]);
01004 }
01005 if (!C2symm) {
01006 for (i=0; i<6; i++) {
01007 vec_negate(&faces[18+3*i], &faces[3*i]);
01008 }
01009 }
01010
01011
01012
01013 for (i=0; i<5; i++) {
01014 vec_copy(&vertices[3*i], &faces[0]);
01015 vec_add(&vertices[3*i], &vertices[3*i], &faces[3*(i+1)]);
01016 vec_add(&vertices[3*i], &vertices[3*i], &faces[3*((i+1)%5+1)]);
01017 vec_normalize(&vertices[3*i]);
01018 }
01019
01020 vec_copy(&vertices[3*5], &faces[3*1]);
01021 vec_add(&vertices[3*5], &vertices[3*5], &faces[3*2]);
01022 vec_normalize(&vertices[3*5]);
01023 float cross[3];
01024 cross_prod(cross, &vertices[3*5], &faces[0]);
01025 vec_normalize(cross);
01026 float phi = angle(&vertices[3*5], &vertices[0]);
01027 rot.identity();
01028 rot.rotate_axis(cross, float(DEGTORAD(-phi)));
01029 rot.multpoint3d(&vertices[3*5], &vertices[3*5]);
01030 for (i=1; i<5; i++) {
01031 rot.identity();
01032 rot.rot(float(i)*72.f, 'x');
01033 rot.multpoint3d(&vertices[3*5], &vertices[3*5+3*i]);
01034 }
01035
01036
01037 if (!C2symm) {
01038 for (i=0; i<10; i++) {
01039 vec_negate(&vertices[30+3*i], &vertices[3*i]);
01040 }
01041 }
01042 }
01043
01044
01045
01046
01047
01048
01049
01050
01051 static int icosahedron_geodesic(float *(&orientations),
01052 int C2symm, int freq) {
01053 int i;
01054 float faces[3*12];
01055 float junk[3*20];
01056 dodecahedron(faces, junk, 0);
01057 float meridian[3], parallel[3];
01058
01059 int numvertex = 0;
01060 for (i=1; i<=freq+1; i++) numvertex += i;
01061 int symmfac = C2symm ? 2 : 1;
01062 int numorient = (10*freq*freq + 2)/symmfac;
01063 orientations = new float[3*numorient];
01064
01065
01066 vec_copy(&orientations[0], &faces[0]);
01067 int k = 1;
01068
01069 for (i=0; i<5; i++) {
01070
01071 float p0[3], p1[3], p2[3];
01072 vec_sub(parallel, &faces[3+3*((i+1)%5)], &faces[3*(i+1)]);
01073 float edgelen = norm(parallel);
01074 vec_normalize(parallel);
01075 vec_sub(meridian, &faces[3*(i+1)], &faces[0]);
01076 vec_normalize(meridian);
01077 vec_copy(p0, &faces[0]);
01078 vec_copy(p1, &faces[3*(i+1)]);
01079 vec_copy(p2, &faces[3+3*((i+1)%5)]);
01080 vec_scaled_add(p0, 1.f/float(freq)*edgelen, meridian);
01081 vec_scaled_add(p2, -1.f/float(freq)*edgelen, parallel);
01082 triangulate(p0, p1, p2, freq-1, &orientations[3*k]);
01083 k += numvertex-(freq+1);
01084
01085
01086 vec_sub(meridian, &faces[3*(i+1)], &faces[21+3*((i+3)%5)]);
01087 vec_normalize(meridian);
01088 vec_copy(p0, &faces[21+3*((i+3)%5)]);
01089 vec_copy(p1, &faces[3*(i+1)]);
01090 vec_scaled_add(p0, 1.f/float(freq)*edgelen, meridian);
01091 vec_scaled_add(p1, -1.f/float(freq)*edgelen, meridian);
01092 vec_copy(p2, p1);
01093 vec_scaled_add(p2, float(freq-2)/float(freq)*edgelen, parallel);
01094 triangulate(p0, p1, p2, freq-2, &orientations[3*k]);
01095 k += numvertex-(freq+1)-freq;
01096 }
01097
01098 if (!C2symm) {
01099 for (i=0; i<numorient/2; i++) {
01100 vec_negate(&orientations[3*numorient/2+3*i], &orientations[3*i]);
01101 }
01102 }
01103
01104 return numorient;
01105 }
01106
01107 float VolMapCreateILS::dimple_depth(float phi) {
01108 int i;
01109 phi = 0.5f*phi;
01110
01111 float min_syseps = vdwparams[0];
01112 float min_sysrmin = vdwparams[1];
01113 for (i=1; i<num_unique_types; i++) {
01114 if (vdwparams[2*i+1]<min_sysrmin) {
01115 min_syseps = vdwparams[2*i ];
01116 min_sysrmin = vdwparams[2*i+1];
01117 }
01118 }
01119 float maxdepth = 0.f;
01120
01121
01122 for (i=0; i<num_probe_atoms; i++) {
01123 float d = norm(&probe_coords[3*i]);
01124 float a = d*sinf(float(DEGTORAD(phi)));
01125 float m = a/cosf(float(DEGTORAD(phi)));
01126 if (phi == 90.f) m = a;
01127 float c = probe_vdw[2*i+1] + min_sysrmin;
01128 if (m>c) {
01129 maxdepth = d;
01130 break;
01131 }
01132 float b = sqrtf(c*c-m*m);
01133 float depth = d + c - d*cosf(float(DEGTORAD(phi))) - b;
01134
01135
01136
01137 float epsilon = min_syseps * probe_vdw[2*i];
01138 float rmin = min_sysrmin + probe_vdw[2*i+1];
01139
01140 float r2 = c*c;
01141 float rm6 = rmin*rmin / r2;
01142 rm6 = rm6 * rm6 * rm6;
01143 float u0 = epsilon * rm6 * (rm6 - 2.f);
01144
01145 r2 = (c+depth)*(c+depth);
01146 rm6 = rmin*rmin / r2;
01147 rm6 = rm6 * rm6 * rm6;
01148 float u1 = epsilon * rm6 * (rm6 - 2.f);
01149
01150 r2 = (c-depth)*(c-depth);
01151 rm6 = rmin*rmin / r2;
01152 rm6 = rm6 * rm6 * rm6;
01153 float u2 = epsilon * rm6 * (rm6 - 2.f);
01154 float du1 = u1-u0;
01155 float du2 = u2-u0;
01156 printf("phi = %.2f: %d dimple depth = %f = %5.2f%%, dU1 = %fkT = %5.2f%%; dU1 = %fkT = %5.2f%%\n",
01157 phi, i, depth, 100.f*depth/(d+probe_vdw[2*i]), du1, fabs(100.f*du1/u0), du2, fabs(100.f*du2/u0));
01158
01159 if (depth>maxdepth) maxdepth = depth;
01160 }
01161 return maxdepth;
01162 }
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182 int VolMapCreateILS::gen_conf_tetrahedral(float *(&conform),
01183 int freq, int &numorient, int &numrot) {
01184
01185 float tetra0[3], tetra1[3], tetra2[3], tetra3[3];
01186 vec_zero(tetra0);
01187 tetra0[0] = 1.f;
01188 Matrix4 rot;
01189 rot.rot(109.47122f, 'z');
01190 rot.multpoint3d(tetra0, tetra1);
01191 rot.identity();
01192 rot.rot(120.f, 'x');
01193 rot.multpoint3d(tetra1, tetra2);
01194 rot.multpoint3d(tetra2, tetra3);
01195
01196 #if defined(DEBUG)
01197 Molecule *mol = app->moleculeList->mol_from_id(molid);
01198 MoleculeGraphics *gmol = mol->moleculeGraphics();
01199 gmol->use_color(8);
01200 gmol->add_line(tetra0, tetra1, 0, 1);
01201 gmol->add_line(tetra0, tetra2, 0, 1);
01202 gmol->add_line(tetra0, tetra3, 0, 1);
01203 gmol->add_line(tetra1, tetra2, 0, 1);
01204 gmol->add_line(tetra1, tetra3, 0, 1);
01205 gmol->add_line(tetra2, tetra3, 0, 1);
01206 #endif
01207
01208
01209 float *orientations;
01210 orientations = new float[3*8];
01211
01212 vec_copy(&orientations[3*0], tetra0);
01213 vec_copy(&orientations[3*1], tetra1);
01214 vec_copy(&orientations[3*2], tetra2);
01215 vec_copy(&orientations[3*3], tetra3);
01216 float face[3];
01217 vec_copy(face, tetra0);
01218 vec_add(face, face, tetra1);
01219 vec_add(face, face, tetra2);
01220 vec_copy(&orientations[3*4], face);
01221 vec_copy(face, tetra0);
01222 vec_add(face, face, tetra1);
01223 vec_add(face, face, tetra3);
01224 vec_copy(&orientations[3*5], face);
01225 vec_copy(face, tetra0);
01226 vec_add(face, face, tetra2);
01227 vec_add(face, face, tetra3);
01228 vec_copy(&orientations[3*6], face);
01229 vec_copy(face, tetra1);
01230 vec_add(face, face, tetra2);
01231 vec_add(face, face, tetra3);
01232 vec_copy(&orientations[3*7], face);
01233
01234 numrot = freq;
01235 numorient = 8;
01236 int numconf = numorient*numrot-6;
01237 conform = new float[3*num_probe_atoms*numconf];
01238 memset(conform, 0, 3*num_probe_atoms*numconf*sizeof(float));
01239
01240 int conf = 0;
01241 int i;
01242 for (i=0; i<numorient; i++) {
01243 float *dir = &orientations[3*i];
01244 vec_normalize(dir);
01245
01246
01247 int j;
01248 for (j=0; j<numrot; j++) {
01249
01250
01251 if (i%4 && j==0) continue;
01252
01253 float psi = float(j)/float(numrot)*360.f/float(probe_axisorder1);
01254 Matrix4 rot;
01255 if (i>=numorient/2) {
01256
01257
01258
01259 float z[3];
01260 vec_zero(z); z[2]=1.f;
01261 rot.rotate_axis(z, float(DEGTORAD(180.f)));
01262 }
01263
01264
01265 rot.rotate_axis(dir, float(DEGTORAD(psi)));
01266
01267
01268 int k;
01269 for (k=0; k<num_probe_atoms; k++) {
01270 rot.multpoint3d(&probe_coords[3*k],
01271 &conform[3*num_probe_atoms*conf + 3*k]);
01272 }
01273
01274 conf++;
01275 }
01276 }
01277
01278 delete [] orientations;
01279
01280
01281 return numconf;
01282 }
01283
01284
01285
01286
01287 static float signed_angle(const float *axis,
01288 const float *v1, const float *v2) {
01289 float normaxis[3], cross1[3], cross2[3], cross3[3];
01290 cross_prod(cross1, axis, v1);
01291 cross_prod(cross2, axis, v2);
01292 cross_prod(cross3, v1, v2);
01293 vec_normalize(cross3);
01294 vec_copy(normaxis, axis);
01295 vec_normalize(normaxis);
01296 float phi = angle(cross1, cross2);
01297 if (dot_prod(axis, cross3)<0) {
01298 phi = -phi;
01299 }
01300 return phi;
01301 }
01302
01303
01304
01305
01306
01307
01308
01309 int VolMapCreateILS::gen_conf(float *(&conform), int freq,
01310 int &numorient, int &numrot) {
01311 int i;
01312 float *orientations = NULL;
01313 int C2symm = (probe_axisorder2==2 ? 1 : 0);
01314 int symmfac = C2symm ? 2 : 1;
01315 float anglespacing = 360.f;
01316
01317 switch (freq) {
01318 case 1:
01319 numorient = 1;
01320 orientations = new float[3*numorient];
01321 break;
01322 case 2:
01323
01324 numorient = 6/symmfac;
01325 orientations = new float[3*numorient];
01326 octahedron(orientations, C2symm);
01327 anglespacing = 90.f;
01328 break;
01329 case 3:
01330
01331 numorient = 8/symmfac;
01332 orientations = new float[3*numorient];
01333 hexahedron(orientations, C2symm);
01334 anglespacing = 109.47122f;
01335 break;
01336 case 4:
01337
01338 numorient = 12/symmfac;
01339 orientations = new float[3*numorient];
01340 float vertices[3*20];
01341 dodecahedron(orientations, vertices, C2symm);
01342 anglespacing = float(180.f-RADTODEG(acos(-1.f/sqrtf(5.f))));
01343 break;
01344 case 5:
01345
01346 numorient = 20/symmfac;
01347 orientations = new float[3*numorient];
01348 float faces[3*12];
01349 dodecahedron(faces, orientations, C2symm);
01350 anglespacing = 180.f-138.189685f;
01351 break;
01352 case 6:
01353
01354 numorient = 32/symmfac;
01355 orientations = new float[3*numorient];
01356 dodecahedron(&orientations[0], &orientations[3*12/symmfac], C2symm);
01357 anglespacing = 37.377380f;
01358 break;
01359 default:
01360
01361 freq -= 5;
01362
01363 numorient = icosahedron_geodesic(orientations, C2symm, freq);
01364
01365 anglespacing = (180.f-138.189685f)/freq;
01366 break;
01367 }
01368
01369
01370
01371
01372 numrot = 1;
01373 if (probe_axisorder1>=0) {
01374 numrot = int(floorf(360.f/probe_axisorder1/anglespacing + 0.5f));
01375 }
01376
01377 int numconf = numorient*numrot;
01378
01379 conform = new float[3*num_probe_atoms*numconf];
01380 memset(conform, 0, 3*num_probe_atoms*numconf*sizeof(float));
01381
01382 #if defined(DEBUG)
01383 Molecule *mol = app->moleculeList->mol_from_id(molid);
01384 MoleculeGraphics *gmol = mol->moleculeGraphics();
01385 for (i=0; i<numorient; i++) {
01386 float dir[3];
01387 vec_scale(dir, 0.8, &orientations[3*i]);
01388 gmol->use_color(7);
01389 if (i==0) gmol->use_color(4);
01390 if (i==1) gmol->use_color(8);
01391 if (i==2) gmol->use_color(9);
01392 gmol->add_sphere(dir, 0.1, 8);
01393 }
01394 #endif
01395
01396
01397 int conf = 0;
01398 for (i=0; i<numorient; i++) {
01399 float *dir = &orientations[3*i];
01400 vec_normalize(dir);
01401
01402 float cross[3], x[3], y[3], z[3];
01403 vec_zero(x); x[0]=1.f;
01404 vec_zero(y); y[1]=1.f;
01405 vec_zero(z); z[2]=1.f;
01406 float phi = 0.f;
01407 float theta = 0.f;
01408
01409 if (!collinear(x, dir, 2.f)) {
01410
01411 cross_prod(cross, x, dir);
01412 phi = angle(dir, x);
01413
01414
01415
01416
01417 float cross2[3];
01418 cross_prod(cross2, x, y);
01419 theta = signed_angle(x, cross2, cross);
01420 } else if (dot_prod(x, dir)<0.f) {
01421
01422 phi = 180.f;
01423 }
01424
01425
01426
01427
01428 int j;
01429 for (j=0; j<numrot; j++) {
01430 Matrix4 m;
01431 float psi = float(j)/float(numrot)*360.f/float(probe_axisorder1);
01432
01433
01434 m.rotate_axis(dir, float(DEGTORAD(psi)));
01435
01436
01437 m.rot(theta, 'x');
01438
01439
01440 m.rotate_axis(z, float(DEGTORAD(phi)));
01441
01442
01443 int k;
01444 for (k=0; k<num_probe_atoms; k++) {
01445 m.multpoint3d(&probe_coords[3*k],
01446 &conform[3*num_probe_atoms*conf + 3*k]);
01447 }
01448
01449 conf++;
01450 }
01451 }
01452
01453 delete [] orientations;
01454
01455
01456 return numconf;
01457 }
01458
01459
01460
01461
01462
01463
01464
01465 void VolMapCreateILS::check_probe_symmetry() {
01466 float principal[3];
01467 if (is_probe_linear(principal)) {
01468 probe_axisorder1 = -1;
01469 vec_copy(probe_symmaxis1, principal);
01470
01471
01472
01473
01474
01475 int Dinfv = 1;
01476 int i, j;
01477 for (i=0; i<num_probe_atoms; i++) {
01478 float image[3];
01479 vec_negate(image, &probe_coords[3*i]);
01480 int match = 1;
01481 for (j=i+1; j<num_probe_atoms; j++) {
01482 if (distance(&probe_coords[3*j], image)>0.05) continue;
01483 if (probe_vdw[2*i ]!=probe_vdw[2*j ] ||
01484 probe_vdw[2*i+1]!=probe_vdw[2*j+1] ||
01485 probe_charge[i]!=probe_charge[j]) {
01486 match = 0;
01487 break;
01488 }
01489 }
01490 if (!match) {
01491 Dinfv = 0;
01492 break;
01493 }
01494 }
01495
01496 if (Dinfv) {
01497
01498 float v[3];
01499 vec_zero(v); v[0] = 1.f;
01500 if (fabs(dot_prod(probe_symmaxis1, v))>0.95) {
01501
01502 v[0] = 0.f; v[1] = 1.f;
01503 }
01504 float cross[3];
01505 cross_prod(cross, probe_symmaxis1, v);
01506 cross_prod(probe_symmaxis2, cross, probe_symmaxis1);
01507 probe_axisorder2 = 2;
01508 }
01509 }
01510 else if (num_probe_atoms==5) {
01511
01512
01513
01514
01515
01516
01517 int i, icenter = -1;
01518 float zero[3];
01519 vec_zero(zero);
01520 for (i=0; i<num_probe_atoms; i++) {
01521 if (distance(&probe_coords[3*i], zero)<0.05) {
01522 icenter = i;
01523 break;
01524 }
01525 }
01526
01527 if (icenter>=0) {
01528 float corner[12];
01529 float vdweps=0.f, vdwrmin=0.f, charge=0.f, dist=0.f;
01530 int match = 1;
01531 int j = 0;
01532
01533
01534
01535 for (i=0; i<num_probe_atoms; i++) {
01536 if (i==icenter) continue;
01537 if (j==0) {
01538 vdweps = probe_vdw[2*i ];
01539 vdwrmin = probe_vdw[2*i+1];
01540 charge = probe_charge[i];
01541 dist = norm(&probe_coords[3*i]);
01542 }
01543 else if (probe_vdw[2*i ] != vdweps ||
01544 probe_vdw[2*i+1] != vdwrmin ||
01545 probe_charge[i] != charge ||
01546 norm(&probe_coords[3*i])-dist > 0.05) {
01547 match = 0;
01548 break;
01549 }
01550
01551 vec_copy(&corner[3*j], &probe_coords[3*i]);
01552 j++;
01553 }
01554
01555
01556 if (match &&
01557 angle(&corner[0], &corner[3])-109.47122f < 5.f &&
01558 angle(&corner[0], &corner[6])-109.47122f < 5.f &&
01559 angle(&corner[0], &corner[9])-109.47122f < 5.f &&
01560 angle(&corner[3], &corner[6])-109.47122f < 5.f &&
01561 angle(&corner[3], &corner[9])-109.47122f < 5.f &&
01562 angle(&corner[6], &corner[9])-109.47122f < 5.f) {
01563 probe_tetrahedralsymm = 1;
01564 probe_axisorder1 = 3;
01565 probe_axisorder2 = 3;
01566 vec_copy(probe_symmaxis1, &corner[0]);
01567 vec_copy(probe_symmaxis2, &corner[3]);
01568 }
01569 }
01570 }
01571 }
01572
01573
01574
01575
01576
01577 void VolMapCreateILS::initialize_probe() {
01578
01579
01580 check_probe_symmetry();
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604 if (probe_axisorder1==1 ||
01605 (probe_axisorder2!=1 && probe_axisorder2!=2)) {
01606
01607 int tmpord = probe_axisorder1;
01608 probe_axisorder1 = probe_axisorder2;
01609 probe_axisorder2 = tmpord;
01610
01611 float tmp[3];
01612 vec_copy(tmp, probe_symmaxis1);
01613 vec_copy(probe_symmaxis1, probe_symmaxis2);
01614 vec_copy(probe_symmaxis2, tmp);
01615 }
01616
01617
01618
01619 Matrix4 rot;
01620 rot.transvecinv(probe_symmaxis1[0], probe_symmaxis1[1], probe_symmaxis1[2]);
01621 int i;
01622 for (i=0; i<num_probe_atoms; i++) {
01623 rot.multpoint3d(&probe_coords[3*i], &probe_coords[3*i]);
01624 }
01625 rot.multpoint3d(probe_symmaxis1, probe_symmaxis1);
01626 rot.multpoint3d(probe_symmaxis2, probe_symmaxis2);
01627
01628
01629 if (probe_axisorder2>1) {
01630 float cross[3], z[3];
01631 vec_zero(z); z[2] = 1.f;
01632 cross_prod(cross, probe_symmaxis1, probe_symmaxis2);
01633
01634 float phi = angle(cross, z);
01635 rot.identity();
01636 rot.rotate_axis(probe_symmaxis1, float(DEGTORAD(phi)));
01637
01638 for (i=0; i<num_probe_atoms; i++) {
01639 rot.multpoint3d(&probe_coords[3*i], &probe_coords[3*i]);
01640 }
01641 rot.multpoint3d(probe_symmaxis1, probe_symmaxis1);
01642 rot.multpoint3d(probe_symmaxis2, probe_symmaxis2);
01643 }
01644
01645
01646 if (getenv("VMDILSNOSYMM")) {
01647
01648
01649 probe_axisorder1 = 1;
01650 probe_axisorder2 = 1;
01651 probe_tetrahedralsymm = 0;
01652 msgWarn << "env(VMDILSNOSYMM) is set: Ignoring probe symmetry!" << sendmsg;
01653 }
01654
01655 num_orientations = 0;
01656 num_rotations = 1;
01657
01658 if (probe_tetrahedralsymm) {
01659 msgInfo << "Probe symmetry: tetrahedral" << sendmsg;
01660
01661 num_conformers = gen_conf_tetrahedral(conformers,
01662 conformer_freq, num_orientations,
01663 num_rotations);
01664 }
01665
01666 else {
01667
01668
01669
01670 if (probe_axisorder1<=1 && probe_axisorder1<=1) {
01671 msgInfo << "Probe symmetry: none" << sendmsg;
01672 }
01673
01674 else if (probe_axisorder1==-1) {
01675 if (probe_axisorder2==2) {
01676 msgInfo << "Probe symmetry: Dinfh (linear, C2)" << sendmsg;
01677 } else {
01678 msgInfo << "Probe symmetry: Cinfv (linear)" << sendmsg;
01679 }
01680 msgInfo << " Probe is linear, generating probe orientations only." << sendmsg;
01681 }
01682 else if (probe_axisorder1>1) {
01683 if (probe_axisorder2==2) {
01684 msgInfo << "Probe symmetry: C" << probe_axisorder1
01685 << ", C2" << sendmsg;
01686 } else {
01687 msgInfo << "Probe symmetry: C" << probe_axisorder1 << sendmsg;
01688 }
01689 msgInfo << " Exploiting C" << probe_axisorder1
01690 << " rotary symmetry for rotation of the oriented probe." << sendmsg;
01691 }
01692
01693 if (probe_axisorder2==2) {
01694 msgInfo << " Exploiting C2 rotary symmetry for probe orientations"
01695 << sendmsg;
01696 }
01697
01698
01699
01700
01701
01702
01703
01704
01705 num_conformers = gen_conf(conformers, conformer_freq,
01706 num_orientations, num_rotations);
01707 }
01708
01709 msgInfo << "Probe orientations: " << num_orientations
01710 << sendmsg;
01711 msgInfo << "Rotamers per orientation: " << num_rotations
01712 << sendmsg;
01713 msgInfo << "Conformers generated: " << num_conformers
01714 << sendmsg << sendmsg;
01715 }
01716
01717
01718
01719
01720
01721 int VolMapCreateILS::box_inside_pbccell(int frame, float *minmaxcoor) {
01722 Matrix4 mat;
01723
01724
01725 measure_pbc2onc(app->moleculeList, molid,
01726 frame, pbccenter, mat);
01727
01728
01729 float box[9];
01730 memset(box, 0, 9*sizeof(float));
01731 box[0] = minmaxcoor[3]-minmaxcoor[0];
01732 box[4] = minmaxcoor[4]-minmaxcoor[1];
01733 box[8] = minmaxcoor[5]-minmaxcoor[2];
01734
01735
01736
01737
01738
01739
01740
01741 float node[8*3];
01742 memset(node, 0, 8*3*sizeof(float));
01743 int n=0;
01744 int i, j, k;
01745 for (i=0; i<=1; i++) {
01746 for (j=0; j<=1; j++) {
01747 for (k=0; k<=1; k++) {
01748 vec_copy(node+3*n, &minmaxcoor[0]);
01749 vec_scaled_add(node+3*n, float(i), &box[0]);
01750 vec_scaled_add(node+3*n, float(j), &box[3]);
01751 vec_scaled_add(node+3*n, float(k), &box[6]);
01752
01753
01754 mat.multpoint3d(node+3*n, node+3*n);
01755 n++;
01756 }
01757 }
01758 }
01759
01760
01761 for (n=0; n<8; n++) {
01762
01763 if (node[3*n ]<0.f) return 0;
01764 if (node[3*n+1]<0.f) return 0;
01765 if (node[3*n+2]<0.f) return 0;
01766 if (node[3*n ]>1.f) return 0;
01767 if (node[3*n+1]>1.f) return 0;
01768 if (node[3*n+2]>1.f) return 0;
01769 }
01770 return 1;
01771 }
01772
01773
01774
01775
01776
01777
01778
01779 int VolMapCreateILS::grid_inside_pbccell(int frame, float *maskvoldata,
01780 const Matrix4 &alignment) {
01781 Matrix4 AA, BB, CC;
01782
01783 Molecule *mol = app->moleculeList->mol_from_id(molid);
01784 mol->get_frame(frame)->get_transforms(AA, BB, CC);
01785
01786
01787 float cella[3], cellb[3], cellc[3];
01788 cella[0] = AA.mat[12];
01789 cella[1] = AA.mat[13];
01790 cella[2] = AA.mat[14];
01791 cellb[0] = BB.mat[12];
01792 cellb[1] = BB.mat[13];
01793 cellb[2] = BB.mat[14];
01794 cellc[0] = CC.mat[12];
01795 cellc[1] = CC.mat[13];
01796 cellc[2] = CC.mat[14];
01797
01798 float normals[3*6];
01799 cross_prod(&normals[0], cella, cellb);
01800 cross_prod(&normals[3], cella, cellc);
01801 cross_prod(&normals[6], cellb, cellc);
01802 vec_normalize(&normals[0]);
01803 vec_normalize(&normals[3]);
01804 vec_normalize(&normals[6]);
01805 vec_scale(&normals[0], cutoff, &normals[0]);
01806 vec_scale(&normals[3], cutoff, &normals[3]);
01807 vec_scale(&normals[6], cutoff, &normals[6]);
01808 vec_negate(&normals[9], &normals[0]);
01809 vec_negate(&normals[12], &normals[3]);
01810 vec_negate(&normals[15], &normals[6]);
01811
01812 Matrix4 pbc2onc;
01813 int allinside = 1;
01814
01815
01816 measure_pbc2onc(app->moleculeList, molid, frame, pbccenter, pbc2onc);
01817
01818
01819
01820
01821 Matrix4 alignmentinv(alignment);
01822 alignmentinv.inverse();
01823
01824 Matrix4 coretransform(pbc2onc);
01825 coretransform.multmatrix(alignmentinv);
01826
01827 float testpos[3], gridpos[3], extgridpos[3];
01828
01829 int n;
01830 for (n=0; n<nsampx*nsampy*nsampz; n++) {
01831
01832 gridpos[0] = float((n%nsampx) *delta + gridorigin[0]);
01833 gridpos[1] = float(((n/nsampx)%nsampy)*delta + gridorigin[1]);
01834 gridpos[2] = float((n/(nsampx*nsampy))*delta + gridorigin[2]);
01835
01836
01837
01838
01839
01840
01841 int i;
01842 for (i=0; i<6; i++) {
01843 vec_add(extgridpos, gridpos, &normals[3*i]);
01844
01845
01846 coretransform.multpoint3d(extgridpos, testpos);
01847 if (testpos[0]<0.f || testpos[0]>1.f ||
01848 testpos[1]<0.f || testpos[1]>1.f ||
01849 testpos[2]<0.f || testpos[2]>1.f) {
01850
01851 maskvoldata[n] = 0.f;
01852 allinside = 0;
01853 i = 6;
01854 }
01855 }
01856 }
01857
01858 return allinside;
01859 }
01860
01861
01870 int VolMapCreateILS::create_unique_paramlist() {
01871 Molecule *mol = app->moleculeList->mol_from_id(molid);
01872
01873
01874 const flint *radius = (flint *) mol->extraflt.data("radius");
01875 if (!radius) return MEASURE_ERR_NORADII;
01876 const flint *occupancy = (flint *) mol->extraflt.data("occupancy");
01877 if (!occupancy) return MEASURE_ERR_NORADII;
01878
01879 int i, j;
01880
01881 #define MAX_UNIQUE_TYPES 200
01882
01883
01884
01885
01886 atomtypes = new int[mol->nAtoms];
01887 atomtypes[0] = 0;
01888 flint *unique_occ = new flint[MAX_UNIQUE_TYPES];
01889 flint *unique_rad = new flint[MAX_UNIQUE_TYPES];
01890 unique_occ[0].f = occupancy[0].f;
01891 unique_rad[0].f = radius[0].f;
01892 num_unique_types = 1;
01893
01894 for (i=1; i<mol->nAtoms; i++) {
01895 int found = 0;
01896
01897
01898 for (j=0; j<num_unique_types; j++) {
01899
01900 if (occupancy[i].i==unique_occ[j].i && radius[i].i==unique_rad[j].i) {
01901 found = 1;
01902 break;
01903 }
01904 }
01905 if (!found) {
01906 if (MAX_UNIQUE_TYPES==num_unique_types) {
01907 msgErr << "Exceeded maximum number " << MAX_UNIQUE_TYPES
01908 << " of unique atom parameter types" << sendmsg;
01909 return -1;
01910 }
01911
01912 unique_occ[j].f = occupancy[i].f;
01913 unique_rad[j].f = radius[i].f;
01914 num_unique_types++;
01915 }
01916 atomtypes[i] = j;
01917 }
01918
01919 vdwparams = new float[2*num_unique_types];
01920 for (j=0; j<num_unique_types; j++) {
01921
01922 if ( !(unique_occ[j].f <= 0.f && unique_rad[j].f > 0.f) ) {
01923 msgErr << "Found invalid VDW parameters " << j
01924 << ": occupancy=" << unique_occ[j].f
01925 << ", radius=" << unique_rad[j].f
01926 << sendmsg;
01927 return -1;
01928 }
01929
01930
01931
01932 vdwparams[2*j ] = sqrtf(-unique_occ[j].f);
01933 vdwparams[2*j+1] = unique_rad[j].f;
01934 }
01935 delete [] unique_occ;
01936 delete [] unique_rad;
01937
01938 msgInfo << "Number of atom types: " << num_unique_types << sendmsg;
01939
01940 #if 0
01941 float *epsilon = new float[mol->nAtoms];
01942 for (i=0; i<mol->nAtoms; i++) {
01943
01944
01945
01946 epsilon[i] = sqrtf(-occupancy[i]);
01947 }
01948
01949 atomtypes = new int[mol->nAtoms];
01950 atomtypes[0] = 0;
01951 float *unique_eps = new float[mol->nAtoms];
01952 float *unique_rad = new float[mol->nAtoms];
01953 unique_eps[0] = epsilon[0];
01954 unique_rad[0] = radius[0];
01955 num_unique_types = 1;
01956
01957 for (i=1; i<mol->nAtoms; i++) {
01958 int found = 0;
01959
01960
01961 for (j=0; j<num_unique_types; j++) {
01962 if (epsilon[i]==unique_eps[j] && radius[i]==unique_rad[j]) {
01963 found = 1;
01964 break;
01965 }
01966 }
01967 if (!found) {
01968
01969 unique_eps[j] = epsilon[i];
01970 unique_rad[j] = radius[i];
01971 num_unique_types++;
01972 }
01973 atomtypes[i] = j;
01974 }
01975
01976 vdwparams = new float[2*num_unique_types];
01977 for (j=0; j<num_unique_types; j++) {
01978 vdwparams[2*j ] = unique_eps[j];
01979 vdwparams[2*j+1] = unique_rad[j];
01980
01981 }
01982 delete [] epsilon;
01983 delete [] unique_eps;
01984 delete [] unique_rad;
01985
01986 msgInfo << "Number of atom types: " << num_unique_types << sendmsg;
01987 #endif
01988
01989 return 0;
01990 }
01991
01992
01993
01994 int VolMapCreateILS::compute() {
01995 int numframes = app->molecule_numframes(molid);
01996 if (first<0 || last>=numframes) return -1;
01997
01998 int err = initialize();
01999 if (err) return err;
02000
02001 int n, frame;
02002 int gridsize = nsampx*nsampy*nsampz;
02003 float *frame_voldata = new float[gridsize];
02004 float *combo_voldata = new float[gridsize];
02005 if (maskonly) {
02006
02007 for (n=0; n<gridsize; n++) {
02008 combo_voldata[n] = 1.f;
02009 frame_voldata[n] = 1.f;
02010 }
02011 } else {
02012 memset(combo_voldata, 0, gridsize*sizeof(float));
02013 }
02014
02015 msgInfo << "Processing frames " << first << "-" << last
02016 << ", " << last-first+1 << " frames in total..." << sendmsg;
02017
02018 computed_frames = 0;
02019
02020 wkf_timerhandle timer = wkf_timer_create();
02021 wkf_timerhandle alltimer = wkf_timer_create();
02022 wkf_timer_start(alltimer);
02023
02024
02025 for (frame=first; frame<=last; frame++) {
02026 msgInfo << "ILS frame " << frame-first+1 << "/" << last-first+1;
02027
02028 #ifdef TIMING
02029 msgInfo << sendmsg;
02030 #else
02031 msgInfo << " ";
02032 #endif
02033
02034 wkf_timer_start(timer);
02035
02036
02037 compute_frame(frame, frame_voldata);
02038
02039 msgInfo << "Total frame time = " << wkf_timer_timenow(timer) << " s" << sendmsg;
02040
02041 if (maskonly) {
02042 for (n=0; n<gridsize; n++) {
02043 combo_voldata[n] *= frame_voldata[n];
02044 }
02045 } else {
02046
02047
02048
02049 int numexcl = 0;
02050 for (n=0; n<gridsize; n++) {
02051 combo_voldata[n] += frame_voldata[n];
02052 if (frame_voldata[n]<=min_occup) numexcl++;
02053 }
02054
02055 }
02056
02057 computed_frames++;
02058 }
02059
02060 double allframetime = wkf_timer_timenow(alltimer);
02061
02062
02063 if (nsubsamp>1||1) {
02064 int ndownsampx = volmap->xsize;
02065 int ndownsampy = volmap->ysize;
02066 int ix, iy, iz;
02067
02068 if (maskonly) {
02069 for (iz=0; iz<nsampz; iz++) {
02070 int isubz = iz/nsubsamp*ndownsampy*ndownsampx;
02071 for (iy=0; iy<nsampy; iy++) {
02072 int isuby = iy/nsubsamp*ndownsampx;
02073 for (ix=0; ix<nsampx; ix++) {
02074 n = iz*nsampy*nsampx + iy*nsampx + ix;
02075 float val = combo_voldata[n];
02076 int m = isubz + isuby + ix/nsubsamp;
02077
02078
02079 volmap->data[m] *= val;
02080 }
02081 }
02082 }
02083
02084 } else {
02085 for (iz=0; iz<nsampz; iz++) {
02086 int isubz = iz/nsubsamp*ndownsampy*ndownsampx;
02087 for (iy=0; iy<nsampy; iy++) {
02088 int isuby = iy/nsubsamp*ndownsampx;
02089 for (ix=0; ix<nsampx; ix++) {
02090 n = iz*nsampy*nsampx + iy*nsampx + ix;
02091 float val = combo_voldata[n];
02092 int m = isubz + isuby + ix/nsubsamp;
02093
02094 volmap->data[m] += val;
02095 }
02096 }
02097 }
02098
02099
02100
02101 float nsamppercell = float(nsubsamp*nsubsamp*nsubsamp*computed_frames);
02102 for (n=0; n<volmap->gridsize(); n++) {
02103 volmap->data[n] = volmap->data[n]/nsamppercell;
02104 }
02105 }
02106
02107 if (!maskonly) {
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117 for (n=0; n<volmap->gridsize(); n++) {
02118 float val = volmap->data[n];
02119 if (val<=min_occup) {
02120 volmap->data[n] = max_energy;
02121 } else {
02122 val = -logf(val);
02123 if (val > max_energy) val = max_energy;
02124 volmap->data[n] = val;
02125 }
02126 }
02127 }
02128 }
02129
02130 delete[] frame_voldata;
02131 delete[] combo_voldata;
02132
02133 msgInfo << "#################################################"
02134 << sendmsg << sendmsg;
02135 msgInfo << "Total time for all frames = "
02136 << allframetime << " s" << sendmsg;
02137 msgInfo << "Avg time per frame = "
02138 << allframetime/(last-first+1) << " s" << sendmsg;
02139 msgInfo << "Downsampling = "
02140 << wkf_timer_timenow(alltimer)-allframetime << " s"
02141 << sendmsg << sendmsg;
02142 msgInfo << "#################################################"
02143 << sendmsg << sendmsg;
02144
02145 wkf_timer_destroy(timer);
02146 wkf_timer_destroy(alltimer);
02147
02148 return 0;
02149 }
02150
02151
02152
02153
02154 void VolMapCreateILS::align_frame(Molecule *mol, int frame, float *coords,
02155 Matrix4 &alignment) {
02156
02157
02158 if (alignsel) {
02159 int i;
02160 int save_frame_alignsel = alignsel->which_frame;
02161
02162 alignsel->which_frame = frame;
02163 alignsel->change(NULL, mol);
02164
02165 float *weight = new float[alignsel->selected];
02166 for (i=0; i<alignsel->selected; i++) weight[i] = 1.0;
02167
02168 measure_fit(alignsel, alignsel, coords, alignrefpos, weight, NULL, &alignment);
02169 delete[] weight;
02170
02171 if (!getenv("VMDILSALIGNMAPS")) {
02172
02173
02174
02175 for (i=0; i < mol->nAtoms; i++) {
02176 alignment.multpoint3d(coords, coords);
02177 coords += 3;
02178 }
02179 }
02180
02181 alignsel->which_frame = save_frame_alignsel;
02182 }
02183
02184
02185 alignment.multmatrix(transform);
02186 }
02187
02188
02189
02190
02191
02192
02193
02194 int VolMapCreateILS::get_atom_coordinates(int frame, Matrix4 &alignment,
02195 int *(&vdwtypes),
02196 float *(&coords)) {
02197 wkf_timerhandle timer = wkf_timer_create();
02198 wkf_timer_start(timer);
02199
02200
02201
02202 int *selon = new int[num_atoms];
02203 memset(selon, 0, num_atoms*sizeof(int));
02204
02205 float minx = minmax[0]-extcutoff;
02206 float miny = minmax[1]-extcutoff;
02207 float minz = minmax[2]-extcutoff;
02208 float maxx = minmax[3]+extcutoff;
02209 float maxy = minmax[4]+extcutoff;
02210 float maxz = minmax[5]+extcutoff;
02211
02212 int numselected = 0;
02213 int i;
02214 for (i=0; i<num_atoms; i++) {
02215 float x = coords[3*i ];
02216 float y = coords[3*i+1];
02217 float z = coords[3*i+2];
02218 if (x>=minx && x<=maxx &&
02219 y>=miny && y<=maxy &&
02220 z>=minz && z<=maxz) {
02221 selon[i] = 1;
02222 numselected++;
02223 }
02224 }
02225
02226 int numcoords = numselected;
02227
02228 float *selcoords = NULL;
02229
02230
02231
02232
02233 if (pbc) {
02234
02235 float ffcutoff[3];
02236 ffcutoff[0] = ffcutoff[1] = ffcutoff[2] = cutoff;
02237
02238
02239 ResizeArray<float> extcoord_array;
02240
02241
02242
02243 ResizeArray<int> indexmap_array;
02244
02245
02246
02247
02248
02249
02250
02251
02252
02253 measure_pbc_neighbors(app->moleculeList, NULL, molid, frame,
02254 &alignment, pbccenter, ffcutoff, minmax,
02255 &extcoord_array, &indexmap_array);
02256
02257 numcoords = numselected+indexmap_array.num();
02258
02259 selcoords = new float[3*numcoords];
02260 vdwtypes = new int[numcoords];
02261
02262 int j = numselected;
02263 for (i=0; i<indexmap_array.num(); i++) {
02264 selcoords[3*j ] = extcoord_array[3*i ];
02265 selcoords[3*j+1] = extcoord_array[3*i+1];
02266 selcoords[3*j+2] = extcoord_array[3*i+2];
02267 vdwtypes[j] = atomtypes[indexmap_array[i]];
02268 j++;
02269 }
02270
02271
02272 } else {
02273 selcoords = new float[3*numcoords];
02274 vdwtypes = new int[numcoords];
02275 }
02276
02277
02278 int j=0;
02279 for (i=0; i<num_atoms; i++) {
02280 if (!selon[i]) continue;
02281 selcoords[3*j ] = coords[3*i ];
02282 selcoords[3*j+1] = coords[3*i+1];
02283 selcoords[3*j+2] = coords[3*i+2];
02284 vdwtypes[j] = atomtypes[i];
02285 j++;
02286 }
02287
02288
02289 coords = selcoords;
02290
02291 delete [] selon;
02292
02293 #ifdef TIMING
02294 msgInfo << "Coord setup: " << wkf_timer_timenow(timer) << " s" << sendmsg;
02295 #endif
02296 wkf_timer_destroy(timer);
02297
02298 return numcoords;
02299 }
02300
02301
02302
02304
02306
02307
02308 int VolMapCreateILS::compute_frame(int frame, float *voldata) {
02309 Matrix4 alignment;
02310 float *coords;
02311
02312 Molecule *mol = app->moleculeList->mol_from_id(molid);
02313 if (!mol) return -1;
02314
02315 #ifdef TIMING
02316 char report[128];
02317 wkf_timerhandle timer = wkf_timer_create();
02318 #endif
02319
02320
02321 coords = mol->get_frame(frame)->pos;
02322
02323
02324
02325
02326 align_frame(mol, frame, coords, alignment);
02327
02328 if (maskonly) {
02329 #ifdef TIMING
02330 wkf_timer_start(timer);
02331 #endif
02332
02333
02334
02335
02336
02337 grid_inside_pbccell(frame, voldata, alignment);
02338
02339 #ifdef TIMING
02340 msgInfo << "Masking: " << wkf_timer_timenow(timer) << " s" << sendmsg;
02341 #endif
02342
02343 return MEASURE_NOERR;
02344 }
02345
02346
02347
02348
02349
02350 int *vdwtypes = NULL;
02351 int numcoords;
02352 float originalign[3];
02353 float axesalign[9];
02354 float gridaxes[9];
02355 memset(gridaxes, 0, 9*sizeof(float));
02356 gridaxes[0] = gridaxes[4] = gridaxes[8] = 1.f;
02357
02358 if (getenv("VMDILSALIGNMAPS")) {
02359
02360 numcoords = num_atoms;
02361 vdwtypes = atomtypes;
02362 alignment.multpoint3d(gridorigin, originalign);
02363 alignment.multpoint3d(&gridaxes[0], &axesalign[0]);
02364 alignment.multpoint3d(&gridaxes[3], &axesalign[3]);
02365 alignment.multpoint3d(&gridaxes[6], &axesalign[6]);
02366 msgInfo << "Aligning maps." << sendmsg;
02367 } else {
02368
02369 numcoords = get_atom_coordinates(frame, alignment,
02370 vdwtypes, coords);
02371 memcpy(originalign, gridorigin, 3*sizeof(float));
02372 memcpy(axesalign, gridaxes, 9*sizeof(float));
02373 msgInfo << "Aligning frames." << sendmsg;
02374 }
02375
02376 if (getenv("VMDALLATOMILS")) {
02377 #ifdef TIMING
02378 wkf_timer_start(timer);
02379 #endif
02380
02381
02382 float lenx = float(nsampx*delta);
02383 float leny = float(nsampy*delta);
02384 float lenz = float(nsampz*delta);
02385
02386 compute_allatoms(voldata, nsampx, nsampy, nsampz,
02387 lenx, leny, lenz, originalign, axesalign,
02388 alignment.mat, numcoords, coords,
02389 vdwtypes, vdwparams, cutoff, probe_vdw, num_probe_atoms,
02390 num_conformers, conformers, max_energy);
02391
02392 #ifdef TIMING
02393 sprintf(report, "compute_allatoms() "
02394 "%f s\n", wkf_timer_timenow(timer));
02395 msgInfo << report << sendmsg;
02396 #endif
02397
02398 } else {
02399
02400 #ifdef TIMING
02401 wkf_timer_start(timer);
02402 #endif
02403
02404
02405 float lenx = float(nsampx*delta);
02406 float leny = float(nsampy*delta);
02407 float lenz = float(nsampz*delta);
02408
02409 int retval;
02410
02411 ComputeOccupancyMap om;
02412
02413
02414 om.map = voldata;
02415 om.mx = nsampx;
02416 om.my = nsampy;
02417 om.mz = nsampz;
02418 om.lx = lenx;
02419 om.ly = leny;
02420 om.lz = lenz;
02421 om.x0 = originalign[0];
02422 om.y0 = originalign[1];
02423 om.z0 = originalign[2];
02424 memcpy(om.ax, &axesalign[0], 3*sizeof(float));
02425 memcpy(om.ay, &axesalign[3], 3*sizeof(float));
02426 memcpy(om.az, &axesalign[6], 3*sizeof(float));
02427 memcpy(om.alignmat, alignment.mat, 16*sizeof(float));
02428 om.num_coords = numcoords;
02429 om.coords = coords;
02430 om.vdw_type = vdwtypes;
02431 om.vdw_params = vdwparams;
02432 om.probe_vdw_params = probe_vdw;
02433 om.conformers = conformers;
02434 om.num_probes = num_probe_atoms;
02435 om.num_conformers = num_conformers;
02436 om.cutoff = cutoff;
02437 om.extcutoff = extcutoff;
02438 om.excl_dist = excl_dist;
02439 om.excl_energy = max_energy;
02440
02441
02442 om.kstart = 0;
02443 om.kstop = om.mz;
02444
02445 retval = ComputeOccupancyMap_setup(&om);
02446
02447 #ifdef TIMING
02448 sprintf(report, "ComputeOccupancyMap_setup() "
02449 "%f s\n", wkf_timer_timenow(timer));
02450 msgInfo << report << sendmsg;
02451 #endif
02452
02453 if (getenv("VMDILSVERBOSE")) {
02454 atom_bin_stats(&om
02455
02456
02457
02458 );
02459 }
02460
02461 if (retval != 0) {
02462 if (getenv("VMDILSVERBOSE")) {
02463 int i, j, k;
02464 int total_extra_atoms = 0;
02465 for (k = 0; k < om.nbz; k++) {
02466 for (j = 0; j < om.nby; j++) {
02467 for (i = 0; i < om.nbx; i++) {
02468 int index = (k*om.nby + j)*om.nbx + i;
02469 if (om.bincnt[index] > BIN_DEPTH) {
02470 printf("*** bin[%d,%d,%d] tried to fill with %d atoms\n",
02471 i, j, k, om.bincnt[index]);
02472 total_extra_atoms += om.bincnt[index] - BIN_DEPTH;
02473 }
02474 }
02475 }
02476 }
02477
02478 printf("*** can't handle total of %d extra atoms\n", total_extra_atoms);
02479 }
02480 ComputeOccupancyMap_cleanup(&om);
02481 return -1;
02482 }
02483
02484 #if defined(VMDCUDA)
02485 if (getenv("VMDILSVERBOSE")) {
02486 printf("*** cpu only = %d\n", om.cpu_only);
02487 }
02488 if (!getenv("VMDNOCUDA") && !(om.cpu_only) &&
02489 (retval=
02490 vmd_cuda_evaluate_occupancy_map(om.mx, om.my, om.mz, om.map,
02491 om.excl_energy, om.cutoff, om.hx, om.hy, om.hz,
02492 om.x0, om.y0, om.z0, om.bx_1, om.by_1, om.bz_1,
02493 om.nbx, om.nby, om.nbz, (float *) om.bin, (float *) om.bin_zero,
02494 om.num_bin_offsets, om.bin_offsets,
02495 om.num_extras, (float *) om.extra,
02496 num_unique_types, om.vdw_params,
02497 om.num_probes, om.probe_vdw_params,
02498 om.num_conformers, om.conformers)) == 0) {
02499
02500 } else {
02501 if (retval != 0) {
02502 msgInfo << "vmd_cuda_evaluate_occupancy_map() FAILED,"
02503 " using CPU for calculation\n" << sendmsg;
02504 }
02505 #endif
02506
02507 #ifdef TIMING
02508 wkf_timer_start(timer);
02509 #endif
02510
02511 retval = ComputeOccupancyMap_calculate_slab(&om);
02512
02513 #ifdef TIMING
02514 sprintf(report, "ComputeOccupancyMap_calculate_slab() "
02515 "%f s\n", wkf_timer_timenow(timer));
02516 msgInfo << report << sendmsg;
02517 #endif
02518
02519 if (retval != 0) {
02520 if (getenv("VMDILSVERBOSE")) {
02521 printf("*** ComputeOccupancyMap_calculate_slab() failed\n");
02522 }
02523 ComputeOccupancyMap_cleanup(&om);
02524 return -1;
02525 }
02526
02527 #if defined(VMDCUDA)
02528 }
02529 #endif
02530
02531 ComputeOccupancyMap_cleanup(&om);
02532 }
02533
02534 if (!getenv("VMDILSALIGNMAPS")) {
02535 delete[] coords;
02536 delete[] vdwtypes;
02537 }
02538
02539 #ifdef TIMING
02540 wkf_timer_destroy(timer);
02541 #endif
02542
02543 return MEASURE_NOERR;
02544 }
02545
02546
02548
02550
02551 static int fill_atom_bins(ComputeOccupancyMap *p);
02552 static void tighten_bin_neighborhood(ComputeOccupancyMap *p);
02553 static void find_distance_exclusions(ComputeOccupancyMap *p);
02554 static void find_energy_exclusions(ComputeOccupancyMap *p);
02555 static void compute_occupancy_monoatom(ComputeOccupancyMap *p);
02556 static void compute_occupancy_multiatom(ComputeOccupancyMap *p);
02557
02558
02559 int ComputeOccupancyMap_setup(ComputeOccupancyMap *p) {
02560
02561
02562 p->bin = NULL;
02563 p->bin_zero = NULL;
02564 p->bincnt = NULL;
02565 p->bincnt_zero = NULL;
02566 p->bin_offsets = NULL;
02567 p->extra = NULL;
02568 p->exclusions = NULL;
02569
02570
02571 int mtotal = p->mx * p->my * p->mz;
02572 memset(p->map, 0, mtotal * sizeof(float));
02573 p->exclusions = new char[mtotal];
02574 memset(p->exclusions, 0, mtotal * sizeof(char));
02575
02576
02577 p->hx = p->lx / p->mx;
02578 p->hy = p->ly / p->my;
02579 p->hz = p->lz / p->mz;
02580
02581 p->cpu_only = 0;
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591 p->mpblx = 12;
02592 p->mpbly = 12;
02593 p->mpblz = 12;
02594
02595
02596 p->bx = p->mpblx * p->hx;
02597 p->by = p->mpbly * p->hy;
02598 p->bz = p->mpblz * p->hz;
02599
02600
02601 while (p->bx * p->by * p->bz > MAX_BIN_VOLUME) {
02602
02603
02604 if (p->bx > p->by && p->bx > p->bz) {
02605 p->mpblx -= 4;
02606 p->bx = p->mpblx * p->hx;
02607 }
02608 else if (p->by >= p->bx && p->by > p->bz) {
02609 p->mpbly -= 4;
02610 p->by = p->mpbly * p->hy;
02611 }
02612 else {
02613 p->mpblz -= 4;
02614 p->bz = p->mpblz * p->hz;
02615 }
02616
02617 }
02618
02619 if (p->bx * p->by * p->bz < MIN_BIN_VOLUME) {
02620
02621
02622 p->bx = p->by = p->bz = DEFAULT_BIN_LENGTH;
02623 p->mpblx = p->mpbly = p->mpblz = 0;
02624 p->cpu_only = 1;
02625 }
02626
02627 p->bx_1 = 1.f / p->bx;
02628 p->by_1 = 1.f / p->by;
02629 p->bz_1 = 1.f / p->bz;
02630
02631 if (fill_atom_bins(p)) {
02632 return -1;
02633 }
02634
02635 tighten_bin_neighborhood(p);
02636
02637 return 0;
02638 }
02639
02640
02641 int ComputeOccupancyMap_calculate_slab(ComputeOccupancyMap *p) {
02642 #ifdef TIMING
02643 char report[128];
02644 wkf_timerhandle timer = wkf_timer_create();
02645 #endif
02646
02647
02648
02649
02650
02651
02652 #if 1
02653 #ifdef TIMING
02654 wkf_timer_start(timer);
02655 #endif
02656 find_distance_exclusions(p);
02657 int i, numexcl=0;
02658 for (i=0; i<p->mx * p->my * p->mz; i++) {
02659 if (p->exclusions[i]) numexcl++;
02660 }
02661 #ifdef TIMING
02662 sprintf(report, "ComputeOccupancyMap: find_distance_exclusions() "
02663 "%f s\n", wkf_timer_timenow(timer));
02664 msgInfo << report << sendmsg;
02665 #endif
02666 #endif
02667
02668 if (1 == p->num_probes) {
02669 #ifdef TIMING
02670 wkf_timer_start(timer);
02671 #endif
02672 compute_occupancy_monoatom(p);
02673 #ifdef TIMING
02674 sprintf(report, "ComputeOccupancyMap: compute_occupancy_monoatom() "
02675 "%f s\n", wkf_timer_timenow(timer));
02676 msgInfo << report << sendmsg;
02677 #endif
02678
02679 }
02680 else {
02681
02682 #if 1
02683 #ifdef TIMING
02684 wkf_timer_start(timer);
02685 #endif
02686 find_energy_exclusions(p);
02687 int i, numexcl=0;
02688 for (i=0; i<p->mx * p->my * p->mz; i++) {
02689 if (p->exclusions[i]) numexcl++;
02690 }
02691 #ifdef TIMING
02692 sprintf(report, "ComputeOccupancyMap: find_energy_exclusions() "
02693 "%f s -> %d exclusions\n", wkf_timer_timenow(timer), numexcl);
02694 msgInfo << report << sendmsg;
02695 #endif
02696 #endif
02697
02698 #ifdef TIMING
02699 wkf_timer_start(timer);
02700 #endif
02701 compute_occupancy_multiatom(p);
02702 #ifdef TIMING
02703 sprintf(report, "ComputeOccupancyMap: compute_occupancy_multiatom() "
02704 "%f s\n", wkf_timer_timenow(timer));
02705 msgInfo << report << sendmsg;
02706 #endif
02707
02708 }
02709
02710 #ifdef TIMING
02711 wkf_timer_destroy(timer);
02712 #endif
02713
02714 return 0;
02715 }
02716
02717
02718 void ComputeOccupancyMap_cleanup(ComputeOccupancyMap *p) {
02719 delete[] p->bin_offsets;
02720 delete[] p->extra;
02721 delete[] p->bincnt;
02722 delete[] p->bin;
02723 delete[] p->exclusions;
02724 }
02725
02726
02727
02728
02729 #define MAX_EXTRA_ATOMS 50
02730
02731 int fill_atom_bins(ComputeOccupancyMap *p) {
02732 int too_many_extra_atoms = 0;
02733 int max_extra_atoms = MAX_EXTRA_ATOMS;
02734
02735
02736 int count_extras = 0;
02737 int n, i, j, k;
02738
02739 const int *vdw_type = p->vdw_type;
02740 const float *coords = p->coords;
02741 const int num_coords = p->num_coords;
02742 const float lx = p->lx;
02743 const float ly = p->ly;
02744 const float lz = p->lz;
02745 const float bx_1 = p->bx_1;
02746 const float by_1 = p->by_1;
02747 const float bz_1 = p->bz_1;
02748 const float x0 = p->x0;
02749 const float y0 = p->y0;
02750 const float z0 = p->z0;
02751 const float extcutoff = p->extcutoff;
02752
02753
02754 p->padx = (int) ceilf(extcutoff * bx_1);
02755 p->pady = (int) ceilf(extcutoff * by_1);
02756 p->padz = (int) ceilf(extcutoff * bz_1);
02757
02758 const int nbx = p->nbx = (int) ceilf(lx * bx_1) + 2*p->padx;
02759 const int nby = p->nby = (int) ceilf(ly * by_1) + 2*p->pady;
02760 p->nbz = (int) ceilf(lz * bz_1) + 2*p->padz;
02761
02762 int nbins = nbx * nby * p->nbz;
02763
02764 BinOfAtoms *bin = p->bin = new BinOfAtoms[nbins];
02765 char *bincnt = p->bincnt = new char[nbins];
02766 AtomPosType *extra = p->extra = new AtomPosType[max_extra_atoms];
02767
02768 memset(bin, 0, nbins * sizeof(BinOfAtoms));
02769 memset(bincnt, 0, nbins * sizeof(char));
02770
02771
02772
02773 BinOfAtoms *bin_zero
02774 = p->bin_zero = bin + ((p->padz*nby + p->pady)*nbx + p->padx);
02775 char *bincnt_zero
02776 = p->bincnt_zero = bincnt + ((p->padz*nby + p->pady)*nbx + p->padx);
02777
02778 for (n = 0; n < num_coords; n++) {
02779 float x = coords[3*n ];
02780 float y = coords[3*n + 1];
02781 float z = coords[3*n + 2];
02782
02783 float sx = x - x0;
02784 float sy = y - y0;
02785 float sz = z - z0;
02786
02787 if (sx < -extcutoff || sx > lx + extcutoff ||
02788 sy < -extcutoff || sy > ly + extcutoff ||
02789 sz < -extcutoff || sz > lz + extcutoff) {
02790 continue;
02791 }
02792
02793 i = (int) floorf(sx * bx_1);
02794 j = (int) floorf(sy * by_1);
02795 k = (int) floorf(sz * bz_1);
02796
02797
02798
02799
02800
02801
02802
02803
02804
02805
02806 int index = (k*nby + j)*nbx + i;
02807 int slot = bincnt_zero[index];
02808
02809 if (slot < BIN_DEPTH) {
02810 AtomPosType *atom = bin_zero[index].atom;
02811 atom[slot].x = x;
02812 atom[slot].y = y;
02813 atom[slot].z = z;
02814 atom[slot].vdwtype = vdw_type[n];
02815 }
02816 else if (count_extras < max_extra_atoms) {
02817 extra[count_extras].x = x;
02818 extra[count_extras].y = y;
02819 extra[count_extras].z = z;
02820 extra[count_extras].vdwtype = vdw_type[n];
02821 count_extras++;
02822 }
02823 else {
02824
02825 printf("*** too many extras, atom index %d\n", n);
02826 too_many_extra_atoms = 1;
02827 }
02828
02829 bincnt_zero[index]++;
02830 }
02831 p->num_extras = count_extras;
02832
02833
02834
02835 for (n = 0; n < nbins; n++) {
02836 for (k = bincnt[n]; k < BIN_DEPTH; k++) {
02837 bin[n].atom[k].vdwtype = -1;
02838 }
02839 }
02840
02841 return (too_many_extra_atoms ? -1 : 0);
02842 }
02843
02844
02845
02846 void tighten_bin_neighborhood(ComputeOccupancyMap *p) {
02847 const int padx = p->padx;
02848 const int pady = p->pady;
02849 const int padz = p->padz;
02850 const float bx2 = p->bx * p->bx;
02851 const float by2 = p->by * p->by;
02852 const float bz2 = p->bz * p->bz;
02853 const float r = p->extcutoff + sqrtf(bx2 + by2 + bz2);
02854 const float r2 = r*r;
02855 int n = 0, i, j, k;
02856 char *bin_offsets
02857 = p->bin_offsets = new char[3 * (2*padx+1)*(2*pady+1)*(2*padz+1)];
02858 for (k = -padz; k <= padz; k++) {
02859 for (j = -pady; j <= pady; j++) {
02860 for (i = -padx; i <= padx; i++) {
02861 if (i*i*bx2 + j*j*by2 + k*k*bz2 >= r2) continue;
02862 bin_offsets[3*n ] = (char) i;
02863 bin_offsets[3*n + 1] = (char) j;
02864 bin_offsets[3*n + 2] = (char) k;
02865 n++;
02866 }
02867 }
02868 }
02869 p->num_bin_offsets = n;
02870 }
02871
02872
02873
02874
02875
02876
02877
02878 void find_distance_exclusions(ComputeOccupancyMap *p) {
02879 const AtomPosType *extra = p->extra;
02880 const BinOfAtoms *bin_zero = p->bin_zero;
02881 char *excl = p->exclusions;
02882
02883 int i, j, k, n, index;
02884 int ic, jc, kc;
02885
02886 const int mx = p->mx;
02887 const int my = p->my;
02888 const int kstart = p->kstart;
02889 const int kstop = p->kstop;
02890 const int nbx = p->nbx;
02891 const int nby = p->nby;
02892 const float excl_dist = p->excl_dist;
02893 const float bx_1 = p->bx_1;
02894 const float by_1 = p->by_1;
02895 const float bz_1 = p->bz_1;
02896 const float hx = p->hx;
02897 const float hy = p->hy;
02898 const float hz = p->hz;
02899 const float x0 = p->x0;
02900 const float y0 = p->y0;
02901 const float z0 = p->z0;
02902 const int num_extras = p->num_extras;
02903 const int bdx = (int) ceilf(excl_dist * bx_1);
02904 const int bdy = (int) ceilf(excl_dist * by_1);
02905 const int bdz = (int) ceilf(excl_dist * bz_1);
02906 const float excldist2 = excl_dist * excl_dist;
02907
02908 for (k = kstart; k < kstop; k++) {
02909 for (j = 0; j < my; j++) {
02910 for (i = 0; i < mx; i++) {
02911
02912 float px = i*hx;
02913 float py = j*hy;
02914 float pz = k*hz;
02915
02916 int ib = (int) floorf(px * bx_1);
02917 int jb = (int) floorf(py * by_1);
02918 int kb = (int) floorf(pz * bz_1);
02919
02920 px += x0;
02921 py += y0;
02922 pz += z0;
02923
02924 for (kc = kb - bdz; kc <= kb + bdz; kc++) {
02925 for (jc = jb - bdy; jc <= jb + bdy; jc++) {
02926 for (ic = ib - bdx; ic <= ib + bdx; ic++) {
02927
02928 const AtomPosType *atom
02929 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
02930
02931 for (n = 0; n < BIN_DEPTH; n++) {
02932 if (-1 == atom[n].vdwtype) break;
02933 float dx = px - atom[n].x;
02934 float dy = py - atom[n].y;
02935 float dz = pz - atom[n].z;
02936 float r2 = dx*dx + dy*dy + dz*dz;
02937 if (r2 <= excldist2) {
02938 index = (k*my + j)*mx + i;
02939 excl[index] = 1;
02940 goto NEXT_MAP_POINT;
02941 }
02942 }
02943
02944 }
02945 }
02946 }
02947
02948 for (n = 0; n < num_extras; n++) {
02949 float dx = px - extra[n].x;
02950 float dy = py - extra[n].y;
02951 float dz = pz - extra[n].z;
02952 float r2 = dx*dx + dy*dy + dz*dz;
02953 if (r2 <= excldist2) {
02954 index = (k*my + j)*mx + i;
02955 excl[index] = 1;
02956 goto NEXT_MAP_POINT;
02957 }
02958 }
02959
02960 NEXT_MAP_POINT:
02961 ;
02962
02963 }
02964 }
02965 }
02966
02967 }
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977 void find_energy_exclusions(ComputeOccupancyMap *p) {
02978 const char *bin_offsets = p->bin_offsets;
02979 const float *vdw_params = p->vdw_params;
02980 const AtomPosType *extra = p->extra;
02981 const BinOfAtoms *bin_zero = p->bin_zero;
02982 char *excl = p->exclusions;
02983
02984 const float probe_vdweps = p->probe_vdw_params[0];
02985 const float probe_vdwrmin = p->probe_vdw_params[1];
02986
02987 const int mx = p->mx;
02988 const int my = p->my;
02989 const int kstart = p->kstart;
02990 const int kstop = p->kstop;
02991 const int nbx = p->nbx;
02992 const int nby = p->nby;
02993 const float hx = p->hx;
02994 const float hy = p->hy;
02995 const float hz = p->hz;
02996 const float bx_1 = p->bx_1;
02997 const float by_1 = p->by_1;
02998 const float bz_1 = p->bz_1;
02999 const float x0 = p->x0;
03000 const float y0 = p->y0;
03001 const float z0 = p->z0;
03002 const int num_bin_offsets = p->num_bin_offsets;
03003 const int num_extras = p->num_extras;
03004 const float excl_energy = p->excl_energy;
03005
03006 int i, j, k, n, index;
03007 const float cutoff2 = p->cutoff * p->cutoff;
03008
03009 for (k = kstart; k < kstop; k++) {
03010 for (j = 0; j < my; j++) {
03011 for (i = 0; i < mx; i++) {
03012
03013 int lindex = (k*my + j)*mx + i;
03014 if (excl[lindex]) continue;
03015
03016 float px = i*hx;
03017 float py = j*hy;
03018 float pz = k*hz;
03019
03020 int ib = (int) floorf(px * bx_1);
03021 int jb = (int) floorf(py * by_1);
03022 int kb = (int) floorf(pz * bz_1);
03023
03024 px += x0;
03025 py += y0;
03026 pz += z0;
03027
03028 float u = 0.f;
03029
03030 for (index = 0; index < num_bin_offsets; index++) {
03031 int ic = ib + (int) bin_offsets[3*index ];
03032 int jc = jb + (int) bin_offsets[3*index + 1];
03033 int kc = kb + (int) bin_offsets[3*index + 2];
03034
03035 const AtomPosType *atom
03036 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03037
03038 for (n = 0; n < BIN_DEPTH; n++) {
03039 if (-1 == atom[n].vdwtype) break;
03040 float dx = px - atom[n].x;
03041 float dy = py - atom[n].y;
03042 float dz = pz - atom[n].z;
03043 float r2 = dx*dx + dy*dy + dz*dz;
03044 if (r2 >= cutoff2) continue;
03045 int pindex = 2 * atom[n].vdwtype;
03046 float epsilon = vdw_params[pindex] * probe_vdweps;
03047 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03048 float rm6 = rmin*rmin / r2;
03049 rm6 = rm6 * rm6 * rm6;
03050 u += epsilon * rm6 * (rm6 - 2.f);
03051 }
03052
03053 }
03054
03055 for (n = 0; n < num_extras; n++) {
03056 float dx = px - extra[n].x;
03057 float dy = py - extra[n].y;
03058 float dz = pz - extra[n].z;
03059 float r2 = dx*dx + dy*dy + dz*dz;
03060 if (r2 >= cutoff2) continue;
03061 int pindex = 2 * extra[n].vdwtype;
03062 float epsilon = vdw_params[pindex] * probe_vdweps;
03063 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03064 float rm6 = rmin*rmin / r2;
03065 rm6 = rm6 * rm6 * rm6;
03066 u += epsilon * rm6 * (rm6 - 2.f);
03067 }
03068
03069 if (u >= excl_energy) excl[lindex] = 1;
03070
03071 }
03072 }
03073 }
03074
03075 }
03076
03077
03078
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088 void compute_occupancy_monoatom(ComputeOccupancyMap *p) {
03089 const char *bin_offsets = p->bin_offsets;
03090 const float *vdw_params = p->vdw_params;
03091 const AtomPosType *extra = p->extra;
03092 const BinOfAtoms *bin_zero = p->bin_zero;
03093 const char *excl = p->exclusions;
03094 float *map = p->map;
03095
03096 const int mx = p->mx;
03097 const int my = p->my;
03098 const int kstart = p->kstart;
03099 const int kstop = p->kstop;
03100 const int nbx = p->nbx;
03101 const int nby = p->nby;
03102 const float hx = p->hx;
03103 const float hy = p->hy;
03104 const float hz = p->hz;
03105 const float bx_1 = p->bx_1;
03106 const float by_1 = p->by_1;
03107 const float bz_1 = p->bz_1;
03108 const float x0 = p->x0;
03109 const float y0 = p->y0;
03110 const float z0 = p->z0;
03111 const int num_bin_offsets = p->num_bin_offsets;
03112 const int num_extras = p->num_extras;
03113
03114 float probe_vdweps = p->probe_vdw_params[0];
03115 float probe_vdwrmin = p->probe_vdw_params[1];
03116
03117 int i, j, k, n, index;
03118 float max_energy = p->excl_energy;
03119 float cutoff2 = p->cutoff * p->cutoff;
03120
03121 for (k = kstart; k < kstop; k++) {
03122 for (j = 0; j < my; j++) {
03123 for (i = 0; i < mx; i++) {
03124
03125 int lindex = (k*my + j)*mx + i;
03126 #if 1
03127 if (excl[lindex]) {
03128 map[lindex] = 0.f;
03129 continue;
03130 }
03131 #endif
03132
03133 float px = i*hx;
03134 float py = j*hy;
03135 float pz = k*hz;
03136
03137 int ib = (int) floorf(px * bx_1);
03138 int jb = (int) floorf(py * by_1);
03139 int kb = (int) floorf(pz * bz_1);
03140
03141 px += x0;
03142 py += y0;
03143 pz += z0;
03144
03145 float u = 0.f;
03146
03147 for (index = 0; index < num_bin_offsets; index++) {
03148 int ic = ib + (int) bin_offsets[3*index ];
03149 int jc = jb + (int) bin_offsets[3*index + 1];
03150 int kc = kb + (int) bin_offsets[3*index + 2];
03151
03152 const AtomPosType *atom
03153 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03154
03155 for (n = 0; n < BIN_DEPTH; n++) {
03156 if (-1 == atom[n].vdwtype) break;
03157 float dx = px - atom[n].x;
03158 float dy = py - atom[n].y;
03159 float dz = pz - atom[n].z;
03160 float r2 = dx*dx + dy*dy + dz*dz;
03161 if (r2 >= cutoff2) continue;
03162 int pindex = 2 * atom[n].vdwtype;
03163 float epsilon = vdw_params[pindex] * probe_vdweps;
03164 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03165 float rm6 = rmin*rmin / r2;
03166 rm6 = rm6 * rm6 * rm6;
03167 u += epsilon * rm6 * (rm6 - 2.f);
03168 }
03169
03170 }
03171
03172 for (n = 0; n < num_extras; n++) {
03173 float dx = px - extra[n].x;
03174 float dy = py - extra[n].y;
03175 float dz = pz - extra[n].z;
03176 float r2 = dx*dx + dy*dy + dz*dz;
03177 if (r2 >= cutoff2) continue;
03178 int pindex = 2 * extra[n].vdwtype;
03179 float epsilon = vdw_params[pindex] * probe_vdweps;
03180 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03181 float rm6 = rmin*rmin / r2;
03182 rm6 = rm6 * rm6 * rm6;
03183 u += epsilon * rm6 * (rm6 - 2.f);
03184 }
03185
03186 float occ = 0.f;
03187 if (u < max_energy) {
03188 occ = expf(-u);
03189 }
03190 map[lindex] = occ;
03191
03192 }
03193 }
03194 }
03195
03196 }
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206 void compute_occupancy_multiatom(ComputeOccupancyMap *p) {
03207 const char *bin_offsets = p->bin_offsets;
03208 const float *vdw_params = p->vdw_params;
03209 const float *probe_vdw_params = p->probe_vdw_params;
03210 const float *conformers = p->conformers;
03211 const AtomPosType *extra = p->extra;
03212 const float hx = p->hx;
03213 const float hy = p->hy;
03214 const float hz = p->hz;
03215 const float x0 = p->x0;
03216 const float y0 = p->y0;
03217 const float z0 = p->z0;
03218 const float bx_1 = p->bx_1;
03219 const float by_1 = p->by_1;
03220 const float bz_1 = p->bz_1;
03221 const float inv_num_conformers = 1.f / (float) p->num_conformers;
03222 const int num_bin_offsets = p->num_bin_offsets;
03223 const int num_extras = p->num_extras;
03224 const int num_probes = p->num_probes;
03225 const int num_conformers = p->num_conformers;
03226 const int nbx = p->nbx;
03227 const int nby = p->nby;
03228 const int mx = p->mx;
03229 const int my = p->my;
03230 const int kstart = p->kstart;
03231 const int kstop = p->kstop;
03232
03233 const BinOfAtoms *bin_zero = p->bin_zero;
03234 const char *excl = p->exclusions;
03235 float *map = p->map;
03236
03237 int i, j, k, n, nb;
03238
03239 const float minocc = expf(-p->excl_energy);
03240 const float cutoff2 = p->cutoff * p->cutoff;
03241
03242 float *u = new float[p->num_conformers];
03243
03244 for (k = kstart; k < kstop; k++) {
03245 for (j = 0; j < my; j++) {
03246 for (i = 0; i < mx; i++) {
03247
03248 int lindex = (k*my + j)*mx + i;
03249 if (excl[lindex]) {
03250 map[lindex] = 0.f;
03251 continue;
03252 }
03253
03254 float px = i*hx;
03255 float py = j*hy;
03256 float pz = k*hz;
03257
03258 int ib = (int) floorf(px * bx_1);
03259 int jb = (int) floorf(py * by_1);
03260 int kb = (int) floorf(pz * bz_1);
03261
03262 int m, ma;
03263
03264 px += x0;
03265 py += y0;
03266 pz += z0;
03267
03268 memset(u, 0, num_conformers * sizeof(float));
03269
03270 for (nb = 0; nb < num_bin_offsets; nb++) {
03271 int ic = ib + (int) bin_offsets[3*nb ];
03272 int jc = jb + (int) bin_offsets[3*nb + 1];
03273 int kc = kb + (int) bin_offsets[3*nb + 2];
03274
03275 const AtomPosType *atom = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03276
03277 for (n = 0; n < BIN_DEPTH; n++) {
03278 if (-1 == atom[n].vdwtype) break;
03279
03280 for (m = 0; m < num_conformers; m++) {
03281 float v = 0.f;
03282 for (ma = 0; ma < num_probes; ma++) {
03283 int index = m*num_probes + ma;
03284 float dx = conformers[3*index ] + px - atom[n].x;
03285 float dy = conformers[3*index + 1] + py - atom[n].y;
03286 float dz = conformers[3*index + 2] + pz - atom[n].z;
03287 float r2 = dx*dx + dy*dy + dz*dz;
03288 if (r2 >= cutoff2) continue;
03289 int pindex = 2 * atom[n].vdwtype;
03290 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03291 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03292 float rm6 = rmin*rmin / r2;
03293 rm6 = rm6 * rm6 * rm6;
03294 v += epsilon * rm6 * (rm6 - 2.f);
03295 }
03296
03297 u[m] += v;
03298
03299 }
03300
03301 }
03302
03303 }
03304
03305 for (n = 0; n < num_extras; n++) {
03306 for (m = 0; m < num_conformers; m++) {
03307 float v = 0.f;
03308 for (ma = 0; ma < num_probes; ma++) {
03309 int index = m*num_probes + ma;
03310 float dx = conformers[3*index ] + px - extra[n].x;
03311 float dy = conformers[3*index + 1] + py - extra[n].y;
03312 float dz = conformers[3*index + 2] + pz - extra[n].z;
03313 float r2 = dx*dx + dy*dy + dz*dz;
03314 if (r2 >= cutoff2) continue;
03315 int pindex = 2 *extra[n].vdwtype;
03316 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03317 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03318 float rm6 = rmin*rmin / r2;
03319 rm6 = rm6 * rm6 * rm6;
03320 v += epsilon * rm6 * (rm6 - 2.f);
03321 }
03322
03323 u[m] += v;
03324
03325 }
03326 }
03327
03328
03329
03330 float z = 0.f;
03331 for (m = 0; m < num_conformers; m++) {
03332 z += expf(-u[m]);
03333 }
03334
03335 float occ = z * inv_num_conformers;
03336 map[lindex] = (occ > minocc ? occ : 0.f);
03337 }
03338 }
03339 }
03340
03341 delete[] u;
03342 }
03343
03344
03345
03346 static void write_bin_histogram_map(
03347 const ComputeOccupancyMap *p,
03348 const char *filename
03349 ) {
03350 float xaxis[3], yaxis[3], zaxis[3];
03351 memset(xaxis, 0, 3*sizeof(float));
03352 memset(yaxis, 0, 3*sizeof(float));
03353 memset(zaxis, 0, 3*sizeof(float));
03354 xaxis[0] = p->nbx * p->bx;
03355 yaxis[1] = p->nby * p->by;
03356 zaxis[2] = p->nbz * p->bz;
03357
03358 int gridsize = p->nbx * p->nby * p->nbz;
03359 float *data = new float[gridsize];
03360
03361 int i;
03362 for (i=0; i<gridsize; i++) {
03363 data[i] = (float) p->bincnt[i];
03364 }
03365
03366 float ori[3];
03367 ori[0] = p->x0 - p->padx * p->bx;
03368 ori[1] = p->y0 - p->pady * p->by;
03369 ori[2] = p->z0 - p->padz * p->bz;
03370
03371 VolumetricData *volhist;
03372 volhist = new VolumetricData("atom binning histogram",
03373 ori, xaxis, yaxis, zaxis,
03374 p->nbx, p->nby, p->nbz, data);
03375
03376
03377 volmap_write_dx_file(volhist, filename);
03378
03379 delete volhist;
03380 }
03381
03382
03383
03384 void atom_bin_stats(const ComputeOccupancyMap *p) {
03385 int histogram[10] = { 0 };
03386 int i, j, k;
03387
03388 printf("*** origin = %g %g %g\n", p->x0, p->y0, p->z0);
03389 printf("*** lenx = %g leny = %g lenz = %g\n", p->lx, p->ly, p->lz);
03390 printf("*** bin lengths = %g %g %g\n", p->bx, p->by, p->bz);
03391 printf("*** inverse bin lengths = %g %g %g\n", p->bx_1, p->by_1, p->bz_1);
03392 printf("*** bin array: %d X %d X %d\n", p->nbx, p->nby, p->nbz);
03393 printf("*** bin padding: %d %d %d\n", p->padx, p->pady, p->padz);
03394 printf("*** cutoff = %g\n", p->cutoff);
03395 printf("*** extcutoff = %g\n", p->extcutoff);
03396 printf("*** size of tight neighborhood = %d\n", p->num_bin_offsets);
03397
03398 for (k = 0; k < p->nbz; k++) {
03399 for (j = 0; j < p->nby; j++) {
03400 for (i = 0; i < p->nbx; i++) {
03401 int index = (k*p->nby + j)*p->nbx + i;
03402 int count = p->bincnt[index];
03403 histogram[(count <= 9 ? count : 9)]++;
03404 }
03405 }
03406 }
03407
03408 printf("*** histogram of bin fill:\n");
03409 for (i = 0; i < (int) (sizeof(histogram) / sizeof(int)); i++) {
03410 if (i < 9) {
03411 printf("*** atom count %d number of bins %d\n",
03412 i, histogram[i]);
03413 }
03414 else {
03415 printf("*** atom count > 8 number of bins %d\n", histogram[i]);
03416 }
03417 }
03418 printf("*** number of extra atoms = %d\n", p->num_extras);
03419
03420 write_bin_histogram_map(p, "binning_histogram.dx");
03421 }
03422
03423
03424
03425
03426
03427 void compute_allatoms(
03428 float *map,
03429 int mx, int my, int mz,
03430 float lx, float ly, float lz,
03431 const float origin[3],
03432 const float axes[9],
03433 const float alignmat[16],
03434 int num_coords,
03435 const float *coords,
03436 const int *vdw_type,
03437 const float *vdw_params,
03438 float cutoff,
03439 const float *probe_vdw_params,
03440 int num_probe_atoms,
03441 int num_conformers,
03442 const float *conformers,
03443 float excl_energy
03444 ) {
03445 const float theTrivialConformer[] = { 0.f, 0.f, 0.f };
03446
03447 if (0 == num_conformers) {
03448 num_conformers = 1;
03449 conformers = theTrivialConformer;
03450 }
03451
03452 float hx = lx / mx;
03453 float hy = ly / my;
03454 float hz = lz / mz;
03455
03456 int i, j, k, n, m, ma;
03457
03458 float cutoff2 = cutoff * cutoff;
03459 float minocc = expf(-excl_energy);
03460
03461 float *u = new float[num_conformers];
03462
03463 #if 1
03464 printf("*** All atoms calculation (quadratic complexity)\n");
03465 printf("*** number of map points = %d\n", mx*my*mz);
03466 printf("*** number of atoms = %d\n", num_coords);
03467 printf("*** number of conformers = %d\n", num_conformers);
03468 printf("*** number of probe atoms = %d\n", num_probe_atoms);
03469 #endif
03470
03471 for (k = 0; k < mz; k++) {
03472 for (j = 0; j < my; j++) {
03473 for (i = 0; i < mx; i++) {
03474
03475 int mindex = (k*my + j)*mx + i;
03476
03477 float px = i*hx + origin[0];
03478 float py = j*hy + origin[1];
03479 float pz = k*hz + origin[2];
03480
03481 memset(u, 0, num_conformers * sizeof(float));
03482
03483 for (n = 0; n < num_coords; n++) {
03484
03485 for (m = 0; m < num_conformers; m++) {
03486 float v = 0.f;
03487 for (ma = 0; ma < num_probe_atoms; ma++) {
03488 int index = m*num_probe_atoms + ma;
03489 float dx = conformers[3*index ] + px - coords[3*n ];
03490 float dy = conformers[3*index + 1] + py - coords[3*n + 1];
03491 float dz = conformers[3*index + 2] + pz - coords[3*n + 2];
03492 float r2 = dx*dx + dy*dy + dz*dz;
03493 if (r2 >= cutoff2) continue;
03494 int pindex = 2 * vdw_type[n];
03495 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03496 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03497 float rm6 = rmin*rmin / r2;
03498 rm6 = rm6 * rm6 * rm6;
03499 v += epsilon * rm6 * (rm6 - 2.f);
03500 }
03501
03502 u[m] += v;
03503
03504 }
03505
03506 }
03507
03508 float z = 0.f;
03509 for (m = 0; m < num_conformers; m++) {
03510 z += expf(-u[m]);
03511 }
03512
03513 map[mindex] = z / num_conformers;
03514 if (map[mindex] < minocc) map[mindex] = 0.f;
03515 }
03516 }
03517 }
03518
03519 delete[] u;
03520 }
03521