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] = { 0 };
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] = { 0 };
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
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) {
00863 Wmin = W;
00864
00865 }
00866 if (W>max_energy+5.f) {
00867 effrad[t] = dist;
00868 break;
00869 }
00870 }
00871
00872
00873 if (effrad[t]<excl_dist) excl_dist = effrad[t];
00874 }
00875
00876 delete [] effrad;
00877 delete [] conf;
00878 }
00879
00880
00881
00882
00883 static bool collinear(const float *axis1, const float *axis2, float tol) {
00884 if (fabs(dot_prod(axis1, axis2)) > 1.f-DEGTORAD(tol)) return 1;
00885 return 0;
00886 }
00887
00888
00889
00890
00891 int VolMapCreateILS::is_probe_linear(float *axis) {
00892 if (num_probe_atoms==1) return 0;
00893
00894 float vec0[3], vec1[3];
00895 vec_sub(vec0, &probe_coords[3], &probe_coords[0]);
00896 vec_copy(axis, vec0);
00897 if (num_probe_atoms==2) return 1;
00898
00899 float norm0 = norm(vec0);
00900 int i;
00901 for (i=2; i<num_probe_atoms; i++) {
00902 vec_sub(vec1, &probe_coords[3*i], &probe_coords[0]);
00903 float dot = dot_prod(vec0, vec1)/(norm0*norm(vec1));
00904 if (fabs(dot) < 0.95f) return 0;
00905
00906 if (dot>0.f) vec_add(axis, axis, vec1);
00907 else vec_sub(axis, axis, vec1);
00908 }
00909 vec_normalize(axis);
00910 return 1;
00911 }
00912
00913
00914
00915
00916
00917
00918 static int triangulate(const float *pole, const float *eq1,
00919 const float *eq2, int freq, float *v) {
00920 if (freq==0) {
00921 vec_copy(v, pole);
00922 return 1;
00923 }
00924
00925 float meridian[3], parallel[3];
00926 vec_sub(meridian, eq1, pole);
00927 vec_sub(parallel, eq2, eq1);
00928 float mlen = norm(meridian);
00929 float plen = norm(parallel);
00930 vec_normalize(meridian);
00931 vec_normalize(parallel);
00932 int i, k = 0;
00933 for (i=0; i<=freq; i++) {
00934 float latitude = float(i)/float(freq)*mlen;
00935 float p[3], p0[3];
00936 vec_copy(p0, pole);
00937 vec_scaled_add(p0, latitude, meridian);
00938 int j;
00939 for (j=0; j<=i; j++) {
00940 float longitude = float(j)/float(freq)*plen;
00941 vec_copy(p, p0);
00942 vec_scaled_add(p, longitude, parallel);
00943 vec_copy(&v[3*k], p);
00944 k++;
00945 }
00946 }
00947 return k;
00948 }
00949
00950
00951
00952
00953 static void octahedron(float *vertices, int C2symm) {
00954 const float v[] = {1.f, 0.f, 0.f,
00955 0.f, 1.f, 0.f,
00956 0.f, 0.f, 1.f};
00957 memcpy(vertices, v, 9*sizeof(float));
00958 if (!C2symm) {
00959 int i;
00960 for (i=0; i<3; i++) {
00961 vec_negate(&vertices[9+3*i], &vertices[3*i]);
00962 }
00963 }
00964 }
00965
00966
00967
00968 static void hexahedron(float *vertices, int C2symm) {
00969 const float v[] = {1.f, 1.f, 1.f,
00970 1.f, -1.f, 1.f,
00971 1.f, 1.f, -1.f,
00972 1.f, -1.f, -1.f};
00973 memcpy(vertices, v, 12*sizeof(float));
00974
00975 if (!C2symm) {
00976 int i;
00977 for (i=0; i<4; i++) {
00978 vec_negate(&vertices[12+3*i], &vertices[3*i]);
00979 }
00980 }
00981 }
00982
00983
00984
00985
00986
00987
00988
00989 static void dodecahedron(float *faces, float *vertices, int C2symm) {
00990
00991 const float dihedral = float(180.f-RADTODEG(acos(-1.f/sqrtf(5.f))));
00992
00993
00994 float x[3];
00995 vec_zero(x); x[0] = 1.f;
00996 vec_copy(&faces[0], x);
00997
00998 Matrix4 rot;
00999 rot.rot(dihedral, 'z');
01000 rot.multpoint3d(&faces[0], &faces[3]);
01001
01002 int i;
01003 for (i=1; i<5; i++) {
01004 rot.identity();
01005 rot.rot(float(i)*72.f, 'x');
01006 rot.multpoint3d(&faces[3], &faces[3+3*i]);
01007 }
01008 if (!C2symm) {
01009 for (i=0; i<6; i++) {
01010 vec_negate(&faces[18+3*i], &faces[3*i]);
01011 }
01012 }
01013
01014
01015
01016 for (i=0; i<5; i++) {
01017 vec_copy(&vertices[3*i], &faces[0]);
01018 vec_add(&vertices[3*i], &vertices[3*i], &faces[3*(i+1)]);
01019 vec_add(&vertices[3*i], &vertices[3*i], &faces[3*((i+1)%5+1)]);
01020 vec_normalize(&vertices[3*i]);
01021 }
01022
01023 vec_copy(&vertices[3*5], &faces[3*1]);
01024 vec_add(&vertices[3*5], &vertices[3*5], &faces[3*2]);
01025 vec_normalize(&vertices[3*5]);
01026 float cross[3];
01027 cross_prod(cross, &vertices[3*5], &faces[0]);
01028 vec_normalize(cross);
01029 float phi = angle(&vertices[3*5], &vertices[0]);
01030 rot.identity();
01031 rot.rotate_axis(cross, float(DEGTORAD(-phi)));
01032 rot.multpoint3d(&vertices[3*5], &vertices[3*5]);
01033 for (i=1; i<5; i++) {
01034 rot.identity();
01035 rot.rot(float(i)*72.f, 'x');
01036 rot.multpoint3d(&vertices[3*5], &vertices[3*5+3*i]);
01037 }
01038
01039
01040 if (!C2symm) {
01041 for (i=0; i<10; i++) {
01042 vec_negate(&vertices[30+3*i], &vertices[3*i]);
01043 }
01044 }
01045 }
01046
01047
01048
01049
01050
01051
01052
01053
01054 static int icosahedron_geodesic(float *(&orientations),
01055 int C2symm, int freq) {
01056 int i;
01057 float faces[3*12];
01058 float junk[3*20];
01059 dodecahedron(faces, junk, 0);
01060 float meridian[3], parallel[3];
01061
01062 int numvertex = 0;
01063 for (i=1; i<=freq+1; i++) numvertex += i;
01064 int symmfac = C2symm ? 2 : 1;
01065 int numorient = (10*freq*freq + 2)/symmfac;
01066 orientations = new float[3*numorient];
01067
01068
01069 vec_copy(&orientations[0], &faces[0]);
01070 int k = 1;
01071
01072 for (i=0; i<5; i++) {
01073
01074 float p0[3], p1[3], p2[3];
01075 vec_sub(parallel, &faces[3+3*((i+1)%5)], &faces[3*(i+1)]);
01076 float edgelen = norm(parallel);
01077 vec_normalize(parallel);
01078 vec_sub(meridian, &faces[3*(i+1)], &faces[0]);
01079 vec_normalize(meridian);
01080 vec_copy(p0, &faces[0]);
01081 vec_copy(p1, &faces[3*(i+1)]);
01082 vec_copy(p2, &faces[3+3*((i+1)%5)]);
01083 vec_scaled_add(p0, 1.f/float(freq)*edgelen, meridian);
01084 vec_scaled_add(p2, -1.f/float(freq)*edgelen, parallel);
01085 triangulate(p0, p1, p2, freq-1, &orientations[3*k]);
01086 k += numvertex-(freq+1);
01087
01088
01089 vec_sub(meridian, &faces[3*(i+1)], &faces[21+3*((i+3)%5)]);
01090 vec_normalize(meridian);
01091 vec_copy(p0, &faces[21+3*((i+3)%5)]);
01092 vec_copy(p1, &faces[3*(i+1)]);
01093 vec_scaled_add(p0, 1.f/float(freq)*edgelen, meridian);
01094 vec_scaled_add(p1, -1.f/float(freq)*edgelen, meridian);
01095 vec_copy(p2, p1);
01096 vec_scaled_add(p2, float(freq-2)/float(freq)*edgelen, parallel);
01097 triangulate(p0, p1, p2, freq-2, &orientations[3*k]);
01098 k += numvertex-(freq+1)-freq;
01099 }
01100
01101 if (!C2symm) {
01102 for (i=0; i<numorient/2; i++) {
01103 vec_negate(&orientations[3*numorient/2+3*i], &orientations[3*i]);
01104 }
01105 }
01106
01107 return numorient;
01108 }
01109
01110 float VolMapCreateILS::dimple_depth(float phi) {
01111 int i;
01112 phi = 0.5f*phi;
01113
01114 float min_syseps = vdwparams[0];
01115 float min_sysrmin = vdwparams[1];
01116 for (i=1; i<num_unique_types; i++) {
01117 if (vdwparams[2*i+1]<min_sysrmin) {
01118 min_syseps = vdwparams[2*i ];
01119 min_sysrmin = vdwparams[2*i+1];
01120 }
01121 }
01122 float maxdepth = 0.f;
01123
01124
01125 for (i=0; i<num_probe_atoms; i++) {
01126 float d = norm(&probe_coords[3*i]);
01127 float sphi, cphi;
01128 sincosf(float(DEGTORAD(phi)), &sphi, &cphi);
01129 float a = d*sphi;
01130 float m = a/cphi;
01131 if (phi == 90.f) m = a;
01132 float c = probe_vdw[2*i+1] + min_sysrmin;
01133 if (m>c) {
01134 maxdepth = d;
01135 break;
01136 }
01137 float b = sqrtf(c*c-m*m);
01138 float depth = d + c - d*cosf(float(DEGTORAD(phi))) - b;
01139
01140
01141
01142 float epsilon = min_syseps * probe_vdw[2*i];
01143 float rmin = min_sysrmin + probe_vdw[2*i+1];
01144
01145 float r2 = c*c;
01146 float rm6 = rmin*rmin / r2;
01147 rm6 = rm6 * rm6 * rm6;
01148 float u0 = epsilon * rm6 * (rm6 - 2.f);
01149
01150 r2 = (c+depth)*(c+depth);
01151 rm6 = rmin*rmin / r2;
01152 rm6 = rm6 * rm6 * rm6;
01153 float u1 = epsilon * rm6 * (rm6 - 2.f);
01154
01155 r2 = (c-depth)*(c-depth);
01156 rm6 = rmin*rmin / r2;
01157 rm6 = rm6 * rm6 * rm6;
01158 float u2 = epsilon * rm6 * (rm6 - 2.f);
01159 float du1 = u1-u0;
01160 float du2 = u2-u0;
01161 printf("phi = %.2f: %d dimple depth = %f = %5.2f%%, dU1 = %fkT = %5.2f%%; dU1 = %fkT = %5.2f%%\n",
01162 phi, i, depth, 100.f*depth/(d+probe_vdw[2*i]), du1, fabs(100.f*du1/u0), du2, fabs(100.f*du2/u0));
01163
01164 if (depth>maxdepth) maxdepth = depth;
01165 }
01166 return maxdepth;
01167 }
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187 int VolMapCreateILS::gen_conf_tetrahedral(float *(&conform),
01188 int freq, int &numorient, int &numrot) {
01189
01190 float tetra0[3], tetra1[3], tetra2[3], tetra3[3];
01191 vec_zero(tetra0);
01192 tetra0[0] = 1.f;
01193 Matrix4 rot;
01194 rot.rot(109.47122f, 'z');
01195 rot.multpoint3d(tetra0, tetra1);
01196 rot.identity();
01197 rot.rot(120.f, 'x');
01198 rot.multpoint3d(tetra1, tetra2);
01199 rot.multpoint3d(tetra2, tetra3);
01200
01201 #if defined(DEBUG)
01202 Molecule *mol = app->moleculeList->mol_from_id(molid);
01203 MoleculeGraphics *gmol = mol->moleculeGraphics();
01204 gmol->use_color(8);
01205 gmol->add_line(tetra0, tetra1, 0, 1);
01206 gmol->add_line(tetra0, tetra2, 0, 1);
01207 gmol->add_line(tetra0, tetra3, 0, 1);
01208 gmol->add_line(tetra1, tetra2, 0, 1);
01209 gmol->add_line(tetra1, tetra3, 0, 1);
01210 gmol->add_line(tetra2, tetra3, 0, 1);
01211 #endif
01212
01213
01214 float *orientations;
01215 orientations = new float[3*8];
01216
01217 vec_copy(&orientations[3*0], tetra0);
01218 vec_copy(&orientations[3*1], tetra1);
01219 vec_copy(&orientations[3*2], tetra2);
01220 vec_copy(&orientations[3*3], tetra3);
01221 float face[3];
01222 vec_copy(face, tetra0);
01223 vec_add(face, face, tetra1);
01224 vec_add(face, face, tetra2);
01225 vec_copy(&orientations[3*4], face);
01226 vec_copy(face, tetra0);
01227 vec_add(face, face, tetra1);
01228 vec_add(face, face, tetra3);
01229 vec_copy(&orientations[3*5], face);
01230 vec_copy(face, tetra0);
01231 vec_add(face, face, tetra2);
01232 vec_add(face, face, tetra3);
01233 vec_copy(&orientations[3*6], face);
01234 vec_copy(face, tetra1);
01235 vec_add(face, face, tetra2);
01236 vec_add(face, face, tetra3);
01237 vec_copy(&orientations[3*7], face);
01238
01239 numrot = freq;
01240 numorient = 8;
01241 int numconf = numorient*numrot-6;
01242 conform = new float[3*num_probe_atoms*numconf];
01243 memset(conform, 0, 3*num_probe_atoms*numconf*sizeof(float));
01244
01245 int conf = 0;
01246 int i;
01247 for (i=0; i<numorient; i++) {
01248 float *dir = &orientations[3*i];
01249 vec_normalize(dir);
01250
01251
01252 int j;
01253 for (j=0; j<numrot; j++) {
01254
01255
01256 if (i%4 && j==0) continue;
01257
01258 float psi = float(j)/float(numrot)*360.f/float(probe_axisorder1);
01259 Matrix4 rot;
01260 if (i>=numorient/2) {
01261
01262
01263
01264 float z[3];
01265 vec_zero(z); z[2]=1.f;
01266 rot.rotate_axis(z, float(DEGTORAD(180.f)));
01267 }
01268
01269
01270 rot.rotate_axis(dir, float(DEGTORAD(psi)));
01271
01272
01273 int k;
01274 for (k=0; k<num_probe_atoms; k++) {
01275 rot.multpoint3d(&probe_coords[3*k],
01276 &conform[3*num_probe_atoms*conf + 3*k]);
01277 }
01278
01279 conf++;
01280 }
01281 }
01282
01283 delete [] orientations;
01284
01285
01286 return numconf;
01287 }
01288
01289
01290
01291
01292 static float signed_angle(const float *axis,
01293 const float *v1, const float *v2) {
01294 float normaxis[3], cross1[3], cross2[3], cross3[3];
01295 cross_prod(cross1, axis, v1);
01296 cross_prod(cross2, axis, v2);
01297 cross_prod(cross3, v1, v2);
01298 vec_normalize(cross3);
01299 vec_copy(normaxis, axis);
01300 vec_normalize(normaxis);
01301 float phi = angle(cross1, cross2);
01302 if (dot_prod(axis, cross3)<0) {
01303 phi = -phi;
01304 }
01305 return phi;
01306 }
01307
01308
01309
01310
01311
01312
01313
01314 int VolMapCreateILS::gen_conf(float *(&conform), int freq,
01315 int &numorient, int &numrot) {
01316 int i;
01317 float *orientations = NULL;
01318 int C2symm = (probe_axisorder2==2 ? 1 : 0);
01319 int symmfac = C2symm ? 2 : 1;
01320 float anglespacing = 360.f;
01321
01322 switch (freq) {
01323 case 1:
01324 numorient = 1;
01325 orientations = new float[3*numorient];
01326 break;
01327 case 2:
01328
01329 numorient = 6/symmfac;
01330 orientations = new float[3*numorient];
01331 octahedron(orientations, C2symm);
01332 anglespacing = 90.f;
01333 break;
01334 case 3:
01335
01336 numorient = 8/symmfac;
01337 orientations = new float[3*numorient];
01338 hexahedron(orientations, C2symm);
01339 anglespacing = 109.47122f;
01340 break;
01341 case 4:
01342
01343 numorient = 12/symmfac;
01344 orientations = new float[3*numorient];
01345 float vertices[3*20];
01346 dodecahedron(orientations, vertices, C2symm);
01347 anglespacing = float(180.f-RADTODEG(acos(-1.f/sqrtf(5.f))));
01348 break;
01349 case 5:
01350
01351 numorient = 20/symmfac;
01352 orientations = new float[3*numorient];
01353 float faces[3*12];
01354 dodecahedron(faces, orientations, C2symm);
01355 anglespacing = 180.f-138.189685f;
01356 break;
01357 case 6:
01358
01359 numorient = 32/symmfac;
01360 orientations = new float[3*numorient];
01361 dodecahedron(&orientations[0], &orientations[3*12/symmfac], C2symm);
01362 anglespacing = 37.377380f;
01363 break;
01364 default:
01365
01366 freq -= 5;
01367
01368 numorient = icosahedron_geodesic(orientations, C2symm, freq);
01369
01370 anglespacing = (180.f-138.189685f)/freq;
01371 break;
01372 }
01373
01374
01375
01376
01377 numrot = 1;
01378 if (probe_axisorder1>=0) {
01379 numrot = int(floorf(360.f/probe_axisorder1/anglespacing + 0.5f));
01380 }
01381
01382 int numconf = numorient*numrot;
01383
01384 conform = new float[3*num_probe_atoms*numconf];
01385 memset(conform, 0, 3*num_probe_atoms*numconf*sizeof(float));
01386
01387 #if defined(DEBUG)
01388 Molecule *mol = app->moleculeList->mol_from_id(molid);
01389 MoleculeGraphics *gmol = mol->moleculeGraphics();
01390 for (i=0; i<numorient; i++) {
01391 float dir[3];
01392 vec_scale(dir, 0.8, &orientations[3*i]);
01393 gmol->use_color(7);
01394 if (i==0) gmol->use_color(4);
01395 if (i==1) gmol->use_color(8);
01396 if (i==2) gmol->use_color(9);
01397 gmol->add_sphere(dir, 0.1, 8);
01398 }
01399 #endif
01400
01401
01402 int conf = 0;
01403 for (i=0; i<numorient; i++) {
01404 float *dir = &orientations[3*i];
01405 vec_normalize(dir);
01406
01407 float cross[3], x[3], y[3], z[3];
01408 vec_zero(x); x[0]=1.f;
01409 vec_zero(y); y[1]=1.f;
01410 vec_zero(z); z[2]=1.f;
01411 float phi = 0.f;
01412 float theta = 0.f;
01413
01414 if (!collinear(x, dir, 2.f)) {
01415
01416 cross_prod(cross, x, dir);
01417 phi = angle(dir, x);
01418
01419
01420
01421
01422 float cross2[3];
01423 cross_prod(cross2, x, y);
01424 theta = signed_angle(x, cross2, cross);
01425 } else if (dot_prod(x, dir)<0.f) {
01426
01427 phi = 180.f;
01428 }
01429
01430
01431
01432
01433 int j;
01434 for (j=0; j<numrot; j++) {
01435 Matrix4 m;
01436 float psi = float(j)/float(numrot)*360.f/float(probe_axisorder1);
01437
01438
01439 m.rotate_axis(dir, float(DEGTORAD(psi)));
01440
01441
01442 m.rot(theta, 'x');
01443
01444
01445 m.rotate_axis(z, float(DEGTORAD(phi)));
01446
01447
01448 int k;
01449 for (k=0; k<num_probe_atoms; k++) {
01450 m.multpoint3d(&probe_coords[3*k],
01451 &conform[3*num_probe_atoms*conf + 3*k]);
01452 }
01453
01454 conf++;
01455 }
01456 }
01457
01458 delete [] orientations;
01459
01460
01461 return numconf;
01462 }
01463
01464
01465
01466
01467
01468
01469
01470 void VolMapCreateILS::check_probe_symmetry() {
01471 float principal[3];
01472 if (is_probe_linear(principal)) {
01473 probe_axisorder1 = -1;
01474 vec_copy(probe_symmaxis1, principal);
01475
01476
01477
01478
01479
01480 int Dinfv = 1;
01481 int i, j;
01482 for (i=0; i<num_probe_atoms; i++) {
01483 float image[3];
01484 vec_negate(image, &probe_coords[3*i]);
01485 int match = 1;
01486 for (j=i+1; j<num_probe_atoms; j++) {
01487 if (distance(&probe_coords[3*j], image)>0.05) continue;
01488 if (probe_vdw[2*i ]!=probe_vdw[2*j ] ||
01489 probe_vdw[2*i+1]!=probe_vdw[2*j+1] ||
01490 probe_charge[i]!=probe_charge[j]) {
01491 match = 0;
01492 break;
01493 }
01494 }
01495 if (!match) {
01496 Dinfv = 0;
01497 break;
01498 }
01499 }
01500
01501 if (Dinfv) {
01502
01503 float v[3];
01504 vec_zero(v); v[0] = 1.f;
01505 if (fabs(dot_prod(probe_symmaxis1, v))>0.95) {
01506
01507 v[0] = 0.f; v[1] = 1.f;
01508 }
01509 float cross[3];
01510 cross_prod(cross, probe_symmaxis1, v);
01511 cross_prod(probe_symmaxis2, cross, probe_symmaxis1);
01512 probe_axisorder2 = 2;
01513 }
01514 }
01515 else if (num_probe_atoms==5) {
01516
01517
01518
01519
01520
01521
01522 int i, icenter = -1;
01523 float zero[3];
01524 vec_zero(zero);
01525 for (i=0; i<num_probe_atoms; i++) {
01526 if (distance(&probe_coords[3*i], zero)<0.05) {
01527 icenter = i;
01528 break;
01529 }
01530 }
01531
01532 if (icenter>=0) {
01533 float corner[12];
01534 float vdweps=0.f, vdwrmin=0.f, charge=0.f, dist=0.f;
01535 int match = 1;
01536 int j = 0;
01537
01538
01539
01540 for (i=0; i<num_probe_atoms; i++) {
01541 if (i==icenter) continue;
01542 if (j==0) {
01543 vdweps = probe_vdw[2*i ];
01544 vdwrmin = probe_vdw[2*i+1];
01545 charge = probe_charge[i];
01546 dist = norm(&probe_coords[3*i]);
01547 }
01548 else if (probe_vdw[2*i ] != vdweps ||
01549 probe_vdw[2*i+1] != vdwrmin ||
01550 probe_charge[i] != charge ||
01551 norm(&probe_coords[3*i])-dist > 0.05) {
01552 match = 0;
01553 break;
01554 }
01555
01556 vec_copy(&corner[3*j], &probe_coords[3*i]);
01557 j++;
01558 }
01559
01560
01561 if (match &&
01562 angle(&corner[0], &corner[3])-109.47122f < 5.f &&
01563 angle(&corner[0], &corner[6])-109.47122f < 5.f &&
01564 angle(&corner[0], &corner[9])-109.47122f < 5.f &&
01565 angle(&corner[3], &corner[6])-109.47122f < 5.f &&
01566 angle(&corner[3], &corner[9])-109.47122f < 5.f &&
01567 angle(&corner[6], &corner[9])-109.47122f < 5.f) {
01568 probe_tetrahedralsymm = 1;
01569 probe_axisorder1 = 3;
01570 probe_axisorder2 = 3;
01571 vec_copy(probe_symmaxis1, &corner[0]);
01572 vec_copy(probe_symmaxis2, &corner[3]);
01573 }
01574 }
01575 }
01576 }
01577
01578
01579
01580
01581
01582 void VolMapCreateILS::initialize_probe() {
01583
01584
01585 check_probe_symmetry();
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609 if (probe_axisorder1==1 ||
01610 (probe_axisorder2!=1 && probe_axisorder2!=2)) {
01611
01612 int tmpord = probe_axisorder1;
01613 probe_axisorder1 = probe_axisorder2;
01614 probe_axisorder2 = tmpord;
01615
01616 float tmp[3];
01617 vec_copy(tmp, probe_symmaxis1);
01618 vec_copy(probe_symmaxis1, probe_symmaxis2);
01619 vec_copy(probe_symmaxis2, tmp);
01620 }
01621
01622
01623
01624 Matrix4 rot;
01625 rot.transvecinv(probe_symmaxis1[0], probe_symmaxis1[1], probe_symmaxis1[2]);
01626 int i;
01627 for (i=0; i<num_probe_atoms; i++) {
01628 rot.multpoint3d(&probe_coords[3*i], &probe_coords[3*i]);
01629 }
01630 rot.multpoint3d(probe_symmaxis1, probe_symmaxis1);
01631 rot.multpoint3d(probe_symmaxis2, probe_symmaxis2);
01632
01633
01634 if (probe_axisorder2>1) {
01635 float cross[3], z[3];
01636 vec_zero(z); z[2] = 1.f;
01637 cross_prod(cross, probe_symmaxis1, probe_symmaxis2);
01638
01639 float phi = angle(cross, z);
01640 rot.identity();
01641 rot.rotate_axis(probe_symmaxis1, float(DEGTORAD(phi)));
01642
01643 for (i=0; i<num_probe_atoms; i++) {
01644 rot.multpoint3d(&probe_coords[3*i], &probe_coords[3*i]);
01645 }
01646 rot.multpoint3d(probe_symmaxis1, probe_symmaxis1);
01647 rot.multpoint3d(probe_symmaxis2, probe_symmaxis2);
01648 }
01649
01650
01651 if (getenv("VMDILSNOSYMM")) {
01652
01653
01654 probe_axisorder1 = 1;
01655 probe_axisorder2 = 1;
01656 probe_tetrahedralsymm = 0;
01657 msgWarn << "env(VMDILSNOSYMM) is set: Ignoring probe symmetry!" << sendmsg;
01658 }
01659
01660 num_orientations = 0;
01661 num_rotations = 1;
01662
01663 if (probe_tetrahedralsymm) {
01664 msgInfo << "Probe symmetry: tetrahedral" << sendmsg;
01665
01666 num_conformers = gen_conf_tetrahedral(conformers,
01667 conformer_freq, num_orientations,
01668 num_rotations);
01669 }
01670
01671 else {
01672
01673
01674
01675 if (probe_axisorder1<=1 && probe_axisorder1<=1) {
01676 msgInfo << "Probe symmetry: none" << sendmsg;
01677 }
01678
01679 else if (probe_axisorder1==-1) {
01680 if (probe_axisorder2==2) {
01681 msgInfo << "Probe symmetry: Dinfh (linear, C2)" << sendmsg;
01682 } else {
01683 msgInfo << "Probe symmetry: Cinfv (linear)" << sendmsg;
01684 }
01685 msgInfo << " Probe is linear, generating probe orientations only." << sendmsg;
01686 }
01687 else if (probe_axisorder1>1) {
01688 if (probe_axisorder2==2) {
01689 msgInfo << "Probe symmetry: C" << probe_axisorder1
01690 << ", C2" << sendmsg;
01691 } else {
01692 msgInfo << "Probe symmetry: C" << probe_axisorder1 << sendmsg;
01693 }
01694 msgInfo << " Exploiting C" << probe_axisorder1
01695 << " rotary symmetry for rotation of the oriented probe." << sendmsg;
01696 }
01697
01698 if (probe_axisorder2==2) {
01699 msgInfo << " Exploiting C2 rotary symmetry for probe orientations"
01700 << sendmsg;
01701 }
01702
01703
01704
01705
01706
01707
01708
01709
01710 num_conformers = gen_conf(conformers, conformer_freq,
01711 num_orientations, num_rotations);
01712 }
01713
01714 msgInfo << "Probe orientations: " << num_orientations
01715 << sendmsg;
01716 msgInfo << "Rotamers per orientation: " << num_rotations
01717 << sendmsg;
01718 msgInfo << "Conformers generated: " << num_conformers
01719 << sendmsg << sendmsg;
01720 }
01721
01722
01723
01724
01725
01726 int VolMapCreateILS::box_inside_pbccell(int frame, float *minmaxcoor) {
01727 Matrix4 mat;
01728
01729
01730 measure_pbc2onc(app->moleculeList, molid,
01731 frame, pbccenter, mat);
01732
01733
01734 float box[9];
01735 memset(box, 0, 9*sizeof(float));
01736 box[0] = minmaxcoor[3]-minmaxcoor[0];
01737 box[4] = minmaxcoor[4]-minmaxcoor[1];
01738 box[8] = minmaxcoor[5]-minmaxcoor[2];
01739
01740
01741
01742
01743
01744
01745
01746 float node[8*3];
01747 memset(node, 0, 8*3*sizeof(float));
01748 int n=0;
01749 int i, j, k;
01750 for (i=0; i<=1; i++) {
01751 for (j=0; j<=1; j++) {
01752 for (k=0; k<=1; k++) {
01753 vec_copy(node+3*n, &minmaxcoor[0]);
01754 vec_scaled_add(node+3*n, float(i), &box[0]);
01755 vec_scaled_add(node+3*n, float(j), &box[3]);
01756 vec_scaled_add(node+3*n, float(k), &box[6]);
01757
01758
01759 mat.multpoint3d(node+3*n, node+3*n);
01760 n++;
01761 }
01762 }
01763 }
01764
01765
01766 for (n=0; n<8; n++) {
01767
01768 if (node[3*n ]<0.f) return 0;
01769 if (node[3*n+1]<0.f) return 0;
01770 if (node[3*n+2]<0.f) return 0;
01771 if (node[3*n ]>1.f) return 0;
01772 if (node[3*n+1]>1.f) return 0;
01773 if (node[3*n+2]>1.f) return 0;
01774 }
01775 return 1;
01776 }
01777
01778
01779
01780
01781
01782
01783
01784 int VolMapCreateILS::grid_inside_pbccell(int frame, float *maskvoldata,
01785 const Matrix4 &alignment) {
01786 Matrix4 AA, BB, CC;
01787
01788 Molecule *mol = app->moleculeList->mol_from_id(molid);
01789 mol->get_frame(frame)->get_transforms(AA, BB, CC);
01790
01791
01792 float cella[3], cellb[3], cellc[3];
01793 cella[0] = AA.mat[12];
01794 cella[1] = AA.mat[13];
01795 cella[2] = AA.mat[14];
01796 cellb[0] = BB.mat[12];
01797 cellb[1] = BB.mat[13];
01798 cellb[2] = BB.mat[14];
01799 cellc[0] = CC.mat[12];
01800 cellc[1] = CC.mat[13];
01801 cellc[2] = CC.mat[14];
01802
01803 float normals[3*6];
01804 cross_prod(&normals[0], cella, cellb);
01805 cross_prod(&normals[3], cella, cellc);
01806 cross_prod(&normals[6], cellb, cellc);
01807 vec_normalize(&normals[0]);
01808 vec_normalize(&normals[3]);
01809 vec_normalize(&normals[6]);
01810 vec_scale(&normals[0], cutoff, &normals[0]);
01811 vec_scale(&normals[3], cutoff, &normals[3]);
01812 vec_scale(&normals[6], cutoff, &normals[6]);
01813 vec_negate(&normals[9], &normals[0]);
01814 vec_negate(&normals[12], &normals[3]);
01815 vec_negate(&normals[15], &normals[6]);
01816
01817 Matrix4 pbc2onc;
01818 int allinside = 1;
01819
01820
01821 measure_pbc2onc(app->moleculeList, molid, frame, pbccenter, pbc2onc);
01822
01823
01824
01825
01826 Matrix4 alignmentinv(alignment);
01827 alignmentinv.inverse();
01828
01829 Matrix4 coretransform(pbc2onc);
01830 coretransform.multmatrix(alignmentinv);
01831
01832 float testpos[3], gridpos[3], extgridpos[3];
01833
01834 int n;
01835 for (n=0; n<nsampx*nsampy*nsampz; n++) {
01836
01837 gridpos[0] = float((n%nsampx) *delta + gridorigin[0]);
01838 gridpos[1] = float(((n/nsampx)%nsampy)*delta + gridorigin[1]);
01839 gridpos[2] = float((n/(nsampx*nsampy))*delta + gridorigin[2]);
01840
01841
01842
01843
01844
01845
01846 int i;
01847 for (i=0; i<6; i++) {
01848 vec_add(extgridpos, gridpos, &normals[3*i]);
01849
01850
01851 coretransform.multpoint3d(extgridpos, testpos);
01852 if (testpos[0]<0.f || testpos[0]>1.f ||
01853 testpos[1]<0.f || testpos[1]>1.f ||
01854 testpos[2]<0.f || testpos[2]>1.f) {
01855
01856 maskvoldata[n] = 0.f;
01857 allinside = 0;
01858 i = 6;
01859 }
01860 }
01861 }
01862
01863 return allinside;
01864 }
01865
01866
01875 int VolMapCreateILS::create_unique_paramlist() {
01876 Molecule *mol = app->moleculeList->mol_from_id(molid);
01877
01878
01879 const flint *radius = (flint *) mol->extraflt.data("radius");
01880 if (!radius) return MEASURE_ERR_NORADII;
01881 const flint *occupancy = (flint *) mol->extraflt.data("occupancy");
01882 if (!occupancy) return MEASURE_ERR_NORADII;
01883
01884 int i, j;
01885
01886 #define MAX_UNIQUE_TYPES 200
01887
01888
01889
01890
01891 atomtypes = new int[mol->nAtoms];
01892 atomtypes[0] = 0;
01893 flint *unique_occ = new flint[MAX_UNIQUE_TYPES];
01894 flint *unique_rad = new flint[MAX_UNIQUE_TYPES];
01895 unique_occ[0].f = occupancy[0].f;
01896 unique_rad[0].f = radius[0].f;
01897 num_unique_types = 1;
01898
01899 for (i=1; i<mol->nAtoms; i++) {
01900 int found = 0;
01901
01902
01903 for (j=0; j<num_unique_types; j++) {
01904
01905 if (occupancy[i].i==unique_occ[j].i && radius[i].i==unique_rad[j].i) {
01906 found = 1;
01907 break;
01908 }
01909 }
01910 if (!found) {
01911 if (MAX_UNIQUE_TYPES==num_unique_types) {
01912 msgErr << "Exceeded maximum number " << MAX_UNIQUE_TYPES
01913 << " of unique atom parameter types" << sendmsg;
01914 return -1;
01915 }
01916
01917 unique_occ[j].f = occupancy[i].f;
01918 unique_rad[j].f = radius[i].f;
01919 num_unique_types++;
01920 }
01921 atomtypes[i] = j;
01922 }
01923
01924 vdwparams = new float[2*num_unique_types];
01925 for (j=0; j<num_unique_types; j++) {
01926
01927 if ( !(unique_occ[j].f <= 0.f && unique_rad[j].f > 0.f) ) {
01928 msgErr << "Found invalid VDW parameters " << j
01929 << ": occupancy=" << unique_occ[j].f
01930 << ", radius=" << unique_rad[j].f
01931 << sendmsg;
01932 return -1;
01933 }
01934
01935
01936
01937 vdwparams[2*j ] = sqrtf(-unique_occ[j].f);
01938 vdwparams[2*j+1] = unique_rad[j].f;
01939 }
01940 delete [] unique_occ;
01941 delete [] unique_rad;
01942
01943 msgInfo << "Number of atom types: " << num_unique_types << sendmsg;
01944
01945 #if 0
01946 float *epsilon = new float[mol->nAtoms];
01947 for (i=0; i<mol->nAtoms; i++) {
01948
01949
01950
01951 epsilon[i] = sqrtf(-occupancy[i]);
01952 }
01953
01954 atomtypes = new int[mol->nAtoms];
01955 atomtypes[0] = 0;
01956 float *unique_eps = new float[mol->nAtoms];
01957 float *unique_rad = new float[mol->nAtoms];
01958 unique_eps[0] = epsilon[0];
01959 unique_rad[0] = radius[0];
01960 num_unique_types = 1;
01961
01962 for (i=1; i<mol->nAtoms; i++) {
01963 int found = 0;
01964
01965
01966 for (j=0; j<num_unique_types; j++) {
01967 if (epsilon[i]==unique_eps[j] && radius[i]==unique_rad[j]) {
01968 found = 1;
01969 break;
01970 }
01971 }
01972 if (!found) {
01973
01974 unique_eps[j] = epsilon[i];
01975 unique_rad[j] = radius[i];
01976 num_unique_types++;
01977 }
01978 atomtypes[i] = j;
01979 }
01980
01981 vdwparams = new float[2*num_unique_types];
01982 for (j=0; j<num_unique_types; j++) {
01983 vdwparams[2*j ] = unique_eps[j];
01984 vdwparams[2*j+1] = unique_rad[j];
01985
01986 }
01987 delete [] epsilon;
01988 delete [] unique_eps;
01989 delete [] unique_rad;
01990
01991 msgInfo << "Number of atom types: " << num_unique_types << sendmsg;
01992 #endif
01993
01994 return 0;
01995 }
01996
01997
01998
01999 int VolMapCreateILS::compute() {
02000 int numframes = app->molecule_numframes(molid);
02001 if (first<0 || last>=numframes) return -1;
02002
02003 int err = initialize();
02004 if (err) return err;
02005
02006 int n, frame;
02007 int gridsize = nsampx*nsampy*nsampz;
02008 float *frame_voldata = new float[gridsize];
02009 float *combo_voldata = new float[gridsize];
02010 if (maskonly) {
02011
02012 for (n=0; n<gridsize; n++) {
02013 combo_voldata[n] = 1.f;
02014 frame_voldata[n] = 1.f;
02015 }
02016 } else {
02017 memset(combo_voldata, 0, gridsize*sizeof(float));
02018 }
02019
02020 msgInfo << "Processing frames " << first << "-" << last
02021 << ", " << last-first+1 << " frames in total..." << sendmsg;
02022
02023 computed_frames = 0;
02024
02025 wkf_timerhandle timer = wkf_timer_create();
02026 wkf_timerhandle alltimer = wkf_timer_create();
02027 wkf_timer_start(alltimer);
02028
02029
02030 for (frame=first; frame<=last; frame++) {
02031 msgInfo << "ILS frame " << frame-first+1 << "/" << last-first+1;
02032
02033 #ifdef TIMING
02034 msgInfo << sendmsg;
02035 #else
02036 msgInfo << " ";
02037 #endif
02038
02039 wkf_timer_start(timer);
02040
02041
02042 compute_frame(frame, frame_voldata);
02043
02044 msgInfo << "Total frame time = " << wkf_timer_timenow(timer) << " s" << sendmsg;
02045
02046 if (maskonly) {
02047 for (n=0; n<gridsize; n++) {
02048 combo_voldata[n] *= frame_voldata[n];
02049 }
02050 } else {
02051
02052
02053
02054 int numexcl = 0;
02055 for (n=0; n<gridsize; n++) {
02056 combo_voldata[n] += frame_voldata[n];
02057 if (frame_voldata[n]<=min_occup) numexcl++;
02058 }
02059
02060 }
02061
02062 computed_frames++;
02063 }
02064
02065 double allframetime = wkf_timer_timenow(alltimer);
02066
02067
02068 if (nsubsamp>1||1) {
02069 int ndownsampx = volmap->xsize;
02070 int ndownsampy = volmap->ysize;
02071 int ix, iy, iz;
02072
02073 if (maskonly) {
02074 for (iz=0; iz<nsampz; iz++) {
02075 int isubz = iz/nsubsamp*ndownsampy*ndownsampx;
02076 for (iy=0; iy<nsampy; iy++) {
02077 int isuby = iy/nsubsamp*ndownsampx;
02078 for (ix=0; ix<nsampx; ix++) {
02079 n = iz*nsampy*nsampx + iy*nsampx + ix;
02080 float val = combo_voldata[n];
02081 int m = isubz + isuby + ix/nsubsamp;
02082
02083
02084 volmap->data[m] *= val;
02085 }
02086 }
02087 }
02088
02089 } else {
02090 for (iz=0; iz<nsampz; iz++) {
02091 int isubz = iz/nsubsamp*ndownsampy*ndownsampx;
02092 for (iy=0; iy<nsampy; iy++) {
02093 int isuby = iy/nsubsamp*ndownsampx;
02094 for (ix=0; ix<nsampx; ix++) {
02095 n = iz*nsampy*nsampx + iy*nsampx + ix;
02096 float val = combo_voldata[n];
02097 int m = isubz + isuby + ix/nsubsamp;
02098
02099 volmap->data[m] += val;
02100 }
02101 }
02102 }
02103
02104
02105
02106 float nsamppercell = float(nsubsamp*nsubsamp*nsubsamp*computed_frames);
02107 for (n=0; n<volmap->gridsize(); n++) {
02108 volmap->data[n] = volmap->data[n]/nsamppercell;
02109 }
02110 }
02111
02112 if (!maskonly) {
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122 for (n=0; n<volmap->gridsize(); n++) {
02123 float val = volmap->data[n];
02124 if (val<=min_occup) {
02125 volmap->data[n] = max_energy;
02126 } else {
02127 val = -logf(val);
02128 if (val > max_energy) val = max_energy;
02129 volmap->data[n] = val;
02130 }
02131 }
02132 }
02133 }
02134
02135 delete[] frame_voldata;
02136 delete[] combo_voldata;
02137
02138 msgInfo << "#################################################"
02139 << sendmsg << sendmsg;
02140 msgInfo << "Total time for all frames = "
02141 << allframetime << " s" << sendmsg;
02142 msgInfo << "Avg time per frame = "
02143 << allframetime/(last-first+1) << " s" << sendmsg;
02144 msgInfo << "Downsampling = "
02145 << wkf_timer_timenow(alltimer)-allframetime << " s"
02146 << sendmsg << sendmsg;
02147 msgInfo << "#################################################"
02148 << sendmsg << sendmsg;
02149
02150 wkf_timer_destroy(timer);
02151 wkf_timer_destroy(alltimer);
02152
02153 return 0;
02154 }
02155
02156
02157
02158
02159 void VolMapCreateILS::align_frame(Molecule *mol, int frame, float *coords,
02160 Matrix4 &alignment) {
02161
02162
02163 if (alignsel) {
02164 int i;
02165 int save_frame_alignsel = alignsel->which_frame;
02166
02167 alignsel->which_frame = frame;
02168 alignsel->change(NULL, mol);
02169
02170 float *weight = new float[alignsel->selected];
02171 for (i=0; i<alignsel->selected; i++) weight[i] = 1.0;
02172
02173 measure_fit(alignsel, alignsel, coords, alignrefpos, weight, NULL, &alignment);
02174 delete[] weight;
02175
02176 if (!getenv("VMDILSALIGNMAPS")) {
02177
02178
02179
02180 for (i=0; i < mol->nAtoms; i++) {
02181 alignment.multpoint3d(coords, coords);
02182 coords += 3;
02183 }
02184 }
02185
02186 alignsel->which_frame = save_frame_alignsel;
02187 }
02188
02189
02190 alignment.multmatrix(transform);
02191 }
02192
02193
02194
02195
02196
02197
02198
02199 int VolMapCreateILS::get_atom_coordinates(int frame, Matrix4 &alignment,
02200 int *(&vdwtypes),
02201 float *(&coords)) {
02202 wkf_timerhandle timer = wkf_timer_create();
02203 wkf_timer_start(timer);
02204
02205
02206
02207 int *selon = new int[num_atoms];
02208 memset(selon, 0, num_atoms*sizeof(int));
02209
02210 float minx = minmax[0]-extcutoff;
02211 float miny = minmax[1]-extcutoff;
02212 float minz = minmax[2]-extcutoff;
02213 float maxx = minmax[3]+extcutoff;
02214 float maxy = minmax[4]+extcutoff;
02215 float maxz = minmax[5]+extcutoff;
02216
02217 int numselected = 0;
02218 int i;
02219 for (i=0; i<num_atoms; i++) {
02220 float x = coords[3*i ];
02221 float y = coords[3*i+1];
02222 float z = coords[3*i+2];
02223 if (x>=minx && x<=maxx &&
02224 y>=miny && y<=maxy &&
02225 z>=minz && z<=maxz) {
02226 selon[i] = 1;
02227 numselected++;
02228 }
02229 }
02230
02231 int numcoords = numselected;
02232
02233 float *selcoords = NULL;
02234
02235
02236
02237
02238 if (pbc) {
02239
02240 float ffcutoff[3];
02241 ffcutoff[0] = ffcutoff[1] = ffcutoff[2] = cutoff;
02242
02243
02244 ResizeArray<float> extcoord_array;
02245
02246
02247
02248 ResizeArray<int> indexmap_array;
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258 measure_pbc_neighbors(app->moleculeList, NULL, molid, frame,
02259 &alignment, pbccenter, ffcutoff, minmax,
02260 &extcoord_array, &indexmap_array);
02261
02262 numcoords = numselected+indexmap_array.num();
02263
02264 selcoords = new float[3*numcoords];
02265 vdwtypes = new int[numcoords];
02266
02267 int j = numselected;
02268 for (i=0; i<indexmap_array.num(); i++) {
02269 selcoords[3*j ] = extcoord_array[3*i ];
02270 selcoords[3*j+1] = extcoord_array[3*i+1];
02271 selcoords[3*j+2] = extcoord_array[3*i+2];
02272 vdwtypes[j] = atomtypes[indexmap_array[i]];
02273 j++;
02274 }
02275
02276
02277 } else {
02278 selcoords = new float[3*numcoords];
02279 vdwtypes = new int[numcoords];
02280 }
02281
02282
02283 int j=0;
02284 for (i=0; i<num_atoms; i++) {
02285 if (!selon[i]) continue;
02286 selcoords[3*j ] = coords[3*i ];
02287 selcoords[3*j+1] = coords[3*i+1];
02288 selcoords[3*j+2] = coords[3*i+2];
02289 vdwtypes[j] = atomtypes[i];
02290 j++;
02291 }
02292
02293
02294 coords = selcoords;
02295
02296 delete [] selon;
02297
02298 #ifdef TIMING
02299 msgInfo << "Coord setup: " << wkf_timer_timenow(timer) << " s" << sendmsg;
02300 #endif
02301 wkf_timer_destroy(timer);
02302
02303 return numcoords;
02304 }
02305
02306
02307
02309
02311
02312
02313 int VolMapCreateILS::compute_frame(int frame, float *voldata) {
02314 Matrix4 alignment;
02315 float *coords;
02316
02317 Molecule *mol = app->moleculeList->mol_from_id(molid);
02318 if (!mol) return -1;
02319
02320 #ifdef TIMING
02321 char report[128] = { 0 };
02322 wkf_timerhandle timer = wkf_timer_create();
02323 #endif
02324
02325
02326 coords = mol->get_frame(frame)->pos;
02327
02328
02329
02330
02331 align_frame(mol, frame, coords, alignment);
02332
02333 if (maskonly) {
02334 #ifdef TIMING
02335 wkf_timer_start(timer);
02336 #endif
02337
02338
02339
02340
02341
02342 grid_inside_pbccell(frame, voldata, alignment);
02343
02344 #ifdef TIMING
02345 msgInfo << "Masking: " << wkf_timer_timenow(timer) << " s" << sendmsg;
02346 #endif
02347
02348 return MEASURE_NOERR;
02349 }
02350
02351
02352
02353
02354
02355 int *vdwtypes = NULL;
02356 int numcoords;
02357 float originalign[3];
02358 float axesalign[9];
02359 float gridaxes[9];
02360 memset(gridaxes, 0, 9*sizeof(float));
02361 gridaxes[0] = gridaxes[4] = gridaxes[8] = 1.f;
02362
02363 if (getenv("VMDILSALIGNMAPS")) {
02364
02365 numcoords = num_atoms;
02366 vdwtypes = atomtypes;
02367 alignment.multpoint3d(gridorigin, originalign);
02368 alignment.multpoint3d(&gridaxes[0], &axesalign[0]);
02369 alignment.multpoint3d(&gridaxes[3], &axesalign[3]);
02370 alignment.multpoint3d(&gridaxes[6], &axesalign[6]);
02371 msgInfo << "Aligning maps." << sendmsg;
02372 } else {
02373
02374 numcoords = get_atom_coordinates(frame, alignment,
02375 vdwtypes, coords);
02376 memcpy(originalign, gridorigin, 3*sizeof(float));
02377 memcpy(axesalign, gridaxes, 9*sizeof(float));
02378 msgInfo << "Aligning frames." << sendmsg;
02379 }
02380
02381 if (getenv("VMDALLATOMILS")) {
02382 #ifdef TIMING
02383 wkf_timer_start(timer);
02384 #endif
02385
02386
02387 float lenx = float(nsampx*delta);
02388 float leny = float(nsampy*delta);
02389 float lenz = float(nsampz*delta);
02390
02391 compute_allatoms(voldata, nsampx, nsampy, nsampz,
02392 lenx, leny, lenz, originalign, axesalign,
02393 alignment.mat, numcoords, coords,
02394 vdwtypes, vdwparams, cutoff, probe_vdw, num_probe_atoms,
02395 num_conformers, conformers, max_energy);
02396
02397 #ifdef TIMING
02398 sprintf(report, "compute_allatoms() "
02399 "%f s\n", wkf_timer_timenow(timer));
02400 msgInfo << report << sendmsg;
02401 #endif
02402
02403 } else {
02404
02405 #ifdef TIMING
02406 wkf_timer_start(timer);
02407 #endif
02408
02409
02410 float lenx = float(nsampx*delta);
02411 float leny = float(nsampy*delta);
02412 float lenz = float(nsampz*delta);
02413
02414 int retval;
02415
02416 ComputeOccupancyMap om;
02417
02418
02419 om.map = voldata;
02420 om.mx = nsampx;
02421 om.my = nsampy;
02422 om.mz = nsampz;
02423 om.lx = lenx;
02424 om.ly = leny;
02425 om.lz = lenz;
02426 om.x0 = originalign[0];
02427 om.y0 = originalign[1];
02428 om.z0 = originalign[2];
02429 memcpy(om.ax, &axesalign[0], 3*sizeof(float));
02430 memcpy(om.ay, &axesalign[3], 3*sizeof(float));
02431 memcpy(om.az, &axesalign[6], 3*sizeof(float));
02432 memcpy(om.alignmat, alignment.mat, 16*sizeof(float));
02433 om.num_coords = numcoords;
02434 om.coords = coords;
02435 om.vdw_type = vdwtypes;
02436 om.vdw_params = vdwparams;
02437 om.probe_vdw_params = probe_vdw;
02438 om.conformers = conformers;
02439 om.num_probes = num_probe_atoms;
02440 om.num_conformers = num_conformers;
02441 om.cutoff = cutoff;
02442 om.extcutoff = extcutoff;
02443 om.excl_dist = excl_dist;
02444 om.excl_energy = max_energy;
02445
02446
02447 om.kstart = 0;
02448 om.kstop = om.mz;
02449
02450 retval = ComputeOccupancyMap_setup(&om);
02451
02452 #ifdef TIMING
02453 sprintf(report, "ComputeOccupancyMap_setup() "
02454 "%f s\n", wkf_timer_timenow(timer));
02455 msgInfo << report << sendmsg;
02456 #endif
02457
02458 if (getenv("VMDILSVERBOSE")) {
02459 atom_bin_stats(&om
02460
02461
02462
02463 );
02464 }
02465
02466 if (retval != 0) {
02467 if (getenv("VMDILSVERBOSE")) {
02468 int i, j, k;
02469 int total_extra_atoms = 0;
02470 for (k = 0; k < om.nbz; k++) {
02471 for (j = 0; j < om.nby; j++) {
02472 for (i = 0; i < om.nbx; i++) {
02473 int index = (k*om.nby + j)*om.nbx + i;
02474 if (om.bincnt[index] > BIN_DEPTH) {
02475 printf("*** bin[%d,%d,%d] tried to fill with %d atoms\n",
02476 i, j, k, om.bincnt[index]);
02477 total_extra_atoms += om.bincnt[index] - BIN_DEPTH;
02478 }
02479 }
02480 }
02481 }
02482
02483 printf("*** can't handle total of %d extra atoms\n", total_extra_atoms);
02484 }
02485 ComputeOccupancyMap_cleanup(&om);
02486 return -1;
02487 }
02488
02489 #if defined(VMDCUDA)
02490 if (getenv("VMDILSVERBOSE")) {
02491 printf("*** cpu only = %d\n", om.cpu_only);
02492 }
02493 if (!getenv("VMDNOCUDA") && !(om.cpu_only) &&
02494 (retval=
02495 vmd_cuda_evaluate_occupancy_map(om.mx, om.my, om.mz, om.map,
02496 om.excl_energy, om.cutoff, om.hx, om.hy, om.hz,
02497 om.x0, om.y0, om.z0, om.bx_1, om.by_1, om.bz_1,
02498 om.nbx, om.nby, om.nbz, (float *) om.bin, (float *) om.bin_zero,
02499 om.num_bin_offsets, om.bin_offsets,
02500 om.num_extras, (float *) om.extra,
02501 num_unique_types, om.vdw_params,
02502 om.num_probes, om.probe_vdw_params,
02503 om.num_conformers, om.conformers)) == 0) {
02504
02505 } else {
02506 if (retval != 0) {
02507 msgInfo << "vmd_cuda_evaluate_occupancy_map() FAILED,"
02508 " using CPU for calculation\n" << sendmsg;
02509 }
02510 #endif
02511
02512 #ifdef TIMING
02513 wkf_timer_start(timer);
02514 #endif
02515
02516 retval = ComputeOccupancyMap_calculate_slab(&om);
02517
02518 #ifdef TIMING
02519 sprintf(report, "ComputeOccupancyMap_calculate_slab() "
02520 "%f s\n", wkf_timer_timenow(timer));
02521 msgInfo << report << sendmsg;
02522 #endif
02523
02524 if (retval != 0) {
02525 if (getenv("VMDILSVERBOSE")) {
02526 printf("*** ComputeOccupancyMap_calculate_slab() failed\n");
02527 }
02528 ComputeOccupancyMap_cleanup(&om);
02529 return -1;
02530 }
02531
02532 #if defined(VMDCUDA)
02533 }
02534 #endif
02535
02536 ComputeOccupancyMap_cleanup(&om);
02537 }
02538
02539 if (!getenv("VMDILSALIGNMAPS")) {
02540 delete[] coords;
02541 delete[] vdwtypes;
02542 }
02543
02544 #ifdef TIMING
02545 wkf_timer_destroy(timer);
02546 #endif
02547
02548 return MEASURE_NOERR;
02549 }
02550
02551
02553
02555
02556 static int fill_atom_bins(ComputeOccupancyMap *p);
02557 static void tighten_bin_neighborhood(ComputeOccupancyMap *p);
02558 static void find_distance_exclusions(ComputeOccupancyMap *p);
02559 static void find_energy_exclusions(ComputeOccupancyMap *p);
02560 static void compute_occupancy_monoatom(ComputeOccupancyMap *p);
02561 static void compute_occupancy_multiatom(ComputeOccupancyMap *p);
02562
02563
02564 int ComputeOccupancyMap_setup(ComputeOccupancyMap *p) {
02565
02566
02567 p->bin = NULL;
02568 p->bin_zero = NULL;
02569 p->bincnt = NULL;
02570 p->bincnt_zero = NULL;
02571 p->bin_offsets = NULL;
02572 p->extra = NULL;
02573 p->exclusions = NULL;
02574
02575
02576 int mtotal = p->mx * p->my * p->mz;
02577 memset(p->map, 0, mtotal * sizeof(float));
02578 p->exclusions = new char[mtotal];
02579 memset(p->exclusions, 0, mtotal * sizeof(char));
02580
02581
02582 p->hx = p->lx / p->mx;
02583 p->hy = p->ly / p->my;
02584 p->hz = p->lz / p->mz;
02585
02586 p->cpu_only = 0;
02587
02588
02589
02590
02591
02592
02593
02594
02595
02596 p->mpblx = 12;
02597 p->mpbly = 12;
02598 p->mpblz = 12;
02599
02600
02601 p->bx = p->mpblx * p->hx;
02602 p->by = p->mpbly * p->hy;
02603 p->bz = p->mpblz * p->hz;
02604
02605
02606 while (p->bx * p->by * p->bz > MAX_BIN_VOLUME) {
02607
02608
02609 if (p->bx > p->by && p->bx > p->bz) {
02610 p->mpblx -= 4;
02611 p->bx = p->mpblx * p->hx;
02612 }
02613 else if (p->by >= p->bx && p->by > p->bz) {
02614 p->mpbly -= 4;
02615 p->by = p->mpbly * p->hy;
02616 }
02617 else {
02618 p->mpblz -= 4;
02619 p->bz = p->mpblz * p->hz;
02620 }
02621
02622 }
02623
02624 if (p->bx * p->by * p->bz < MIN_BIN_VOLUME) {
02625
02626
02627 p->bx = p->by = p->bz = DEFAULT_BIN_LENGTH;
02628 p->mpblx = p->mpbly = p->mpblz = 0;
02629 p->cpu_only = 1;
02630 }
02631
02632 p->bx_1 = 1.f / p->bx;
02633 p->by_1 = 1.f / p->by;
02634 p->bz_1 = 1.f / p->bz;
02635
02636 if (fill_atom_bins(p)) {
02637 return -1;
02638 }
02639
02640 tighten_bin_neighborhood(p);
02641
02642 return 0;
02643 }
02644
02645
02646 int ComputeOccupancyMap_calculate_slab(ComputeOccupancyMap *p) {
02647 #ifdef TIMING
02648 char report[128] = { 0 };
02649 wkf_timerhandle timer = wkf_timer_create();
02650 #endif
02651
02652
02653
02654
02655
02656
02657 #if 1
02658 #ifdef TIMING
02659 wkf_timer_start(timer);
02660 #endif
02661 find_distance_exclusions(p);
02662 int i, numexcl=0;
02663 for (i=0; i<p->mx * p->my * p->mz; i++) {
02664 if (p->exclusions[i]) numexcl++;
02665 }
02666 #ifdef TIMING
02667 sprintf(report, "ComputeOccupancyMap: find_distance_exclusions() "
02668 "%f s\n", wkf_timer_timenow(timer));
02669 msgInfo << report << sendmsg;
02670 #endif
02671 #endif
02672
02673 if (1 == p->num_probes) {
02674 #ifdef TIMING
02675 wkf_timer_start(timer);
02676 #endif
02677 compute_occupancy_monoatom(p);
02678 #ifdef TIMING
02679 sprintf(report, "ComputeOccupancyMap: compute_occupancy_monoatom() "
02680 "%f s\n", wkf_timer_timenow(timer));
02681 msgInfo << report << sendmsg;
02682 #endif
02683
02684 }
02685 else {
02686
02687 #if 1
02688 #ifdef TIMING
02689 wkf_timer_start(timer);
02690 #endif
02691 find_energy_exclusions(p);
02692 int i, numexcl=0;
02693 for (i=0; i<p->mx * p->my * p->mz; i++) {
02694 if (p->exclusions[i]) numexcl++;
02695 }
02696 #ifdef TIMING
02697 sprintf(report, "ComputeOccupancyMap: find_energy_exclusions() "
02698 "%f s -> %d exclusions\n", wkf_timer_timenow(timer), numexcl);
02699 msgInfo << report << sendmsg;
02700 #endif
02701 #endif
02702
02703 #ifdef TIMING
02704 wkf_timer_start(timer);
02705 #endif
02706 compute_occupancy_multiatom(p);
02707 #ifdef TIMING
02708 sprintf(report, "ComputeOccupancyMap: compute_occupancy_multiatom() "
02709 "%f s\n", wkf_timer_timenow(timer));
02710 msgInfo << report << sendmsg;
02711 #endif
02712
02713 }
02714
02715 #ifdef TIMING
02716 wkf_timer_destroy(timer);
02717 #endif
02718
02719 return 0;
02720 }
02721
02722
02723 void ComputeOccupancyMap_cleanup(ComputeOccupancyMap *p) {
02724 delete[] p->bin_offsets;
02725 delete[] p->extra;
02726 delete[] p->bincnt;
02727 delete[] p->bin;
02728 delete[] p->exclusions;
02729 }
02730
02731
02732
02733
02734 #define MAX_EXTRA_ATOMS 50
02735
02736 int fill_atom_bins(ComputeOccupancyMap *p) {
02737 int too_many_extra_atoms = 0;
02738 int max_extra_atoms = MAX_EXTRA_ATOMS;
02739
02740
02741 int count_extras = 0;
02742 int n, i, j, k;
02743
02744 const int *vdw_type = p->vdw_type;
02745 const float *coords = p->coords;
02746 const int num_coords = p->num_coords;
02747 const float lx = p->lx;
02748 const float ly = p->ly;
02749 const float lz = p->lz;
02750 const float bx_1 = p->bx_1;
02751 const float by_1 = p->by_1;
02752 const float bz_1 = p->bz_1;
02753 const float x0 = p->x0;
02754 const float y0 = p->y0;
02755 const float z0 = p->z0;
02756 const float extcutoff = p->extcutoff;
02757
02758
02759 p->padx = (int) ceilf(extcutoff * bx_1);
02760 p->pady = (int) ceilf(extcutoff * by_1);
02761 p->padz = (int) ceilf(extcutoff * bz_1);
02762
02763 const int nbx = p->nbx = (int) ceilf(lx * bx_1) + 2*p->padx;
02764 const int nby = p->nby = (int) ceilf(ly * by_1) + 2*p->pady;
02765 p->nbz = (int) ceilf(lz * bz_1) + 2*p->padz;
02766
02767 int nbins = nbx * nby * p->nbz;
02768
02769 BinOfAtoms *bin = p->bin = new BinOfAtoms[nbins];
02770 char *bincnt = p->bincnt = new char[nbins];
02771 AtomPosType *extra = p->extra = new AtomPosType[max_extra_atoms];
02772
02773 memset(bin, 0, nbins * sizeof(BinOfAtoms));
02774 memset(bincnt, 0, nbins * sizeof(char));
02775
02776
02777
02778 BinOfAtoms *bin_zero
02779 = p->bin_zero = bin + ((p->padz*nby + p->pady)*nbx + p->padx);
02780 char *bincnt_zero
02781 = p->bincnt_zero = bincnt + ((p->padz*nby + p->pady)*nbx + p->padx);
02782
02783 for (n = 0; n < num_coords; n++) {
02784 float x = coords[3*n ];
02785 float y = coords[3*n + 1];
02786 float z = coords[3*n + 2];
02787
02788 float sx = x - x0;
02789 float sy = y - y0;
02790 float sz = z - z0;
02791
02792 if (sx < -extcutoff || sx > lx + extcutoff ||
02793 sy < -extcutoff || sy > ly + extcutoff ||
02794 sz < -extcutoff || sz > lz + extcutoff) {
02795 continue;
02796 }
02797
02798 i = (int) floorf(sx * bx_1);
02799 j = (int) floorf(sy * by_1);
02800 k = (int) floorf(sz * bz_1);
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811 int index = (k*nby + j)*nbx + i;
02812 int slot = bincnt_zero[index];
02813
02814 if (slot < BIN_DEPTH) {
02815 AtomPosType *atom = bin_zero[index].atom;
02816 atom[slot].x = x;
02817 atom[slot].y = y;
02818 atom[slot].z = z;
02819 atom[slot].vdwtype = vdw_type[n];
02820 }
02821 else if (count_extras < max_extra_atoms) {
02822 extra[count_extras].x = x;
02823 extra[count_extras].y = y;
02824 extra[count_extras].z = z;
02825 extra[count_extras].vdwtype = vdw_type[n];
02826 count_extras++;
02827 }
02828 else {
02829
02830 printf("*** too many extras, atom index %d\n", n);
02831 too_many_extra_atoms = 1;
02832 }
02833
02834 bincnt_zero[index]++;
02835 }
02836 p->num_extras = count_extras;
02837
02838
02839
02840 for (n = 0; n < nbins; n++) {
02841 for (k = bincnt[n]; k < BIN_DEPTH; k++) {
02842 bin[n].atom[k].vdwtype = -1;
02843 }
02844 }
02845
02846 return (too_many_extra_atoms ? -1 : 0);
02847 }
02848
02849
02850
02851 void tighten_bin_neighborhood(ComputeOccupancyMap *p) {
02852 const int padx = p->padx;
02853 const int pady = p->pady;
02854 const int padz = p->padz;
02855 const float bx2 = p->bx * p->bx;
02856 const float by2 = p->by * p->by;
02857 const float bz2 = p->bz * p->bz;
02858 const float r = p->extcutoff + sqrtf(bx2 + by2 + bz2);
02859 const float r2 = r*r;
02860 int n = 0, i, j, k;
02861 char *bin_offsets
02862 = p->bin_offsets = new char[3 * (2*padx+1)*(2*pady+1)*(2*padz+1)];
02863 for (k = -padz; k <= padz; k++) {
02864 for (j = -pady; j <= pady; j++) {
02865 for (i = -padx; i <= padx; i++) {
02866 if (i*i*bx2 + j*j*by2 + k*k*bz2 >= r2) continue;
02867 bin_offsets[3*n ] = (char) i;
02868 bin_offsets[3*n + 1] = (char) j;
02869 bin_offsets[3*n + 2] = (char) k;
02870 n++;
02871 }
02872 }
02873 }
02874 p->num_bin_offsets = n;
02875 }
02876
02877
02878
02879
02880
02881
02882
02883 void find_distance_exclusions(ComputeOccupancyMap *p) {
02884 const AtomPosType *extra = p->extra;
02885 const BinOfAtoms *bin_zero = p->bin_zero;
02886 char *excl = p->exclusions;
02887
02888 int i, j, k, n, index;
02889 int ic, jc, kc;
02890
02891 const int mx = p->mx;
02892 const int my = p->my;
02893 const int kstart = p->kstart;
02894 const int kstop = p->kstop;
02895 const int nbx = p->nbx;
02896 const int nby = p->nby;
02897 const float excl_dist = p->excl_dist;
02898 const float bx_1 = p->bx_1;
02899 const float by_1 = p->by_1;
02900 const float bz_1 = p->bz_1;
02901 const float hx = p->hx;
02902 const float hy = p->hy;
02903 const float hz = p->hz;
02904 const float x0 = p->x0;
02905 const float y0 = p->y0;
02906 const float z0 = p->z0;
02907 const int num_extras = p->num_extras;
02908 const int bdx = (int) ceilf(excl_dist * bx_1);
02909 const int bdy = (int) ceilf(excl_dist * by_1);
02910 const int bdz = (int) ceilf(excl_dist * bz_1);
02911 const float excldist2 = excl_dist * excl_dist;
02912
02913 for (k = kstart; k < kstop; k++) {
02914 for (j = 0; j < my; j++) {
02915 for (i = 0; i < mx; i++) {
02916
02917 float px = i*hx;
02918 float py = j*hy;
02919 float pz = k*hz;
02920
02921 int ib = (int) floorf(px * bx_1);
02922 int jb = (int) floorf(py * by_1);
02923 int kb = (int) floorf(pz * bz_1);
02924
02925 px += x0;
02926 py += y0;
02927 pz += z0;
02928
02929 for (kc = kb - bdz; kc <= kb + bdz; kc++) {
02930 for (jc = jb - bdy; jc <= jb + bdy; jc++) {
02931 for (ic = ib - bdx; ic <= ib + bdx; ic++) {
02932
02933 const AtomPosType *atom
02934 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
02935
02936 for (n = 0; n < BIN_DEPTH; n++) {
02937 if (-1 == atom[n].vdwtype) break;
02938 float dx = px - atom[n].x;
02939 float dy = py - atom[n].y;
02940 float dz = pz - atom[n].z;
02941 float r2 = dx*dx + dy*dy + dz*dz;
02942 if (r2 <= excldist2) {
02943 index = (k*my + j)*mx + i;
02944 excl[index] = 1;
02945 goto NEXT_MAP_POINT;
02946 }
02947 }
02948
02949 }
02950 }
02951 }
02952
02953 for (n = 0; n < num_extras; n++) {
02954 float dx = px - extra[n].x;
02955 float dy = py - extra[n].y;
02956 float dz = pz - extra[n].z;
02957 float r2 = dx*dx + dy*dy + dz*dz;
02958 if (r2 <= excldist2) {
02959 index = (k*my + j)*mx + i;
02960 excl[index] = 1;
02961 goto NEXT_MAP_POINT;
02962 }
02963 }
02964
02965 NEXT_MAP_POINT:
02966 ;
02967
02968 }
02969 }
02970 }
02971
02972 }
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982 void find_energy_exclusions(ComputeOccupancyMap *p) {
02983 const char *bin_offsets = p->bin_offsets;
02984 const float *vdw_params = p->vdw_params;
02985 const AtomPosType *extra = p->extra;
02986 const BinOfAtoms *bin_zero = p->bin_zero;
02987 char *excl = p->exclusions;
02988
02989 const float probe_vdweps = p->probe_vdw_params[0];
02990 const float probe_vdwrmin = p->probe_vdw_params[1];
02991
02992 const int mx = p->mx;
02993 const int my = p->my;
02994 const int kstart = p->kstart;
02995 const int kstop = p->kstop;
02996 const int nbx = p->nbx;
02997 const int nby = p->nby;
02998 const float hx = p->hx;
02999 const float hy = p->hy;
03000 const float hz = p->hz;
03001 const float bx_1 = p->bx_1;
03002 const float by_1 = p->by_1;
03003 const float bz_1 = p->bz_1;
03004 const float x0 = p->x0;
03005 const float y0 = p->y0;
03006 const float z0 = p->z0;
03007 const int num_bin_offsets = p->num_bin_offsets;
03008 const int num_extras = p->num_extras;
03009 const float excl_energy = p->excl_energy;
03010
03011 int i, j, k, n, index;
03012 const float cutoff2 = p->cutoff * p->cutoff;
03013
03014 for (k = kstart; k < kstop; k++) {
03015 for (j = 0; j < my; j++) {
03016 for (i = 0; i < mx; i++) {
03017
03018 int lindex = (k*my + j)*mx + i;
03019 if (excl[lindex]) continue;
03020
03021 float px = i*hx;
03022 float py = j*hy;
03023 float pz = k*hz;
03024
03025 int ib = (int) floorf(px * bx_1);
03026 int jb = (int) floorf(py * by_1);
03027 int kb = (int) floorf(pz * bz_1);
03028
03029 px += x0;
03030 py += y0;
03031 pz += z0;
03032
03033 float u = 0.f;
03034
03035 for (index = 0; index < num_bin_offsets; index++) {
03036 int ic = ib + (int) bin_offsets[3*index ];
03037 int jc = jb + (int) bin_offsets[3*index + 1];
03038 int kc = kb + (int) bin_offsets[3*index + 2];
03039
03040 const AtomPosType *atom
03041 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03042
03043 for (n = 0; n < BIN_DEPTH; n++) {
03044 if (-1 == atom[n].vdwtype) break;
03045 float dx = px - atom[n].x;
03046 float dy = py - atom[n].y;
03047 float dz = pz - atom[n].z;
03048 float r2 = dx*dx + dy*dy + dz*dz;
03049 if (r2 >= cutoff2) continue;
03050 int pindex = 2 * atom[n].vdwtype;
03051 float epsilon = vdw_params[pindex] * probe_vdweps;
03052 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03053 float rm6 = rmin*rmin / r2;
03054 rm6 = rm6 * rm6 * rm6;
03055 u += epsilon * rm6 * (rm6 - 2.f);
03056 }
03057
03058 }
03059
03060 for (n = 0; n < num_extras; n++) {
03061 float dx = px - extra[n].x;
03062 float dy = py - extra[n].y;
03063 float dz = pz - extra[n].z;
03064 float r2 = dx*dx + dy*dy + dz*dz;
03065 if (r2 >= cutoff2) continue;
03066 int pindex = 2 * extra[n].vdwtype;
03067 float epsilon = vdw_params[pindex] * probe_vdweps;
03068 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03069 float rm6 = rmin*rmin / r2;
03070 rm6 = rm6 * rm6 * rm6;
03071 u += epsilon * rm6 * (rm6 - 2.f);
03072 }
03073
03074 if (u >= excl_energy) excl[lindex] = 1;
03075
03076 }
03077 }
03078 }
03079
03080 }
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093 void compute_occupancy_monoatom(ComputeOccupancyMap *p) {
03094 const char *bin_offsets = p->bin_offsets;
03095 const float *vdw_params = p->vdw_params;
03096 const AtomPosType *extra = p->extra;
03097 const BinOfAtoms *bin_zero = p->bin_zero;
03098 const char *excl = p->exclusions;
03099 float *map = p->map;
03100
03101 const int mx = p->mx;
03102 const int my = p->my;
03103 const int kstart = p->kstart;
03104 const int kstop = p->kstop;
03105 const int nbx = p->nbx;
03106 const int nby = p->nby;
03107 const float hx = p->hx;
03108 const float hy = p->hy;
03109 const float hz = p->hz;
03110 const float bx_1 = p->bx_1;
03111 const float by_1 = p->by_1;
03112 const float bz_1 = p->bz_1;
03113 const float x0 = p->x0;
03114 const float y0 = p->y0;
03115 const float z0 = p->z0;
03116 const int num_bin_offsets = p->num_bin_offsets;
03117 const int num_extras = p->num_extras;
03118
03119 float probe_vdweps = p->probe_vdw_params[0];
03120 float probe_vdwrmin = p->probe_vdw_params[1];
03121
03122 int i, j, k, n, index;
03123 float max_energy = p->excl_energy;
03124 float cutoff2 = p->cutoff * p->cutoff;
03125
03126 for (k = kstart; k < kstop; k++) {
03127 for (j = 0; j < my; j++) {
03128 for (i = 0; i < mx; i++) {
03129
03130 int lindex = (k*my + j)*mx + i;
03131 #if 1
03132 if (excl[lindex]) {
03133 map[lindex] = 0.f;
03134 continue;
03135 }
03136 #endif
03137
03138 float px = i*hx;
03139 float py = j*hy;
03140 float pz = k*hz;
03141
03142 int ib = (int) floorf(px * bx_1);
03143 int jb = (int) floorf(py * by_1);
03144 int kb = (int) floorf(pz * bz_1);
03145
03146 px += x0;
03147 py += y0;
03148 pz += z0;
03149
03150 float u = 0.f;
03151
03152 for (index = 0; index < num_bin_offsets; index++) {
03153 int ic = ib + (int) bin_offsets[3*index ];
03154 int jc = jb + (int) bin_offsets[3*index + 1];
03155 int kc = kb + (int) bin_offsets[3*index + 2];
03156
03157 const AtomPosType *atom
03158 = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03159
03160 for (n = 0; n < BIN_DEPTH; n++) {
03161 if (-1 == atom[n].vdwtype) break;
03162 float dx = px - atom[n].x;
03163 float dy = py - atom[n].y;
03164 float dz = pz - atom[n].z;
03165 float r2 = dx*dx + dy*dy + dz*dz;
03166 if (r2 >= cutoff2) continue;
03167 int pindex = 2 * atom[n].vdwtype;
03168 float epsilon = vdw_params[pindex] * probe_vdweps;
03169 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03170 float rm6 = rmin*rmin / r2;
03171 rm6 = rm6 * rm6 * rm6;
03172 u += epsilon * rm6 * (rm6 - 2.f);
03173 }
03174
03175 }
03176
03177 for (n = 0; n < num_extras; n++) {
03178 float dx = px - extra[n].x;
03179 float dy = py - extra[n].y;
03180 float dz = pz - extra[n].z;
03181 float r2 = dx*dx + dy*dy + dz*dz;
03182 if (r2 >= cutoff2) continue;
03183 int pindex = 2 * extra[n].vdwtype;
03184 float epsilon = vdw_params[pindex] * probe_vdweps;
03185 float rmin = vdw_params[pindex + 1] + probe_vdwrmin;
03186 float rm6 = rmin*rmin / r2;
03187 rm6 = rm6 * rm6 * rm6;
03188 u += epsilon * rm6 * (rm6 - 2.f);
03189 }
03190
03191 float occ = 0.f;
03192 if (u < max_energy) {
03193 occ = expf(-u);
03194 }
03195 map[lindex] = occ;
03196
03197 }
03198 }
03199 }
03200
03201 }
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211 void compute_occupancy_multiatom(ComputeOccupancyMap *p) {
03212 const char *bin_offsets = p->bin_offsets;
03213 const float *vdw_params = p->vdw_params;
03214 const float *probe_vdw_params = p->probe_vdw_params;
03215 const float *conformers = p->conformers;
03216 const AtomPosType *extra = p->extra;
03217 const float hx = p->hx;
03218 const float hy = p->hy;
03219 const float hz = p->hz;
03220 const float x0 = p->x0;
03221 const float y0 = p->y0;
03222 const float z0 = p->z0;
03223 const float bx_1 = p->bx_1;
03224 const float by_1 = p->by_1;
03225 const float bz_1 = p->bz_1;
03226 const float inv_num_conformers = 1.f / (float) p->num_conformers;
03227 const int num_bin_offsets = p->num_bin_offsets;
03228 const int num_extras = p->num_extras;
03229 const int num_probes = p->num_probes;
03230 const int num_conformers = p->num_conformers;
03231 const int nbx = p->nbx;
03232 const int nby = p->nby;
03233 const int mx = p->mx;
03234 const int my = p->my;
03235 const int kstart = p->kstart;
03236 const int kstop = p->kstop;
03237
03238 const BinOfAtoms *bin_zero = p->bin_zero;
03239 const char *excl = p->exclusions;
03240 float *map = p->map;
03241
03242 int i, j, k, n, nb;
03243
03244 const float minocc = expf(-p->excl_energy);
03245 const float cutoff2 = p->cutoff * p->cutoff;
03246
03247 float *u = new float[p->num_conformers];
03248
03249 for (k = kstart; k < kstop; k++) {
03250 for (j = 0; j < my; j++) {
03251 for (i = 0; i < mx; i++) {
03252
03253 int lindex = (k*my + j)*mx + i;
03254 if (excl[lindex]) {
03255 map[lindex] = 0.f;
03256 continue;
03257 }
03258
03259 float px = i*hx;
03260 float py = j*hy;
03261 float pz = k*hz;
03262
03263 int ib = (int) floorf(px * bx_1);
03264 int jb = (int) floorf(py * by_1);
03265 int kb = (int) floorf(pz * bz_1);
03266
03267 int m, ma;
03268
03269 px += x0;
03270 py += y0;
03271 pz += z0;
03272
03273 memset(u, 0, num_conformers * sizeof(float));
03274
03275 for (nb = 0; nb < num_bin_offsets; nb++) {
03276 int ic = ib + (int) bin_offsets[3*nb ];
03277 int jc = jb + (int) bin_offsets[3*nb + 1];
03278 int kc = kb + (int) bin_offsets[3*nb + 2];
03279
03280 const AtomPosType *atom = bin_zero[(kc*nby + jc)*nbx + ic].atom;
03281
03282 for (n = 0; n < BIN_DEPTH; n++) {
03283 if (-1 == atom[n].vdwtype) break;
03284
03285 for (m = 0; m < num_conformers; m++) {
03286 float v = 0.f;
03287 for (ma = 0; ma < num_probes; ma++) {
03288 int index = m*num_probes + ma;
03289 float dx = conformers[3*index ] + px - atom[n].x;
03290 float dy = conformers[3*index + 1] + py - atom[n].y;
03291 float dz = conformers[3*index + 2] + pz - atom[n].z;
03292 float r2 = dx*dx + dy*dy + dz*dz;
03293 if (r2 >= cutoff2) continue;
03294 int pindex = 2 * atom[n].vdwtype;
03295 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03296 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03297 float rm6 = rmin*rmin / r2;
03298 rm6 = rm6 * rm6 * rm6;
03299 v += epsilon * rm6 * (rm6 - 2.f);
03300 }
03301
03302 u[m] += v;
03303
03304 }
03305
03306 }
03307
03308 }
03309
03310 for (n = 0; n < num_extras; n++) {
03311 for (m = 0; m < num_conformers; m++) {
03312 float v = 0.f;
03313 for (ma = 0; ma < num_probes; ma++) {
03314 int index = m*num_probes + ma;
03315 float dx = conformers[3*index ] + px - extra[n].x;
03316 float dy = conformers[3*index + 1] + py - extra[n].y;
03317 float dz = conformers[3*index + 2] + pz - extra[n].z;
03318 float r2 = dx*dx + dy*dy + dz*dz;
03319 if (r2 >= cutoff2) continue;
03320 int pindex = 2 *extra[n].vdwtype;
03321 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03322 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03323 float rm6 = rmin*rmin / r2;
03324 rm6 = rm6 * rm6 * rm6;
03325 v += epsilon * rm6 * (rm6 - 2.f);
03326 }
03327
03328 u[m] += v;
03329
03330 }
03331 }
03332
03333
03334
03335 float z = 0.f;
03336 for (m = 0; m < num_conformers; m++) {
03337 z += expf(-u[m]);
03338 }
03339
03340 float occ = z * inv_num_conformers;
03341 map[lindex] = (occ > minocc ? occ : 0.f);
03342 }
03343 }
03344 }
03345
03346 delete[] u;
03347 }
03348
03349
03350
03351 static void write_bin_histogram_map(
03352 const ComputeOccupancyMap *p,
03353 const char *filename
03354 ) {
03355 float xaxis[3], yaxis[3], zaxis[3];
03356 memset(xaxis, 0, 3*sizeof(float));
03357 memset(yaxis, 0, 3*sizeof(float));
03358 memset(zaxis, 0, 3*sizeof(float));
03359 xaxis[0] = p->nbx * p->bx;
03360 yaxis[1] = p->nby * p->by;
03361 zaxis[2] = p->nbz * p->bz;
03362
03363 int gridsize = p->nbx * p->nby * p->nbz;
03364 float *data = new float[gridsize];
03365
03366 int i;
03367 for (i=0; i<gridsize; i++) {
03368 data[i] = (float) p->bincnt[i];
03369 }
03370
03371 float ori[3];
03372 ori[0] = p->x0 - p->padx * p->bx;
03373 ori[1] = p->y0 - p->pady * p->by;
03374 ori[2] = p->z0 - p->padz * p->bz;
03375
03376 VolumetricData *volhist;
03377 volhist = new VolumetricData("atom binning histogram",
03378 ori, xaxis, yaxis, zaxis,
03379 p->nbx, p->nby, p->nbz, data);
03380
03381
03382 volmap_write_dx_file(volhist, filename);
03383
03384 delete volhist;
03385 }
03386
03387
03388
03389 void atom_bin_stats(const ComputeOccupancyMap *p) {
03390 int histogram[10] = { 0 };
03391 int i, j, k;
03392
03393 printf("*** origin = %g %g %g\n", p->x0, p->y0, p->z0);
03394 printf("*** lenx = %g leny = %g lenz = %g\n", p->lx, p->ly, p->lz);
03395 printf("*** bin lengths = %g %g %g\n", p->bx, p->by, p->bz);
03396 printf("*** inverse bin lengths = %g %g %g\n", p->bx_1, p->by_1, p->bz_1);
03397 printf("*** bin array: %d X %d X %d\n", p->nbx, p->nby, p->nbz);
03398 printf("*** bin padding: %d %d %d\n", p->padx, p->pady, p->padz);
03399 printf("*** cutoff = %g\n", p->cutoff);
03400 printf("*** extcutoff = %g\n", p->extcutoff);
03401 printf("*** size of tight neighborhood = %d\n", p->num_bin_offsets);
03402
03403 for (k = 0; k < p->nbz; k++) {
03404 for (j = 0; j < p->nby; j++) {
03405 for (i = 0; i < p->nbx; i++) {
03406 int index = (k*p->nby + j)*p->nbx + i;
03407 int count = p->bincnt[index];
03408 histogram[(count <= 9 ? count : 9)]++;
03409 }
03410 }
03411 }
03412
03413 printf("*** histogram of bin fill:\n");
03414 for (i = 0; i < (int) (sizeof(histogram) / sizeof(int)); i++) {
03415 if (i < 9) {
03416 printf("*** atom count %d number of bins %d\n",
03417 i, histogram[i]);
03418 }
03419 else {
03420 printf("*** atom count > 8 number of bins %d\n", histogram[i]);
03421 }
03422 }
03423 printf("*** number of extra atoms = %d\n", p->num_extras);
03424
03425 write_bin_histogram_map(p, "binning_histogram.dx");
03426 }
03427
03428
03429
03430
03431
03432 void compute_allatoms(
03433 float *map,
03434 int mx, int my, int mz,
03435 float lx, float ly, float lz,
03436 const float origin[3],
03437 const float axes[9],
03438 const float alignmat[16],
03439 int num_coords,
03440 const float *coords,
03441 const int *vdw_type,
03442 const float *vdw_params,
03443 float cutoff,
03444 const float *probe_vdw_params,
03445 int num_probe_atoms,
03446 int num_conformers,
03447 const float *conformers,
03448 float excl_energy
03449 ) {
03450 const float theTrivialConformer[] = { 0.f, 0.f, 0.f };
03451
03452 if (0 == num_conformers) {
03453 num_conformers = 1;
03454 conformers = theTrivialConformer;
03455 }
03456
03457 float hx = lx / mx;
03458 float hy = ly / my;
03459 float hz = lz / mz;
03460
03461 int i, j, k, n, m, ma;
03462
03463 float cutoff2 = cutoff * cutoff;
03464 float minocc = expf(-excl_energy);
03465
03466 float *u = new float[num_conformers];
03467
03468 #if 1
03469 printf("*** All atoms calculation (quadratic complexity)\n");
03470 printf("*** number of map points = %d\n", mx*my*mz);
03471 printf("*** number of atoms = %d\n", num_coords);
03472 printf("*** number of conformers = %d\n", num_conformers);
03473 printf("*** number of probe atoms = %d\n", num_probe_atoms);
03474 #endif
03475
03476 for (k = 0; k < mz; k++) {
03477 for (j = 0; j < my; j++) {
03478 for (i = 0; i < mx; i++) {
03479
03480 int mindex = (k*my + j)*mx + i;
03481
03482 float px = i*hx + origin[0];
03483 float py = j*hy + origin[1];
03484 float pz = k*hz + origin[2];
03485
03486 memset(u, 0, num_conformers * sizeof(float));
03487
03488 for (n = 0; n < num_coords; n++) {
03489
03490 for (m = 0; m < num_conformers; m++) {
03491 float v = 0.f;
03492 for (ma = 0; ma < num_probe_atoms; ma++) {
03493 int index = m*num_probe_atoms + ma;
03494 float dx = conformers[3*index ] + px - coords[3*n ];
03495 float dy = conformers[3*index + 1] + py - coords[3*n + 1];
03496 float dz = conformers[3*index + 2] + pz - coords[3*n + 2];
03497 float r2 = dx*dx + dy*dy + dz*dz;
03498 if (r2 >= cutoff2) continue;
03499 int pindex = 2 * vdw_type[n];
03500 float epsilon = vdw_params[pindex] * probe_vdw_params[2*ma];
03501 float rmin = vdw_params[pindex + 1] + probe_vdw_params[2*ma + 1];
03502 float rm6 = rmin*rmin / r2;
03503 rm6 = rm6 * rm6 * rm6;
03504 v += epsilon * rm6 * (rm6 - 2.f);
03505 }
03506
03507 u[m] += v;
03508
03509 }
03510
03511 }
03512
03513 float z = 0.f;
03514 for (m = 0; m < num_conformers; m++) {
03515 z += expf(-u[m]);
03516 }
03517
03518 map[mindex] = z / num_conformers;
03519 if (map[mindex] < minocc) map[mindex] = 0.f;
03520 }
03521 }
03522 }
03523
03524 delete[] u;
03525 }
03526