00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <math.h>
00024 #include "Measure.h"
00025 #include "AtomSel.h"
00026 #include "Matrix4.h"
00027 #include "utilities.h"
00028 #include "fitrms.h"
00029 #include "ResizeArray.h"
00030 #include "SpatialSearch.h"
00031 #include "MoleculeList.h"
00032 #include "Inform.h"
00033 #include "Timestep.h"
00034 #include "VMDApp.h"
00035 #include "WKFThreads.h"
00036 #include "WKFUtils.h"
00037
00038
00039 static const char *measure_error_messages[] = {
00040 "no atom selection",
00041 "no atoms in selection",
00042 "incorrect number of weights for selection",
00043 "internal error: NULL pointer given",
00044 "bad weight sum, would cause divide by zero",
00045 "molecule was deleted(?)",
00046 "cannot understand weight parameter",
00047 "non-number given as parameter",
00048 "two selections don't have the same number of atoms",
00049 "internal error: out of range",
00050 "no coordinates in selection",
00051 "couldn't compute eigenvalue/vectors",
00052 "unknown Tcl problem",
00053 "no atom radii",
00054 "order parameter contains out-of-range atom index",
00055 "order parameter not supported in old RMS fit mode",
00056 "specified frames are out of range",
00057 "both selections must reference the same molecule",
00058 "one atom appears twice in list",
00059 "molecule contains no frames",
00060 "invalid atom id",
00061 "cutoff must be smaller than cell dimension",
00062 "Zero volmap gridsize"
00063 };
00064
00065 const char *measure_error(int errnum) {
00066 if (errnum >= 0 || errnum < -23)
00067 return "bad error number";
00068 return measure_error_messages[-errnum - 1];
00069 }
00070
00071 int measure_move(const AtomSel *sel, float *framepos, const Matrix4 &mat) {
00072 if (!sel) return MEASURE_ERR_NOSEL;
00073 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
00074
00075
00076 int i;
00077 float *pos = framepos;
00078 if (mat.mat[3]==0 && mat.mat[7]==0 && mat.mat[11]==0 && mat.mat[15]==1) {
00079
00080
00081 const float dx = mat.mat[12];
00082 const float dy = mat.mat[13];
00083 const float dz = mat.mat[14];
00084 const float *m = mat.mat;
00085 if (sel->selected == sel->num_atoms) {
00086 for (i=0; i<sel->num_atoms; i++) {
00087 float x = pos[0]*m[0] + pos[1]*m[4] + pos[2]*m[8] + dx;
00088 float y = pos[0]*m[1] + pos[1]*m[5] + pos[2]*m[9] + dy;
00089 float z = pos[0]*m[2] + pos[1]*m[6] + pos[2]*m[10] + dz;
00090 pos[0] = x;
00091 pos[1] = y;
00092 pos[2] = z;
00093 pos += 3;
00094 }
00095 } else {
00096 pos += sel->firstsel*3;
00097 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00098 if (sel->on[i]) {
00099 float x = pos[0]*m[0] + pos[1]*m[4] + pos[2]*m[8] + dx;
00100 float y = pos[0]*m[1] + pos[1]*m[5] + pos[2]*m[9] + dy;
00101 float z = pos[0]*m[2] + pos[1]*m[6] + pos[2]*m[10] + dz;
00102 pos[0] = x;
00103 pos[1] = y;
00104 pos[2] = z;
00105 }
00106 pos += 3;
00107 }
00108 }
00109 } else {
00110 pos += sel->firstsel*3;
00111 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00112 if (sel->on[i]) {
00113 mat.multpoint3d(pos, pos);
00114 }
00115 pos += 3;
00116 }
00117 }
00118 return MEASURE_NOERR;
00119 }
00120
00121
00122
00123 int measure_sumweights(const AtomSel *sel, int numweights,
00124 const float *weights, float *weightsum) {
00125 if (!sel) return MEASURE_ERR_NOSEL;
00126 if (!weights) return MEASURE_ERR_NOWEIGHT;
00127 if (!weightsum) return MEASURE_ERR_GENERAL;
00128
00129 double sum = 0;
00130
00131 if (numweights == sel->num_atoms) {
00132 int i;
00133 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00134 if (sel->on[i]) {
00135 sum += weights[i];
00136 }
00137 }
00138 } else if (numweights == sel->selected) {
00139 int i, j;
00140 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00141 if (sel->on[i]) {
00142 sum += weights[j];
00143 j++;
00144 }
00145 }
00146 } else {
00147 return MEASURE_ERR_BADWEIGHTPARM;
00148 }
00149
00150 *weightsum = (float) sum;
00151 return MEASURE_NOERR;
00152 }
00153
00154
00155
00156
00157 int measure_center(const AtomSel *sel, const float *framepos,
00158 const float *weight, float *com) {
00159 if (!sel) return MEASURE_ERR_NOSEL;
00160 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
00161 if (!weight) return MEASURE_ERR_NOWEIGHT;
00162 if (!com) return MEASURE_ERR_NOCOM;
00163
00164 int i, j;
00165 float x, y, z, w;
00166 j=0;
00167 w=x=y=z=0;
00168 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00169 if (sel->on[i]) {
00170 float tw = weight[j];
00171 w += tw;
00172 x += tw * framepos[3*i ];
00173 y += tw * framepos[3*i+1];
00174 z += tw * framepos[3*i+2];
00175 j++;
00176 }
00177 }
00178
00179 if (w == 0) {
00180 return MEASURE_ERR_BADWEIGHTSUM;
00181 }
00182
00183 com[0] = x / w;
00184 com[1] = y / w;
00185 com[2] = z / w;
00186
00187 return MEASURE_NOERR;
00188 }
00189
00190
00191
00192 int measure_minmax(int num, const int *on, const float *framepos,
00193 const float *radii, float *min_coord, float *max_coord) {
00194 int i;
00195 float minx, miny, minz;
00196 float maxx, maxy, maxz;
00197
00198 if (!on) return MEASURE_ERR_NOSEL;
00199 if (num == 0) return MEASURE_ERR_NOATOMS;
00200 if (!min_coord || !max_coord) return MEASURE_ERR_NOMINMAXCOORDS;
00201
00202 vec_zero(min_coord);
00203 vec_zero(max_coord);
00204
00205
00206 int firstsel = 0;
00207 int lastsel = -1;
00208 if (find_first_selection_aligned(num, on, &firstsel))
00209 return MEASURE_NOERR;
00210
00211 if (find_last_selection_aligned(num, on, &lastsel))
00212 return MEASURE_NOERR;
00213
00214
00215 i=firstsel;
00216 if (radii == NULL) {
00217
00218 minx = maxx = framepos[i*3 ];
00219 miny = maxy = framepos[i*3+1];
00220 minz = maxz = framepos[i*3+2];
00221 } else {
00222
00223 minx = framepos[i*3 ] - radii[i];
00224 maxx = framepos[i*3 ] + radii[i];
00225 miny = framepos[i*3+1] - radii[i];
00226 maxy = framepos[i*3+1] + radii[i];
00227 minz = framepos[i*3+2] - radii[i];
00228 maxz = framepos[i*3+2] + radii[i];
00229 }
00230
00231
00232 if (radii == NULL) {
00233
00234 #if 0
00235 minmax_selected_3fv_aligned(framepos, on, atomSel->num_atoms,
00236 firstsel, lastsel, fmin, fmax);
00237 #else
00238 for (i++; i<=lastsel; i++) {
00239 if (on[i]) {
00240 int ind = i * 3;
00241 float tmpx = framepos[ind ];
00242 if (tmpx < minx) minx = tmpx;
00243 if (tmpx > maxx) maxx = tmpx;
00244
00245 float tmpy = framepos[ind+1];
00246 if (tmpy < miny) miny = tmpy;
00247 if (tmpy > maxy) maxy = tmpy;
00248
00249 float tmpz = framepos[ind+2];
00250 if (tmpz < minz) minz = tmpz;
00251 if (tmpz > maxz) maxz = tmpz;
00252 }
00253 }
00254 #endif
00255 } else {
00256
00257 for (i++; i<=lastsel; i++) {
00258 if (on[i]) {
00259 int ind = i * 3;
00260 float mintmpx = framepos[ind ] - radii[i];
00261 float maxtmpx = framepos[ind ] + radii[i];
00262 if (mintmpx < minx) minx = mintmpx;
00263 if (maxtmpx > maxx) maxx = maxtmpx;
00264
00265 float mintmpy = framepos[ind+1] - radii[i];
00266 float maxtmpy = framepos[ind+1] + radii[i];
00267 if (mintmpy < miny) miny = mintmpy;
00268 if (maxtmpy > maxy) maxy = maxtmpy;
00269
00270 float mintmpz = framepos[ind+2] - radii[i];
00271 float maxtmpz = framepos[ind+2] + radii[i];
00272 if (mintmpz < minz) minz = mintmpz;
00273 if (maxtmpz > maxz) maxz = maxtmpz;
00274 }
00275 }
00276 }
00277
00278
00279 min_coord[0]=minx;
00280 min_coord[1]=miny;
00281 min_coord[2]=minz;
00282 max_coord[0]=maxx;
00283 max_coord[1]=maxy;
00284 max_coord[2]=maxz;
00285
00286 return MEASURE_NOERR;
00287 }
00288
00289
00290
00291 extern int measure_avpos(const AtomSel *sel, MoleculeList *mlist,
00292 int start, int end, int step, float *avpos) {
00293 if (!sel) return MEASURE_ERR_NOSEL;
00294 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00295
00296 Molecule *mymol = mlist->mol_from_id(sel->molid());
00297 int maxframes = mymol->numframes();
00298
00299
00300 if (end == -1)
00301 end = maxframes-1;
00302
00303 if (maxframes == 0 || start < 0 || start > end ||
00304 end >= maxframes || step <= 0)
00305 return MEASURE_ERR_BADFRAMERANGE;
00306
00307 int i;
00308 for (i=0; i<(3*sel->selected); i++)
00309 avpos[i] = 0.0f;
00310
00311 int frame, avcount, j;
00312 for (avcount=0,frame=start; frame<=end; avcount++,frame+=step) {
00313 const float *framepos = (mymol->get_frame(frame))->pos;
00314 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00315 if (sel->on[i]) {
00316 avpos[j*3 ] += framepos[i*3 ];
00317 avpos[j*3 + 1] += framepos[i*3 + 1];
00318 avpos[j*3 + 2] += framepos[i*3 + 2];
00319 j++;
00320 }
00321 }
00322 }
00323
00324 float avinv = 1.0f / (float) avcount;
00325 for (j=0; j<(3*sel->selected); j++) {
00326 avpos[j] *= avinv;
00327 }
00328
00329 return MEASURE_NOERR;
00330 }
00331
00332
00333
00334 extern int measure_dipole(const AtomSel *sel, MoleculeList *mlist,
00335 float *dipole, int unitsdebye, int usecenter) {
00336 if (!sel) return MEASURE_ERR_NOSEL;
00337 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00338
00339 Molecule *mymol = mlist->mol_from_id(sel->molid());
00340 double rvec[3] = {0, 0, 0};
00341 double qrvec[3] = {0, 0, 0};
00342 double mrvec[3] = {0, 0, 0};
00343 double totalq = 0.0;
00344 double totalm = 0.0;
00345 int i;
00346
00347
00348 const float *framepos = sel->coordinates(mlist);
00349
00350
00351 const float *q = mymol->charge();
00352 const float *m = mymol->mass();
00353
00354 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00355 if (sel->on[i]) {
00356 int ind = i * 3;
00357 rvec[0] += framepos[ind ];
00358 rvec[1] += framepos[ind + 1];
00359 rvec[2] += framepos[ind + 2];
00360
00361 qrvec[0] += framepos[ind ] * q[i];
00362 qrvec[1] += framepos[ind + 1] * q[i];
00363 qrvec[2] += framepos[ind + 2] * q[i];
00364
00365 mrvec[0] += framepos[ind ] * m[i];
00366 mrvec[1] += framepos[ind + 1] * m[i];
00367 mrvec[2] += framepos[ind + 2] * m[i];
00368
00369 totalq += q[i];
00370 totalm += m[i];
00371 }
00372 }
00373
00374
00375 if (totalm < 0.0001)
00376 usecenter=1;
00377
00378 switch (usecenter) {
00379 case 1:
00380 {
00381 double rscale = totalq / sel->selected;
00382 dipole[0] = (float) (qrvec[0] - (rvec[0] * rscale));
00383 dipole[1] = (float) (qrvec[1] - (rvec[1] * rscale));
00384 dipole[2] = (float) (qrvec[2] - (rvec[2] * rscale));
00385 break;
00386 }
00387
00388 case -1:
00389 {
00390 double mscale = totalq / totalm;
00391 dipole[0] = (float) (qrvec[0] - (mrvec[0] * mscale));
00392 dipole[1] = (float) (qrvec[1] - (mrvec[1] * mscale));
00393 dipole[2] = (float) (qrvec[2] - (mrvec[2] * mscale));
00394 break;
00395 }
00396
00397 case 0:
00398 default:
00399 {
00400 dipole[0] = (float) qrvec[0];
00401 dipole[1] = (float) qrvec[1];
00402 dipole[2] = (float) qrvec[2];
00403 break;
00404 }
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 if (unitsdebye) {
00417
00418
00419
00420 dipole[0] *= 4.80320425132f;
00421 dipole[1] *= 4.80320425132f;
00422 dipole[2] *= 4.80320425132f;
00423 }
00424
00425 return MEASURE_NOERR;
00426 }
00427
00428
00429
00430 extern int measure_rmsf(const AtomSel *sel, MoleculeList *mlist,
00431 int start, int end, int step, float *rmsf) {
00432 if (!sel) return MEASURE_ERR_NOSEL;
00433 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00434
00435 Molecule *mymol = mlist->mol_from_id(sel->molid());
00436 int maxframes = mymol->numframes();
00437
00438
00439 if (end == -1)
00440 end = maxframes-1;
00441
00442 if (maxframes == 0 || start < 0 || start > end ||
00443 end >= maxframes || step <= 0)
00444 return MEASURE_ERR_BADFRAMERANGE;
00445
00446 int i;
00447 for (i=0; i<sel->selected; i++)
00448 rmsf[i] = 0.0f;
00449
00450 int rc;
00451 float *avpos = new float[3*sel->selected];
00452 rc = measure_avpos(sel, mlist, start, end, step, avpos);
00453
00454 if (rc != MEASURE_NOERR) {
00455 delete [] avpos;
00456 return rc;
00457 }
00458
00459
00460 int frame, avcount, j;
00461 for (avcount=0,frame=start; frame<=end; avcount++,frame+=step) {
00462 const float *framepos = (mymol->get_frame(frame))->pos;
00463 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00464 if (sel->on[i]) {
00465 rmsf[j] += distance2(&avpos[3*j], &framepos[3*i]);
00466 j++;
00467 }
00468 }
00469 }
00470
00471 float avinv = 1.0f / (float) avcount;
00472 for (j=0; j<sel->selected; j++) {
00473 rmsf[j] = sqrtf(rmsf[j] * avinv);
00474 }
00475
00476 delete [] avpos;
00477 return MEASURE_NOERR;
00478 }
00479
00480
00482
00483
00484
00485 int measure_rgyr(const AtomSel *sel, MoleculeList *mlist, const float *weight,
00486 float *rgyr) {
00487 if (!rgyr) return MEASURE_ERR_NORGYR;
00488 if (!sel) return MEASURE_ERR_NOSEL;
00489 if (!mlist) return MEASURE_ERR_GENERAL;
00490
00491 const float *framepos = sel->coordinates(mlist);
00492
00493
00494 float com[3];
00495 int ret_val = measure_center(sel, framepos, weight, com);
00496 if (ret_val < 0)
00497 return ret_val;
00498
00499
00500 int i, j;
00501 float total_w, sum;
00502
00503 total_w=sum=0;
00504 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00505 if (sel->on[i]) {
00506 float w = weight[j];
00507 total_w += w;
00508 sum += w * distance2(framepos + 3*i, com);
00509 j++;
00510 }
00511 }
00512
00513 if (total_w == 0) {
00514 return MEASURE_ERR_BADWEIGHTSUM;
00515 }
00516
00517
00518 *rgyr = sqrtf(sum/total_w);
00519
00520 return MEASURE_NOERR;
00521 }
00522
00523
00525
00526
00527
00528
00529
00530
00531
00532 int measure_rmsd(const AtomSel *sel1, const AtomSel *sel2,
00533 int num, const float *framepos1, const float *framepos2,
00534 float *weight, float *rmsd) {
00535 if (!sel1 || !sel2) return MEASURE_ERR_NOSEL;
00536 if (sel1->selected < 1 || sel2->selected < 1) return MEASURE_ERR_NOSEL;
00537 if (!weight || !rmsd) return MEASURE_ERR_NOWEIGHT;
00538
00539
00540 if (sel1->selected != sel2->selected) return MEASURE_ERR_MISMATCHEDCNT;
00541
00542
00543
00544
00545 int sel_flg;
00546 if (num == sel1->num_atoms) {
00547 sel_flg = 1;
00548 } else {
00549 sel_flg = 0;
00550 }
00551
00552
00553 float tmp_w;
00554 int w_index = 0;
00555 int sel1ind = sel1->firstsel;
00556 int sel2ind = sel2->firstsel;
00557 float wsum = 0;
00558 float rmsdsum = 0;
00559
00560 *rmsd = 10000000;
00561
00562
00563 int count = sel1->selected;
00564 while (count-- > 0) {
00565
00566
00567 while (!sel1->on[sel1ind])
00568 sel1ind++;
00569 while (!sel2->on[sel2ind])
00570 sel2ind++;
00571
00572
00573 if (sel_flg == 0) {
00574 tmp_w = weight[w_index++];
00575 } else {
00576 tmp_w = weight[sel1ind];
00577 }
00578
00579
00580 rmsdsum += tmp_w * distance2(framepos1 + 3*sel1ind, framepos2 + 3*sel2ind);
00581 wsum += tmp_w;
00582
00583
00584 sel1ind++;
00585 sel2ind++;
00586 }
00587
00588
00589 if (wsum == 0) {
00590 return MEASURE_ERR_BADWEIGHTSUM;
00591 }
00592
00593
00594 *rmsd = sqrtf(rmsdsum / wsum);
00595
00596 return MEASURE_NOERR;
00597 }
00598
00599
00600
00601 #define ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\
00602 a[k][l]=h+s*(g-h*tau);
00603
00604 static int jacobi(float a[4][4], float d[3], float v[3][3])
00605 {
00606 int n=3;
00607 int j,iq,ip,i;
00608 float tresh,theta,tau,t,sm,s,h,g,c,*b,*z;
00609
00610 b=new float[n];
00611 z=new float[n];
00612 for (ip=0;ip<n;ip++) {
00613 for (iq=0;iq<n;iq++) v[ip][iq]=0.0;
00614 v[ip][ip]=1.0;
00615 }
00616 for (ip=0;ip<n;ip++) {
00617 b[ip]=d[ip]=a[ip][ip];
00618 z[ip]=0.0;
00619 }
00620 for (i=1;i<=50;i++) {
00621 sm=0.0;
00622 for (ip=0;ip<n-1;ip++) {
00623 for (iq=ip+1;iq<n;iq++)
00624 sm += (float) fabs(a[ip][iq]);
00625 }
00626 if (sm == 0.0) {
00627 delete [] z;
00628 delete [] b;
00629 return 0;
00630 }
00631 if (i < 4)
00632 tresh=0.2f*sm/(n*n);
00633 else
00634 tresh=0.0f;
00635 for (ip=0;ip<n-1;ip++) {
00636 for (iq=ip+1;iq<n;iq++) {
00637 g=100.0f * fabsf(a[ip][iq]);
00638 if (i > 4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip])
00639 && (float)(fabs(d[iq])+g) == (float)fabs(d[iq]))
00640 a[ip][iq]=0.0;
00641 else if (fabs(a[ip][iq]) > tresh) {
00642 h=d[iq]-d[ip];
00643 if ((float)(fabs(h)+g) == (float)fabs(h))
00644 t=(a[ip][iq])/h;
00645 else {
00646 theta=0.5f*h/(a[ip][iq]);
00647 t=1.0f/(fabsf(theta)+sqrtf(1.0f+theta*theta));
00648 if (theta < 0.0f) t = -t;
00649 }
00650 c=1.0f/sqrtf(1+t*t);
00651 s=t*c;
00652 tau=s/(1.0f+c);
00653 h=t*a[ip][iq];
00654 z[ip] -= h;
00655 z[iq] += h;
00656 d[ip] -= h;
00657 d[iq] += h;
00658 a[ip][iq]=0.0;
00659 for (j=0;j<=ip-1;j++) {
00660 ROTATE(a,j,ip,j,iq)
00661 }
00662 for (j=ip+1;j<=iq-1;j++) {
00663 ROTATE(a,ip,j,j,iq)
00664 }
00665 for (j=iq+1;j<n;j++) {
00666 ROTATE(a,ip,j,iq,j)
00667 }
00668 for (j=0;j<n;j++) {
00669 ROTATE(v,j,ip,j,iq)
00670 }
00671 }
00672 }
00673 }
00674 for (ip=0;ip<n;ip++) {
00675 b[ip] += z[ip];
00676 d[ip]=b[ip];
00677 z[ip]=0.0;
00678 }
00679 }
00680 delete [] b;
00681 delete [] z;
00682 return 1;
00683 }
00684 #undef ROTATE
00685
00686 static int transvecinv(const double *v, Matrix4 &res) {
00687 double x, y, z;
00688 x=v[0];
00689 y=v[1];
00690 z=v[2];
00691 if (x == 0.0 && y == 0.0) {
00692 if (z == 0.0) {
00693 return -1;
00694 }
00695 if (z > 0)
00696 res.rot(90, 'y');
00697 else
00698 res.rot(-90, 'y');
00699 return 0;
00700 }
00701 double theta = atan2(y,x);
00702 double length = sqrt(x*x + y*y);
00703 double phi = atan2(z,length);
00704 res.rot((float) RADTODEG(phi), 'y');
00705 res.rot((float) RADTODEG(-theta), 'z');
00706 return 0;
00707 }
00708
00709 static int transvec(const double *v, Matrix4 &res) {
00710 double x, y, z;
00711 x=v[0];
00712 y=v[1];
00713 z=v[2];
00714 if (x == 0.0 && y == 0.0) {
00715 if (z == 0.0) {
00716 return -1;
00717 }
00718 if (z > 0)
00719 res.rot(-90, 'y');
00720 else
00721 res.rot(90, 'y');
00722 return 0;
00723 }
00724 double theta = atan2(y,x);
00725 double length = sqrt(x*x + y*y);
00726 double phi = atan2(z,length);
00727 res.rot((float) RADTODEG(theta), 'z');
00728 res.rot((float) RADTODEG(-phi), 'y');
00729 return 0;
00730 }
00731
00732 static Matrix4 myfit2(const float *x, const float *y,
00733 const float *comx, const float *comy) {
00734
00735 Matrix4 res;
00736 double dx[3], dy[3];
00737 dx[0] = x[0] - comx[0];
00738 dx[1] = x[1] - comx[1];
00739 dx[2] = x[2] - comx[2];
00740 dy[0] = y[0] - comy[0];
00741 dy[1] = y[1] - comy[1];
00742 dy[2] = y[2] - comy[2];
00743
00744 res.translate(comy[0], comy[1], comy[2]);
00745 transvec(dy, res);
00746 transvecinv(dx, res);
00747 res.translate(-comx[0], -comx[1], -comx[2]);
00748 return res;
00749 }
00750
00751 static Matrix4 myfit3(const float *x1, const float *x2,
00752 const float *y1, const float *y2,
00753 const float *comx, const float *comy) {
00754
00755 Matrix4 mx, my, rx1, ry1;
00756 double dx1[3], dy1[3], angle;
00757 float dx2[3], dy2[3], x2t[3], y2t[3];
00758
00759 for (int i=0; i<3; i++) {
00760 dx1[i] = x1[i] - comx[i];
00761 dx2[i] = x2[i] - comx[i];
00762 dy1[i] = y1[i] - comy[i];
00763 dy2[i] = y2[i] - comy[i];
00764 }
00765
00766
00767
00768
00769
00770
00771
00772 transvecinv(dx1, rx1);
00773 rx1.multpoint3d(dx2, x2t);
00774 angle = atan2(x2t[2], x2t[1]);
00775 mx.rot((float) RADTODEG(angle), 'x');
00776 mx.multmatrix(rx1);
00777 mx.translate(-comx[0], -comx[1], -comx[2]);
00778
00779 transvecinv(dy1, ry1);
00780 ry1.multpoint3d(dy2, y2t);
00781 angle = atan2(y2t[2], y2t[1]);
00782 my.rot((float) RADTODEG(angle), 'x');
00783 my.multmatrix(ry1);
00784 my.translate(-comy[0], -comy[1], -comy[2]);
00785 my.inverse();
00786 my.multmatrix(mx);
00787 return my;
00788 }
00789
00790
00791
00792
00793
00794 int measure_fit(const AtomSel *sel1, const AtomSel *sel2, const float *x,
00795 const float *y, const float *weight,
00796 const int *order, Matrix4 *mat) {
00797 float comx[3];
00798 float comy[3];
00799 int num = sel1->selected;
00800 int ret_val;
00801 ret_val = measure_center(sel1, x, weight, comx);
00802 if (ret_val < 0) {
00803 return ret_val;
00804 }
00805 ret_val = measure_center(sel2, y, weight, comy);
00806 if (ret_val < 0) {
00807 return ret_val;
00808 }
00809
00810
00811
00812
00813 switch (sel1->selected) {
00814 case 1: {
00815 Matrix4 tmp;
00816 tmp.translate(-comx[0], -comx[1], -comx[2]);
00817 tmp.translate(comy[0], comy[1], comy[2]);
00818 memcpy(mat->mat, tmp.mat, 16*sizeof(float));
00819 return MEASURE_NOERR;
00820 }
00821 case 3:
00822 case 2: {
00823
00824 int pts[6], count = 0;
00825 int n;
00826 for (n=sel1->firstsel; n<=sel1->lastsel; n++) {
00827 if (sel1->on[n]) {
00828 pts[count++] = n;
00829 if (sel1->selected == 2) {
00830 count++;
00831 break;
00832 }
00833 if (count == 2) break;
00834 }
00835 }
00836 for (n=sel2->firstsel; n<=sel2->lastsel; n++) {
00837 if (sel2->on[n]) {
00838 pts[count++] = n;
00839 if (sel1->selected == 2) {
00840 count++;
00841 break;
00842 }
00843 if (count == 4) break;
00844 }
00845 }
00846 if (count != 4) {
00847 return MEASURE_ERR_MISMATCHEDCNT;
00848 }
00849
00850
00851 if (order != NULL) {
00852 int i;
00853 int tmp[6];
00854 memcpy(tmp, pts, sizeof(pts));
00855 for (i=0; i<num; i++) {
00856 pts[i + num] = tmp[num + order[i]];
00857 }
00858 }
00859
00860 if (sel1->selected == 2) {
00861 *mat = myfit2(x+3*pts[0],y+3*pts[2], comx, comy);
00862 ret_val = 0;
00863 } else {
00864 *mat = myfit3(x+3*pts[0],x+3*pts[1],y+3*pts[2],y+3*pts[3],comx,comy);
00865 ret_val = 0;
00866 }
00867 if (ret_val != 0) {
00868 return MEASURE_ERR_GENERAL;
00869 }
00870
00871 return 0;
00872 }
00873 default:
00874 break;
00875 }
00876
00877
00878
00879
00880 char *opt = getenv("VMDRMSFITMETHOD");
00881 if (!opt || strcmp(opt, "oldvmd")) {
00882 int i, k;
00883 float *v1, *v2;
00884 v1 = new float[3*num];
00885 v2 = new float[3*num];
00886 for (k=0, i=sel1->firstsel; i<=sel1->lastsel; i++) {
00887 if (sel1->on[i]) {
00888 int ind = 3 * i;
00889 v1[k++] = x[ind ];
00890 v1[k++] = x[ind + 1];
00891 v1[k++] = x[ind + 2];
00892 }
00893 }
00894 for (k=0, i=sel2->firstsel; i<=sel2->lastsel; i++) {
00895 if (sel2->on[i]) {
00896 int ind = 3 * i;
00897 v2[k++] = y[ind ];
00898 v2[k++] = y[ind + 1];
00899 v2[k++] = y[ind + 2];
00900 }
00901 }
00902
00903
00904 if (order != NULL) {
00905 int i;
00906 float *tmp = new float[3*num];
00907 memcpy(tmp, v2, 3*num*sizeof(float));
00908 for (i=0; i<num; i++) {
00909 int ind = 3 * i;
00910 int idx = 3 * order[i];
00911 v2[ind ] = tmp[idx ];
00912 v2[ind + 1] = tmp[idx + 1];
00913 v2[ind + 2] = tmp[idx + 2];
00914 }
00915 delete[] tmp;
00916 }
00917
00918 float tmp[16];
00919
00920
00921
00922
00923 MatrixFitRMS(num, v1, v2, weight, tmp);
00924
00925 delete [] v1;
00926 delete [] v2;
00927
00928
00929
00930 float pre[3], post[3];
00931 for (i=0; i<3; i++) {
00932 post[i] = tmp[4*i+3];
00933 tmp[4*i+3] = 0;
00934 }
00935 for (i=0; i<3; i++) {
00936 pre[i] = tmp[12+i];
00937 tmp[12+i] = 0;
00938 }
00939 Matrix4 result;
00940 result.translate(pre);
00941 result.multmatrix(Matrix4(tmp));
00942 result.translate(post);
00943 memcpy(mat->mat, result.mat, 16*sizeof(float));
00944 return 0;
00945 }
00946
00947
00948 if (order != NULL) {
00949 return MEASURE_ERR_NOTSUP;
00950 }
00951
00952
00953 Matrix4 R;
00954 int i,j;
00955 float scale = (float) num * num;
00956 for (i=0; i<3; i++) {
00957 for (j=0; j<3; j++) {
00958 float tmp = 0;
00959 int nx = 0, ny = 0, k = 0;
00960 while (nx < sel1->num_atoms && ny < sel2->num_atoms) {
00961 if (!sel1->on[nx]) {
00962 nx++;
00963 continue;
00964 }
00965 if (!sel2->on[ny]) {
00966 ny++;
00967 continue;
00968 }
00969
00970
00971
00972 tmp += weight[k] * (y[3*ny+i] - comy[i]) * (x[3*nx+j] - comx[j]) /
00973 scale;
00974 nx++;
00975 ny++;
00976 k++;
00977 }
00978 R.mat[4*i+j] = tmp;
00979 }
00980 }
00981
00982
00983 Matrix4 Rt;
00984 for (i=0; i<3; i++) {
00985 for (j=0; j<3; j++) {
00986 Rt.mat[4*i+j] = R.mat[4*j+i];
00987 }
00988 }
00989 Matrix4 RtR(R);
00990 RtR.multmatrix(Rt);
00991
00992
00993 float evalue[3];
00994 float evector[3][3];
00995 float tmpmat[4][4];
00996 for (i=0; i<4; i++)
00997 for (j=0; j<4; j++)
00998 tmpmat[i][j]=RtR.mat[4*i+j];
00999
01000 if(jacobi(tmpmat,evalue,evector) != 0) return MEASURE_ERR_NONZEROJACOBI;
01001
01002 float vectmp;
01003 vectmp=evector[0][1]; evector[0][1]=evector[1][0]; evector[1][0]=vectmp;
01004 vectmp=evector[0][2]; evector[0][2]=evector[2][0]; evector[2][0]=vectmp;
01005 vectmp=evector[2][1]; evector[2][1]=evector[1][2]; evector[1][2]=vectmp;
01006
01007
01008
01009
01010 float *a[3];
01011 a[0] = evector[0];
01012 a[1] = evector[1];
01013 a[2] = evector[2];
01014 #define SWAP(qq,ww) { \
01015 float v; float *v1; \
01016 v = evalue[qq]; evalue[qq] = evalue[ww]; evalue[ww] = v; \
01017 v1 = a[qq]; a[qq] = a[ww]; a[ww] = v1; \
01018 }
01019 if (evalue[0] < evalue[1]) {
01020 SWAP(0, 1);
01021 }
01022 if (evalue[0] < evalue[2]) {
01023 SWAP(0, 2);
01024 }
01025 if (evalue[1] < evalue[2]) {
01026 SWAP(1, 2);
01027 }
01028
01029
01030
01031 float b[3][3];
01032
01033 Rt.multpoint3d(a[0], b[0]);
01034 vec_normalize(b[0]);
01035
01036 Rt.multpoint3d(a[1], b[1]);
01037 vec_normalize(b[1]);
01038
01039 Rt.multpoint3d(a[2], b[2]);
01040 vec_normalize(b[2]);
01041
01042
01043 Matrix4 U;
01044 for (i=0; i<3; i++) {
01045 for (j=0; j<3; j++) {
01046 float *tmp = &(U.mat[4*j+i]);
01047 *tmp = 0;
01048 for (int k=0; k<3; k++) {
01049 *tmp += b[k][i] * a[k][j];
01050 }
01051 }
01052 }
01053
01054
01055
01056 float *um = U.mat;
01057 float det =
01058 um[0]*(um[4+1]*um[8+2] - um[4+2]*um[8+1]) -
01059 um[1]*(um[4+0]*um[8+2] - um[4+2]*um[8+0]) +
01060 um[2]*(um[4+0]*um[8+1] - um[4+1]*um[8+0]);
01061 if (det < 0) {
01062 for (int q=0; q<3; q++) um[8+q] = -um[8+q];
01063 }
01064
01065
01066 Matrix4 tx;
01067 tx.translate(-comx[0], -comx[1], -comx[2]);
01068 Matrix4 ty;
01069 ty.translate(comy[0], comy[1], comy[2]);
01070
01071 ty.multmatrix(U);
01072 ty.multmatrix(tx);
01073 memcpy(mat->mat, ty.mat, 16*sizeof(float));
01074 return MEASURE_NOERR;
01075 }
01076
01077
01078
01079
01080 #define NPTS 500
01081 extern int measure_sasa(const AtomSel *sel, const float *framepos,
01082 const float *radius, float srad, float *sasa,
01083 ResizeArray<float> *sasapts, const AtomSel *restrictsel,
01084 const int *nsamples) {
01085
01086
01087 if (!sel) return MEASURE_ERR_NOSEL;
01088 if (!sel->selected) {
01089 *sasa = 0;
01090 return MEASURE_NOERR;
01091 }
01092 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
01093 if (!radius) return MEASURE_ERR_NORADII;
01094 if (restrictsel && restrictsel->num_atoms != sel->num_atoms)
01095 return MEASURE_ERR_MISMATCHEDCNT;
01096
01097 int i;
01098 int npts = nsamples ? *nsamples : NPTS;
01099 float maxrad = -1;
01100
01101
01102
01103 for (i=0; i<sel->num_atoms; i++) {
01104 float rad = radius[i];
01105 if (maxrad < rad) maxrad = rad;
01106 }
01107
01108
01109
01110 ResizeArray<int> *pairlist = new ResizeArray<int>[sel->num_atoms];
01111 {
01112 GridSearchPair *pairs;
01113 pairs = vmd_gridsearch1(framepos, sel->num_atoms, sel->on,
01114 2.0f * (maxrad + srad), 0, sel->num_atoms * 1000);
01115
01116 GridSearchPair *p, *tmp;
01117 for (p = pairs; p != NULL; p = tmp) {
01118 int ind1=p->ind1;
01119 int ind2=p->ind2;
01120 pairlist[ind1].append(ind2);
01121 pairlist[ind2].append(ind1);
01122 tmp = p->next;
01123 free(p);
01124 }
01125 }
01126
01127 static const float RAND_MAX_INV = 1.0f/VMD_RAND_MAX;
01128
01129
01130
01131
01132 vmd_srandom(38572111);
01133
01134
01135 float *spherepts = new float[3*npts];
01136 for (i=0; i<npts; i++) {
01137 float u1 = (float) vmd_random();
01138 float u2 = (float) vmd_random();
01139 float z = 2.0f*u1*RAND_MAX_INV -1.0f;
01140 float phi = (float) (2.0f*VMD_PI*u2*RAND_MAX_INV);
01141 float R = sqrtf(1.0f-z*z);
01142 spherepts[3*i ] = R*cosf(phi);
01143 spherepts[3*i+1] = R*sinf(phi);
01144 spherepts[3*i+2] = z;
01145 }
01146
01147 const float prefac = (float) (4 * VMD_PI / npts);
01148 float totarea = 0.0f;
01149
01150 for (i=sel->firstsel; i<=sel->lastsel; i++) {
01151 if (sel->on[i]) {
01152
01153 if (restrictsel && !restrictsel->on[i]) continue;
01154 const float *loc = framepos+3*i;
01155 float rad = radius[i]+srad;
01156 float surfpos[3];
01157 int surfpts = npts;
01158 const ResizeArray<int> &nbrs = pairlist[i];
01159 for (int j=0; j<npts; j++) {
01160 surfpos[0] = loc[0] + rad*spherepts[3*j ];
01161 surfpos[1] = loc[1] + rad*spherepts[3*j+1];
01162 surfpos[2] = loc[2] + rad*spherepts[3*j+2];
01163 int on = 1;
01164 for (int k=0; k<nbrs.num(); k++) {
01165 int ind = nbrs[k];
01166 const float *nbrloc = framepos+3*ind;
01167 float radsq = radius[ind]+srad; radsq *= radsq;
01168 float dx = surfpos[0]-nbrloc[0];
01169 float dy = surfpos[1]-nbrloc[1];
01170 float dz = surfpos[2]-nbrloc[2];
01171 if (dx*dx + dy*dy + dz*dz <= radsq) {
01172 on = 0;
01173 break;
01174 }
01175 }
01176 if (on) {
01177 if (sasapts) {
01178 sasapts->append(surfpos[0]);
01179 sasapts->append(surfpos[1]);
01180 sasapts->append(surfpos[2]);
01181 }
01182 } else {
01183 surfpts--;
01184 }
01185 }
01186 float atomarea = prefac * rad * rad * surfpts;
01187 totarea += atomarea;
01188 }
01189 }
01190
01191 delete [] pairlist;
01192 delete [] spherepts;
01193 *sasa = totarea;
01194 return 0;
01195 }
01196
01197
01198
01199
01200
01201
01202
01203
01204 static float fix_pbc_n_sqr(float delta, const float boxby2) {
01205 while (delta >= boxby2) { delta -= 2.0f * boxby2; }
01206 while (delta < -boxby2) { delta += 2.0f * boxby2; }
01207 return delta * delta;
01208 }
01209
01210
01211
01212 static float min_dist_with_pbc(const float *a, const float *b,
01213 const float *boxby2) {
01214 float distsqr;
01215 distsqr = fix_pbc_n_sqr(a[0] - b[0], boxby2[0]);
01216 distsqr += fix_pbc_n_sqr(a[1] - b[1], boxby2[1]);
01217 distsqr += fix_pbc_n_sqr(a[2] - b[2], boxby2[2]);
01218 return sqrtf(distsqr);
01219 }
01220
01225 static inline double spherical_cap(const double &radius, const double &boxby2) {
01226 return (VMD_PI / 3.0 * (radius - boxby2) * (radius - boxby2)
01227 * ( 2.0 * radius + boxby2));
01228 }
01229
01230
01231 typedef struct {
01232 int threadid;
01233 int threadcount;
01234 int count_o_start;
01235 int count_o_end;
01236 const float *olist;
01237 int count_i;
01238 const float *ilist;
01239 int count_h;
01240 int *hlist;
01241 float delta;
01242 const float *boxby2;
01243 wkfmsgtimer *msgtp;
01244 int curframe;
01245 int maxframe;
01246 } gofrparms_t;
01247
01248
01249
01250
01251
01252
01253
01254
01255 extern "C" void * measure_gofr_orth(void *voidparms) {
01256
01257 gofrparms_t *parms = (gofrparms_t *) voidparms;
01258 const int count_o_start = parms->count_o_start;
01259 const int count_o_end = parms->count_o_end;
01260 const int count_i = parms->count_i;
01261 const int count_h = parms->count_h;
01262 const float *olist = parms->olist;
01263 const float *ilist = parms->ilist;
01264 const float *boxby2 = parms->boxby2;
01265 wkfmsgtimer *msgtp = parms->msgtp;
01266 const int curframe = parms->curframe;
01267 const int maxframe = parms->maxframe;
01268 int *hlist = parms->hlist;
01269
01270 int i, j, idx;
01271 float dist;
01272 const float deltascale = 1.0f / parms->delta;
01273 int msgcnt=0;
01274
01275
01276 for (i=count_o_start; i<count_o_end; ++i) {
01277
01278
01279
01280 if (msgtp && wkf_msg_timer_timeout(msgtp)) {
01281 char tmpbuf[1024];
01282 if (msgcnt==0)
01283 sprintf(tmpbuf, "timestep %d of %d", curframe, maxframe);
01284 else
01285 sprintf(tmpbuf, "timestep %d of %d: (%6.2f %% complete)", curframe, maxframe,
01286 (100.0f * i) / (float) (count_o_end - count_o_start + 1));
01287 msgInfo << "vmd_measure_gofr_orth: " << tmpbuf << sendmsg;
01288 msgcnt++;
01289
01290 }
01291
01292 for (j=0; j<count_i; ++j) {
01293
01294 dist = min_dist_with_pbc(&olist[i*3], &ilist[j*3], boxby2);
01295 idx = (int) (dist * deltascale);
01296 if ((idx >= 0) && (idx < count_h))
01297 ++hlist[idx];
01298 }
01299 }
01300
01301 return MEASURE_NOERR;
01302 }
01303
01304
01305
01306
01307
01308 int measure_gofr(AtomSel *sel1, AtomSel *sel2, MoleculeList *mlist,
01309 const int count_h, double *gofr, double *numint, double *histog,
01310 const float delta, int first, int last, int step, int *framecntr,
01311 int usepbc, int selupdate) {
01312 int i, j, frame;
01313 float a, b, c, alpha, beta, gamma;
01314 int isortho=0;
01315 int duplicates=0;
01316
01317
01318 a=b=c=9999999.0;
01319 alpha=beta=gamma=90.0;
01320
01321
01322 framecntr[0]=framecntr[1]=framecntr[2]=0;
01323
01324
01325
01326 if (!sel1 || !sel2 ) {
01327 return MEASURE_ERR_NOSEL;
01328 }
01329
01330
01331
01332 if (sel2->molid() != sel1->molid()) {
01333 return MEASURE_ERR_MISMATCHEDMOLS;
01334 }
01335
01336 Molecule *mymol = mlist->mol_from_id(sel1->molid());
01337 int maxframe = mymol->numframes() - 1;
01338 int nframes = 0;
01339
01340 if (last == -1)
01341 last = maxframe;
01342
01343 if ((last < first) || (last < 0) || (step <=0) || (first < -1)
01344 || (maxframe < 0) || (last > maxframe)) {
01345 msgErr << "measure gofr: bad frame range given."
01346 << " max. allowed frame#: " << maxframe << sendmsg;
01347 return MEASURE_ERR_BADFRAMERANGE;
01348 }
01349
01350
01351 if (usepbc) {
01352 for (isortho=1, nframes=0, frame=first; frame <=last; ++nframes, frame += step) {
01353 const Timestep *ts;
01354
01355 if (first == -1) {
01356
01357 ts = sel1->timestep(mlist);
01358 frame=last;
01359 } else {
01360 ts = mymol->get_frame(frame);
01361 }
01362
01363 a = ts->a_length;
01364 b = ts->b_length;
01365 c = ts->c_length;
01366 alpha = ts->alpha;
01367 beta = ts->beta;
01368 gamma = ts->gamma;
01369
01370
01371 if (fabsf(a*b*c) < 0.0001) {
01372 msgErr << "measure gofr: unit cell volume is zero." << sendmsg;
01373 return MEASURE_ERR_GENERAL;
01374 }
01375
01376
01377 if ((alpha != 90.0) || (beta != 90.0) || (gamma != 90.0)) {
01378 isortho=0;
01379 }
01380 }
01381 } else {
01382
01383 isortho=1;
01384 a=b=c=9999999.0;
01385 alpha=beta=gamma=90.0;
01386 }
01387
01388
01389 if (!isortho) {
01390 msgErr << "measure gofr: only orthorhombic cells are supported (for now)." << sendmsg;
01391 return MEASURE_ERR_GENERAL;
01392 }
01393
01394
01395 for (i=0; i<count_h; ++i) {
01396 gofr[i] = numint[i] = histog[i] = 0.0;
01397 }
01398
01399
01400
01401
01402 float *sel1coords = new float[3*sel1->num_atoms];
01403 float *sel2coords = new float[3*sel2->num_atoms];
01404
01405
01406 wkfmsgtimer *msgt = wkf_msg_timer_create(5);
01407
01408
01409 wkf_thread_t *threads;
01410 gofrparms_t *parms;
01411 #if defined(VMDTHREADS)
01412 int numprocs = wkf_thread_numprocessors();
01413 #else
01414 int numprocs = 1;
01415 #endif
01416
01417 threads = new wkf_thread_t[numprocs];
01418 memset(threads, 0, numprocs * sizeof(wkf_thread_t));
01419
01420
01421 parms = new gofrparms_t[numprocs];
01422 for (i=0; i<numprocs; ++i) {
01423 parms[i].threadid = i;
01424 parms[i].threadcount = numprocs;
01425 parms[i].delta = (float) delta;
01426 parms[i].msgtp = NULL;
01427 parms[i].count_h = count_h;
01428 parms[i].hlist = new int[count_h];
01429 }
01430
01431 msgInfo << "measure gofr: using multi-threaded implementation with "
01432 << numprocs << ((numprocs > 1) ? " CPUs" : " CPU") << sendmsg;
01433
01434 for (nframes=0,frame=first; frame <=last; ++nframes, frame += step) {
01435 const Timestep *ts1, *ts2;
01436
01437 if (frame == -1) {
01438
01439 ts1 = sel1->timestep(mlist);
01440 ts2 = sel2->timestep(mlist);
01441 frame=last;
01442 } else {
01443 sel1->which_frame = frame;
01444 sel2->which_frame = frame;
01445 ts1 = ts2 = mymol->get_frame(frame);
01446 }
01447
01448 if (usepbc) {
01449
01450 a = ts1->a_length;
01451 b = ts1->b_length;
01452 c = ts1->c_length;
01453 alpha = ts1->alpha;
01454 beta = ts1->beta;
01455 gamma = ts1->gamma;
01456 }
01457
01458
01459 float boxby2[3];
01460 boxby2[0] = 0.5f * a;
01461 boxby2[1] = 0.5f * b;
01462 boxby2[2] = 0.5f * c;
01463
01464
01465 if (selupdate) {
01466 if (sel1->change(NULL, mymol) != AtomSel::PARSE_SUCCESS)
01467 msgErr << "measure gofr: failed to evaluate atom selection update";
01468 if (sel2->change(NULL, mymol) != AtomSel::PARSE_SUCCESS)
01469 msgErr << "measure gofr: failed to evaluate atom selection update";
01470 }
01471
01472
01473
01474 if (sel2->molid() == sel1->molid()) {
01475 int i;
01476 for (i=0, duplicates=0; i<sel1->num_atoms; ++i) {
01477 if (sel1->on[i] && sel2->on[i])
01478 ++duplicates;
01479 }
01480 }
01481
01482
01483
01484 const float *framepos = ts1->pos;
01485 for (i=0, j=0; i<sel1->num_atoms; ++i) {
01486 if (sel1->on[i]) {
01487 int a = i*3;
01488 sel1coords[j ] = framepos[a ];
01489 sel1coords[j + 1] = framepos[a + 1];
01490 sel1coords[j + 2] = framepos[a + 2];
01491 j+=3;
01492 }
01493 }
01494 framepos = ts2->pos;
01495 for (i=0, j=0; i<sel2->num_atoms; ++i) {
01496 if (sel2->on[i]) {
01497 int a = i*3;
01498 sel2coords[j ] = framepos[a ];
01499 sel2coords[j + 1] = framepos[a + 1];
01500 sel2coords[j + 2] = framepos[a + 2];
01501 j+=3;
01502 }
01503 }
01504
01505
01506
01507 int maxframe = (int) ((last - first + 1) / ((float) step));
01508 for (i=0; i<numprocs; ++i) {
01509 memset(parms[i].hlist, 0, count_h * sizeof(int));
01510 parms[i].boxby2 = boxby2;
01511 parms[i].curframe = frame;
01512 parms[i].maxframe = maxframe;
01513 }
01514 parms[0].msgtp = msgt;
01515
01516 if (isortho && sel1->selected && sel2->selected) {
01517 int count_o = sel1->selected;
01518 int count_i = sel2->selected;
01519 const float *olist = sel1coords;
01520 const float *ilist = sel2coords;
01521
01522
01523 if (count_o < count_i) {
01524 count_o = sel2->selected;
01525 count_i = sel1->selected;
01526 olist = sel2coords;
01527 ilist = sel1coords;
01528 }
01529
01530
01531
01532
01533
01534 int thrdelta = (count_o + (numprocs-1)) / numprocs;
01535 int o_min = 0;
01536 int o_max = thrdelta;
01537 for (i=0; i<numprocs; ++i, o_min += thrdelta, o_max += thrdelta) {
01538 if (o_max > count_o) o_max = count_o;
01539 if (o_min >= count_o) o_max = - 1;
01540 parms[i].count_o_start = o_min;
01541 parms[i].count_o_end = o_max;
01542 parms[i].count_i = count_i;
01543 parms[i].olist = olist;
01544 parms[i].ilist = ilist;
01545 }
01546
01547
01548
01549 #if defined(VMDTHREADS)
01550 for (i=0; i<numprocs; ++i) {
01551 wkf_thread_create(&threads[i], measure_gofr_orth, &parms[i]);
01552 }
01553 for (i=0; i<numprocs; ++i) {
01554 wkf_thread_join(threads[i], NULL);
01555 }
01556 #else
01557 measure_gofr_orth((void *) &parms[0]);
01558 #endif
01559 ++framecntr[2];
01560 } else {
01561 ++framecntr[1];
01562 }
01563 ++framecntr[0];
01564
01565
01566
01567
01568 parms[0].hlist[0] -= duplicates;
01569
01570
01571
01572
01573 int h_max=count_h;
01574 float smallside=a;
01575 if (isortho && usepbc) {
01576 if(b < smallside) {
01577 smallside=b;
01578 }
01579 if(c < smallside) {
01580 smallside=c;
01581 }
01582 h_max=(int) (sqrtf(0.5f)*smallside/delta) +1;
01583 if (h_max > count_h) {
01584 h_max=count_h;
01585 }
01586 }
01587
01588 double all=0.0;
01589 double pair_dens = 0.0;
01590 if (sel1->selected && sel2->selected) {
01591 if (usepbc) {
01592 pair_dens = a * b * c / ((double)sel1->selected * (double)sel2->selected - (double)duplicates);
01593 } else {
01594 pair_dens = 30.0 * (double)sel1->selected /
01595 ((double)sel1->selected * (double)sel2->selected - (double)duplicates);
01596 }
01597 }
01598
01599
01600 for (i=0; i<h_max; ++i) {
01601
01602 double r_in = delta * (double)i;
01603 double r_out = delta * (double)(i+1);
01604 double slice_vol = 4.0 / 3.0 * VMD_PI
01605 * ((r_out * r_out * r_out) - (r_in * r_in * r_in));
01606
01607 if (isortho && usepbc) {
01608
01609 if (r_out > boxby2[0]) {
01610 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[0]);
01611 }
01612 if (r_out > boxby2[1]) {
01613 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[1]);
01614 }
01615 if (r_out > boxby2[2]) {
01616 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[2]);
01617 }
01618 if (r_in > boxby2[0]) {
01619 slice_vol += 2.0 * spherical_cap(r_in, boxby2[0]);
01620 }
01621 if (r_in > boxby2[1]) {
01622 slice_vol += 2.0 * spherical_cap(r_in, boxby2[1]);
01623 }
01624 if (r_in > boxby2[2]) {
01625 slice_vol += 2.0 * spherical_cap(r_in, boxby2[2]);
01626 }
01627 }
01628
01629 double normf = pair_dens / slice_vol;
01630 double histv = 0.0;
01631 for (j=0; j<numprocs; ++j) {
01632 histv += (double) parms[j].hlist[i];
01633 }
01634 gofr[i] += normf * histv;
01635 all += histv;
01636 if (sel1->selected) {
01637 numint[i] += all / (double)(sel1->selected);
01638 }
01639 histog[i] += histv;
01640 }
01641 }
01642 delete [] sel1coords;
01643 delete [] sel2coords;
01644
01645 double norm = 1.0 / (double) nframes;
01646 for (i=0; i<count_h; ++i) {
01647 gofr[i] *= norm;
01648 numint[i] *= norm;
01649 histog[i] *= norm;
01650 }
01651 wkf_msg_timer_destroy(msgt);
01652
01653
01654 for (i=0; i<numprocs; ++i) {
01655 delete [] parms[i].hlist;
01656 }
01657 delete [] threads;
01658 delete [] parms;
01659
01660 return MEASURE_NOERR;
01661 }
01662
01663
01664 int measure_geom(MoleculeList *mlist, int *molid, int *atmid, ResizeArray<float> *gValues,
01665 int frame, int first, int last, int defmolid, int geomtype) {
01666 int i, ret_val;
01667 for(i=0; i < geomtype; i++) {
01668
01669 if(i > 0 && molid[i-1]==molid[i] && atmid[i-1]==atmid[i]) {
01670 printf("measure_geom: %i/%i %i/%i\n", molid[i-1],atmid[i-1],molid[i],atmid[i]);
01671 return MEASURE_ERR_REPEATEDATOM;
01672 }
01673 }
01674
01675 float value;
01676 int max_ts, orig_ts;
01677
01678
01679 Molecule *mol = mlist->mol_from_id(defmolid);
01680 if( !mol )
01681 return MEASURE_ERR_NOMOLECULE;
01682
01683
01684 if((orig_ts = mol->frame()) < 0)
01685 return MEASURE_ERR_NOFRAMES;
01686
01687
01688 max_ts = mol->numframes()-1;
01689 if (frame<0) {
01690 if (first<0 && last<0) first = last = orig_ts;
01691 if (last<0 || last>max_ts) last = max_ts;
01692 if (first<0) first = 0;
01693 } else {
01694 if (frame>max_ts) frame = max_ts;
01695 first = last = frame;
01696 }
01697
01698
01699 for(i=first; i <= last; i++) {
01700 mol->override_current_frame(i);
01701 switch (geomtype) {
01702 case MEASURE_BOND:
01703 if ((ret_val=calculate_bond(mlist, molid, atmid, &value))<0)
01704 return ret_val;
01705 gValues->append(value);
01706 break;
01707 case MEASURE_ANGLE:
01708 if ((ret_val=calculate_angle(mlist, molid, atmid, &value))<0)
01709 return ret_val;
01710 gValues->append(value);
01711 break;
01712 case MEASURE_DIHED:
01713 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
01714 return ret_val;
01715 gValues->append(value);
01716 break;
01717 }
01718 }
01719
01720
01721 mol->override_current_frame(orig_ts);
01722
01723 return MEASURE_NOERR;
01724 }
01725
01726
01727
01728 int calculate_bond(MoleculeList *mlist, int *molid, int *atmid, float *value) {
01729
01730
01731 int ret_val;
01732 float pos1[3], pos2[3];
01733 if ((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
01734 return ret_val;
01735 if ((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
01736 return ret_val;
01737
01738 vec_sub(pos2, pos2, pos1);
01739 *value = norm(pos2);
01740
01741 return MEASURE_NOERR;
01742 }
01743
01744
01745 int calculate_angle(MoleculeList *mlist, int *molid, int *atmid, float *value) {
01746
01747
01748 int ret_val;
01749 float pos1[3], pos2[3], pos3[3], r1[3], r2[3];
01750 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
01751 return ret_val;
01752 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
01753 return ret_val;
01754 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[2]), atmid[2], pos3))<0)
01755 return ret_val;
01756
01757 vec_sub(r1, pos1, pos2);
01758 vec_sub(r2, pos3, pos2);
01759 *value = angle(r1, r2);
01760
01761 return MEASURE_NOERR;
01762 }
01763
01764
01765 int calculate_dihed(MoleculeList *mlist, int *molid, int *atmid, float *value) {
01766
01767
01768 int ret_val;
01769 float pos1[3], pos2[3], pos3[3], pos4[3];
01770 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
01771 return ret_val;
01772 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
01773 return ret_val;
01774 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[2]), atmid[2], pos3))<0)
01775 return ret_val;
01776 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[3]), atmid[3], pos4))<0)
01777 return ret_val;
01778
01779 *value = dihedral(pos1, pos2, pos3, pos4);
01780
01781 return MEASURE_NOERR;
01782 }
01783
01784
01785
01786
01787 int normal_atom_coord(Molecule *mol, int a, float *pos) {
01788 Timestep *now;
01789
01790 int cell[3];
01791 memset(cell, 0, 3*sizeof(int));
01792
01793
01794 int ret_val = check_mol(mol, a);
01795 if (ret_val<0)
01796 return ret_val;
01797
01798 if ((now = mol->current())) {
01799 memcpy((void *)pos, (void *)(now->pos + 3*a), 3*sizeof(float));
01800
01801
01802 Matrix4 mat;
01803 now->get_transform_from_cell(cell, mat);
01804 mat.multpoint3d(pos, pos);
01805
01806 return MEASURE_NOERR;
01807 }
01808
01809
01810 return MEASURE_ERR_NOFRAMES;
01811 }
01812
01813
01814
01815
01816 int check_mol(Molecule *mol, int a) {
01817
01818 if (!mol)
01819 return MEASURE_ERR_NOMOLECULE;
01820 if (a < 0 || a >= mol->nAtoms)
01821 return MEASURE_ERR_BADATOMID;
01822
01823 return MEASURE_NOERR;
01824 }
01825
01826
01827 int measure_energy(MoleculeList *mlist, int *molid, int *atmid, int natoms, ResizeArray<float> *gValues,
01828 int frame, int first, int last, int defmolid, double *params, int geomtype) {
01829 int i, ret_val;
01830 for(i=0; i < natoms; i++) {
01831
01832 if(i > 0 && molid[i-1]==molid[i] && atmid[i-1]==atmid[i]) {
01833 printf("measure_energy: %i/%i %i/%i\n", molid[i-1],atmid[i-1],molid[i],atmid[i]);
01834 return MEASURE_ERR_REPEATEDATOM;
01835 }
01836 }
01837
01838 float value;
01839 int max_ts, orig_ts;
01840
01841
01842 Molecule *mol = mlist->mol_from_id(defmolid);
01843 if( !mol )
01844 return MEASURE_ERR_NOMOLECULE;
01845
01846
01847 if((orig_ts = mol->frame()) < 0)
01848 return MEASURE_ERR_NOFRAMES;
01849
01850
01851 max_ts = mol->numframes()-1;
01852 if (frame==-1) {
01853 if (first<0 && last<0) first = last = orig_ts;
01854 if (last<0 || last>max_ts) last = max_ts;
01855 if (first<0) first = 0;
01856 } else {
01857 if (frame>max_ts || frame==-2) frame = max_ts;
01858 first = last = frame;
01859 }
01860
01861
01862 for(i=first; i <= last; i++) {
01863 mol->override_current_frame(i);
01864 switch (geomtype) {
01865 case MEASURE_BOND:
01866 if ((ret_val=compute_bond_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1]))<0)
01867 return ret_val;
01868 gValues->append(value);
01869 break;
01870 case MEASURE_ANGLE:
01871 if ((ret_val=compute_angle_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1], (float) params[2], (float) params[3]))<0)
01872 return ret_val;
01873 gValues->append(value);
01874 break;
01875 case MEASURE_DIHED:
01876 if ((ret_val=compute_dihed_energy(mlist, molid, atmid, &value, (float) params[0], int(params[1]), (float) params[2]))<0)
01877 return ret_val;
01878 gValues->append(value);
01879 break;
01880 case MEASURE_IMPRP:
01881 if ((ret_val=compute_imprp_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1]))<0)
01882 return ret_val;
01883 gValues->append(value);
01884 break;
01885 case MEASURE_VDW:
01886 if ((ret_val=compute_vdw_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1], (float) params[2], (float) params[3], (float) params[4], (float) params[5]))<0)
01887 return ret_val;
01888 gValues->append(value);
01889 break;
01890 case MEASURE_ELECT:
01891 if ((ret_val=compute_elect_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1], (bool) params[2], (bool) params[3], (float) params[4]))<0)
01892 return ret_val;
01893 gValues->append(value);
01894 break;
01895 }
01896 }
01897
01898
01899 mol->override_current_frame(orig_ts);
01900
01901 return MEASURE_NOERR;
01902 }
01903
01904
01905 int compute_bond_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float k, float x0) {
01906 int ret_val;
01907 float dist;
01908
01909
01910 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
01911 return ret_val;
01912 float x = dist-x0;
01913 *energy = k*x*x;
01914
01915 return MEASURE_NOERR;
01916 }
01917
01918
01919 int compute_angle_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
01920 float k, float x0, float kub, float s0) {
01921 int ret_val;
01922 float value;
01923
01924
01925 if ((ret_val=calculate_angle(mlist, molid, atmid, &value))<0)
01926 return ret_val;
01927 float x = (float) DEGTORAD((value-x0));
01928 float s = 0.0f;
01929
01930 if (kub>0.0f) {
01931 int twoatoms[2];
01932 twoatoms[0] = atmid[0];
01933 twoatoms[1] = atmid[2];
01934 if ((ret_val=calculate_bond(mlist, molid, twoatoms, &value))<0)
01935 return ret_val;
01936 s = value-s0;
01937 }
01938
01939 *energy = k*x*x + kub*s*s;
01940
01941 return MEASURE_NOERR;
01942 }
01943
01944
01945 int compute_dihed_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
01946 float k, int n, float delta) {
01947 int ret_val;
01948 float value;
01949
01950
01951 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
01952 return ret_val;
01953 *energy = k*(1+cosf((float) (DEGTORAD((n*value-delta)))));
01954
01955 return MEASURE_NOERR;
01956 }
01957
01958
01959 int compute_imprp_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
01960 float k, float x0) {
01961 int ret_val;
01962 float value;
01963
01964
01965 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
01966 return ret_val;
01967 float x = (float) (DEGTORAD((value-x0)));
01968 *energy = k*x*x;
01969
01970 return MEASURE_NOERR;
01971 }
01972
01973
01974
01975
01976
01977 int compute_vdw_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float eps1, float rmin1,
01978 float eps2, float rmin2, float cutoff, float switchdist) {
01979 int ret_val;
01980 float dist;
01981
01982
01983 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
01984 return ret_val;
01985
01986 float sw=1.0;
01987 if (switchdist>0.0 && cutoff>0.0) {
01988 if (dist>=cutoff) {
01989 sw = 0.0;
01990 } else if (dist>=switchdist) {
01991
01992 float dist2 = dist*dist;
01993 float cut2 = cutoff*cutoff;
01994 float switch2 = switchdist*switchdist;
01995 float s = cut2-dist2;
01996 float range = cut2-switch2;
01997 sw = s*s*(cut2+2*dist2-3*switch2)/(range*range*range);
01998 }
01999 }
02000
02001 float term6 = (float) powf((rmin1+rmin2)/dist,6);
02002 *energy = sqrtf(eps1*eps2)*(term6*term6 - 2.0f*term6)*sw;
02003
02004 return MEASURE_NOERR;
02005 }
02006
02007 int compute_elect_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float q1, float q2,
02008 bool flag1, bool flag2, float cutoff) {
02009 int ret_val;
02010 float dist;
02011
02012
02013 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
02014 return ret_val;
02015
02016
02017 if (!flag1) q1 = mlist->mol_from_id(molid[0])->charge()[atmid[0]];
02018 if (!flag2) q2 = mlist->mol_from_id(molid[0])->charge()[atmid[1]];
02019
02020 if (cutoff>0.0) {
02021 if (dist<cutoff) {
02022 float efac = 1.0f-dist*dist/(cutoff*cutoff);
02023 *energy = 332.0636f*q1*q2/dist*efac*efac;
02024 } else {
02025 *energy = 0.0f;
02026 }
02027 } else {
02028 *energy = 332.0636f*q1*q2/dist;
02029 }
02030
02031 return MEASURE_NOERR;
02032 }
02033
02034
02035
02036
02037 static void center_of_mass(AtomSel *sel, MoleculeList *mlist, float *rcom) {
02038 int i;
02039 float m = 0, mtot = 0;
02040 Molecule *mol = mlist->mol_from_id(sel->molid());
02041
02042
02043 const float *mass = mol->mass();
02044
02045
02046 const float *pos = sel->coordinates(mlist);
02047
02048 memset(rcom, 0, 3*sizeof(float));
02049
02050
02051 for (i=sel->firstsel; i<=sel->lastsel; i++) {
02052 if (sel->on[i]) {
02053 int ind = i * 3;
02054
02055 m = mass[i];
02056
02057 rcom[0] += m*pos[ind ];
02058 rcom[1] += m*pos[ind + 1];
02059 rcom[2] += m*pos[ind + 2];
02060
02061
02062 mtot += m;
02063 }
02064 }
02065
02066 rcom[0] /= mtot;
02067 rcom[1] /= mtot;
02068 rcom[2] /= mtot;
02069 }
02070
02071
02072
02073
02074
02075
02076
02077
02078 extern int measure_inertia(AtomSel *sel, MoleculeList *mlist, const float *coor, float rcom[3],
02079 float priaxes[3][3], float itensor[4][4], float evalue[3]) {
02080 if (!sel) return MEASURE_ERR_NOSEL;
02081 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
02082
02083 Molecule *mol = mlist->mol_from_id(sel->molid());
02084
02085 float x, y, z, m;
02086 float Ixx=0, Iyy=0, Izz=0, Ixy=0, Ixz=0, Iyz=0;
02087 int i,j=0;
02088
02089
02090
02091 memset(itensor, 0, 16*sizeof(float));
02092 itensor[3][3] = 1.0;
02093
02094
02095 center_of_mass(sel, mlist, rcom);
02096
02097
02098 const float *pos = sel->coordinates(mlist);
02099
02100
02101 const float *mass = mol->mass();
02102
02103
02104
02105 for (i=sel->firstsel; i<=sel->lastsel; i++) {
02106 if (sel->on[i]) {
02107
02108 if (coor) {
02109
02110 x = coor[j*3 ] - rcom[0];
02111 y = coor[j*3 + 1] - rcom[1];
02112 z = coor[j*3 + 2] - rcom[2];
02113 j++;
02114 } else {
02115
02116 x = pos[i*3 ] - rcom[0];
02117 y = pos[i*3 + 1] - rcom[1];
02118 z = pos[i*3 + 2] - rcom[2];
02119 }
02120
02121 m = mass[i];
02122
02123 Ixx += m*(y*y+z*z);
02124 Iyy += m*(x*x+z*z);
02125 Izz += m*(x*x+y*y);
02126 Ixy -= m*x*y;
02127 Ixz -= m*x*z;
02128 Iyz -= m*y*z;
02129 }
02130 }
02131
02132 itensor[0][0] = Ixx;
02133 itensor[1][1] = Iyy;
02134 itensor[2][2] = Izz;
02135 itensor[0][1] = Ixy;
02136 itensor[1][0] = Ixy;
02137 itensor[0][2] = Ixz;
02138 itensor[2][0] = Ixz;
02139 itensor[1][2] = Iyz;
02140 itensor[2][1] = Iyz;
02141
02142
02143
02144 float evector[3][3];
02145 if (jacobi(itensor,evalue,evector) != 0) return MEASURE_ERR_NONZEROJACOBI;
02146
02147
02148 float vectmp;
02149 vectmp=evector[0][1]; evector[0][1]=evector[1][0]; evector[1][0]=vectmp;
02150 vectmp=evector[0][2]; evector[0][2]=evector[2][0]; evector[2][0]=vectmp;
02151 vectmp=evector[2][1]; evector[2][1]=evector[1][2]; evector[1][2]=vectmp;
02152
02153
02154
02155
02156 float *a[3];
02157 a[0] = evector[0];
02158 a[1] = evector[1];
02159 a[2] = evector[2];
02160
02161
02162 #define SWAP(qq,ww) { \
02163 float v; float *v1; \
02164 v = evalue[qq]; evalue[qq] = evalue[ww]; evalue[ww] = v; \
02165 v1 = a[qq]; a[qq] = a[ww]; a[ww] = v1; \
02166 }
02167 if (evalue[0] < evalue[1]) {
02168 SWAP(0, 1);
02169 }
02170 if (evalue[0] < evalue[2]) {
02171 SWAP(0, 2);
02172 }
02173 if (evalue[1] < evalue[2]) {
02174 SWAP(1, 2);
02175 }
02176
02177 #if 0
02178
02179
02180 if (evalue[1]/evalue[0]>0.1 && fabs(evalue[1]-evalue[2])/evalue[0]<0.05
02181 && fabs(evalue[0]-evalue[1])/evalue[0]>0.05) {
02182 msgInfo << "Principal axes of inertia 2 and 3 are not unique!" << sendmsg;
02183 }
02184 #endif
02185
02186 for (i=0; i<3; i++) {
02187 for (j=0; j<3; j++)
02188 priaxes[i][j] = a[i][j];
02189 }
02190
02191 return MEASURE_NOERR;
02192 }
02193