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*3L;
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*3L;
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 extern int measure_center_perresidue(MoleculeList *mlist, const AtomSel *sel, const float *framepos,
00155 const float *weight, float *com) {
00156 if (!sel) return MEASURE_ERR_NOSEL;
00157 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
00158 if (!weight) return MEASURE_ERR_NOWEIGHT;
00159 if (!com) return MEASURE_ERR_NOCOM;
00160
00161 Molecule *mol = mlist->mol_from_id(sel->molid());
00162 int residue = mol->atom(sel->firstsel)->uniq_resid;
00163 int rescount = 0;
00164 int i, j = 0;
00165 float x=0, y=0, z=0, w=0;
00166 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00167 if (sel->on[i]) {
00168 if (residue != mol->atom(i)->uniq_resid) {
00169 com[3*rescount ] = x / w;
00170 com[3*rescount + 1] = y / w;
00171 com[3*rescount + 2] = z / w;
00172 residue = mol->atom(i)->uniq_resid;
00173 rescount++;
00174 x = 0;
00175 y = 0;
00176 z = 0;
00177 w = 0;
00178 }
00179 float tw = weight[j];
00180 w += tw;
00181 x += tw * framepos[3*i ];
00182 y += tw * framepos[3*i+1];
00183 z += tw * framepos[3*i+2];
00184 j++;
00185 }
00186 }
00187 com[3*rescount ] = x / w;
00188 com[3*rescount + 1] = y / w;
00189 com[3*rescount + 2] = z / w;
00190 rescount++;
00191 return rescount;
00192 }
00193
00194
00195
00196 int measure_center(const AtomSel *sel, const float *framepos,
00197 const float *weight, float *com) {
00198 if (!sel) return MEASURE_ERR_NOSEL;
00199 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
00200 if (!weight) return MEASURE_ERR_NOWEIGHT;
00201 if (!com) return MEASURE_ERR_NOCOM;
00202
00203 #if 0 && (__cplusplus >= 201103L)
00204 double x, y, z, w;
00205 w=x=y=z=0;
00206
00207 int j=0;
00208
00209 #if 1
00210 sel->for_selected_lambda([&] (int i) {
00211 float tw = weight[j];
00212 w += double(tw);
00213
00214 long ind = 3L * i;
00215 x += double(tw * framepos[ind ]);
00216 y += double(tw * framepos[ind+1]);
00217 z += double(tw * framepos[ind+2]);
00218 j++;
00219 });
00220 #else
00221 auto lambda_com = [&] (int i) {
00222 float tw = weight[j];
00223 w += double(tw);
00224
00225 long ind = 3L * i;
00226 x += double(tw * framepos[ind ]);
00227 y += double(tw * framepos[ind+1]);
00228 z += double(tw * framepos[ind+2]);
00229 j++;
00230 };
00231
00232 sel->for_selected_lambda(lambda_com);
00233 #endif
00234
00235 if (w == 0) {
00236 return MEASURE_ERR_BADWEIGHTSUM;
00237 }
00238
00239 x/=w;
00240 y/=w;
00241 z/=w;
00242
00243 com[0] = float(x);
00244 com[1] = float(y);
00245 com[2] = float(z);
00246 #else
00247
00248 int i, j;
00249 double x, y, z, w;
00250 j=0;
00251 w=x=y=z=0;
00252 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00253 if (sel->on[i]) {
00254 float tw = weight[j];
00255 w += double(tw);
00256 x += double(tw * framepos[3L*i ]);
00257 y += double(tw * framepos[3L*i+1]);
00258 z += double(tw * framepos[3L*i+2]);
00259 j++;
00260 }
00261 }
00262
00263 if (w == 0) {
00264 return MEASURE_ERR_BADWEIGHTSUM;
00265 }
00266
00267 x/=w;
00268 y/=w;
00269 z/=w;
00270
00271 com[0] = float(x);
00272 com[1] = float(y);
00273 com[2] = float(z);
00274 #endif
00275
00276 return MEASURE_NOERR;
00277 }
00278
00279
00280
00281 int measure_minmax(int num, const int *on, const float *framepos,
00282 const float *radii, float *min_coord, float *max_coord) {
00283 int i;
00284 float minx, miny, minz;
00285 float maxx, maxy, maxz;
00286
00287 if (!on) return MEASURE_ERR_NOSEL;
00288 if (num == 0) return MEASURE_ERR_NOATOMS;
00289 if (!min_coord || !max_coord) return MEASURE_ERR_NOMINMAXCOORDS;
00290
00291 vec_zero(min_coord);
00292 vec_zero(max_coord);
00293
00294
00295 int firstsel = 0;
00296 int lastsel = -1;
00297 if (analyze_selection_aligned_dispatch(NULL, num, on, &firstsel, &lastsel, NULL))
00298 return MEASURE_NOERR;
00299
00300
00301 i=firstsel;
00302 if (radii == NULL) {
00303
00304 minx = maxx = framepos[i*3L ];
00305 miny = maxy = framepos[i*3L+1];
00306 minz = maxz = framepos[i*3L+2];
00307 } else {
00308
00309 minx = framepos[i*3L ] - radii[i];
00310 maxx = framepos[i*3L ] + radii[i];
00311 miny = framepos[i*3L+1] - radii[i];
00312 maxy = framepos[i*3L+1] + radii[i];
00313 minz = framepos[i*3L+2] - radii[i];
00314 maxz = framepos[i*3L+2] + radii[i];
00315 }
00316
00317
00318 if (radii == NULL) {
00319
00320 #if 0
00321 minmax_selected_3fv_aligned(framepos, on, atomSel->num_atoms,
00322 firstsel, lastsel, fmin, fmax);
00323 #else
00324 for (i++; i<=lastsel; i++) {
00325 if (on[i]) {
00326 long ind = i * 3L;
00327 float tmpx = framepos[ind ];
00328 if (tmpx < minx) minx = tmpx;
00329 if (tmpx > maxx) maxx = tmpx;
00330
00331 float tmpy = framepos[ind+1];
00332 if (tmpy < miny) miny = tmpy;
00333 if (tmpy > maxy) maxy = tmpy;
00334
00335 float tmpz = framepos[ind+2];
00336 if (tmpz < minz) minz = tmpz;
00337 if (tmpz > maxz) maxz = tmpz;
00338 }
00339 }
00340 #endif
00341 } else {
00342
00343 for (i++; i<=lastsel; i++) {
00344 if (on[i]) {
00345 long ind = i * 3L;
00346 float mintmpx = framepos[ind ] - radii[i];
00347 float maxtmpx = framepos[ind ] + radii[i];
00348 if (mintmpx < minx) minx = mintmpx;
00349 if (maxtmpx > maxx) maxx = maxtmpx;
00350
00351 float mintmpy = framepos[ind+1] - radii[i];
00352 float maxtmpy = framepos[ind+1] + radii[i];
00353 if (mintmpy < miny) miny = mintmpy;
00354 if (maxtmpy > maxy) maxy = maxtmpy;
00355
00356 float mintmpz = framepos[ind+2] - radii[i];
00357 float maxtmpz = framepos[ind+2] + radii[i];
00358 if (mintmpz < minz) minz = mintmpz;
00359 if (maxtmpz > maxz) maxz = maxtmpz;
00360 }
00361 }
00362 }
00363
00364
00365 min_coord[0]=minx;
00366 min_coord[1]=miny;
00367 min_coord[2]=minz;
00368 max_coord[0]=maxx;
00369 max_coord[1]=maxy;
00370 max_coord[2]=maxz;
00371
00372 return MEASURE_NOERR;
00373 }
00374
00375
00376
00377
00378
00379
00380 int measure_avpos_perresidue(const AtomSel *sel, MoleculeList *mlist,
00381 int start, int end, int step, float *avpos) {
00382
00383 int retval = measure_avpos(sel, mlist, start, end, step, avpos);
00384 if (retval != MEASURE_NOERR) {
00385 return retval;
00386 }
00387 Molecule *mol = mlist->mol_from_id(sel->molid());
00388 int residue = mol->atom(sel->firstsel)->uniq_resid;
00389 int rescount = 0;
00390 int ressize = 0;
00391 float accumulate[3] = {0.0,0.0,0.0};
00392 int j = 0, k, i;
00393 for (i = sel->firstsel; i <= sel->lastsel; i++) {
00394 if (sel->on[i]) {
00395 if (residue != mol->atom(i)->uniq_resid) {
00396 for (k = 0; k < 3; k++) {
00397 avpos[3*rescount + k] = accumulate[k] / ressize;
00398 accumulate[k] = 0.0;
00399 }
00400 residue = mol->atom(i)->uniq_resid;
00401 ressize = 0;
00402 rescount++;
00403 }
00404 for (k = 0; k < 3; k++) {
00405 accumulate[k] += avpos[3*j + k];
00406 }
00407 j++;
00408 ressize++;
00409 }
00410 }
00411 for (k = 0; k < 3; k++) {
00412 avpos[3*rescount + k] = accumulate[k] / ressize;
00413 }
00414 rescount++;
00415 return rescount;
00416 }
00417
00418
00419 extern int measure_avpos(const AtomSel *sel, MoleculeList *mlist,
00420 int start, int end, int step, float *avpos) {
00421 if (!sel) return MEASURE_ERR_NOSEL;
00422 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00423
00424 Molecule *mymol = mlist->mol_from_id(sel->molid());
00425 int maxframes = mymol->numframes();
00426
00427
00428 if (end == -1)
00429 end = maxframes-1;
00430
00431 if (maxframes == 0 || start < 0 || start > end ||
00432 end >= maxframes || step <= 0)
00433 return MEASURE_ERR_BADFRAMERANGE;
00434
00435 long i;
00436 for (i=0; i<(3L*sel->selected); i++)
00437 avpos[i] = 0.0f;
00438
00439 long frame, avcount, j;
00440 for (avcount=0,frame=start; frame<=end; avcount++,frame+=step) {
00441 const float *framepos = (mymol->get_frame(frame))->pos;
00442 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00443 if (sel->on[i]) {
00444 avpos[j*3L ] += framepos[i*3L ];
00445 avpos[j*3L + 1] += framepos[i*3L + 1];
00446 avpos[j*3L + 2] += framepos[i*3L + 2];
00447 j++;
00448 }
00449 }
00450 }
00451
00452 float avinv = 1.0f / (float) avcount;
00453 for (j=0; j<(3L*sel->selected); j++) {
00454 avpos[j] *= avinv;
00455 }
00456
00457 return MEASURE_NOERR;
00458 }
00459
00460
00461
00462 extern int measure_dipole(const AtomSel *sel, MoleculeList *mlist,
00463 float *dipole, int unitsdebye, int usecenter) {
00464 if (!sel) return MEASURE_ERR_NOSEL;
00465 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00466
00467 Molecule *mymol = mlist->mol_from_id(sel->molid());
00468 double rvec[3] = {0, 0, 0};
00469 double qrvec[3] = {0, 0, 0};
00470 double mrvec[3] = {0, 0, 0};
00471 double totalq = 0.0;
00472 double totalm = 0.0;
00473 int i;
00474
00475
00476 const float *framepos = sel->coordinates(mlist);
00477
00478
00479 const float *q = mymol->charge();
00480 const float *m = mymol->mass();
00481
00482 for (i=sel->firstsel; i<=sel->lastsel; i++) {
00483 if (sel->on[i]) {
00484 int ind = i * 3;
00485 rvec[0] += framepos[ind ];
00486 rvec[1] += framepos[ind + 1];
00487 rvec[2] += framepos[ind + 2];
00488
00489 qrvec[0] += framepos[ind ] * q[i];
00490 qrvec[1] += framepos[ind + 1] * q[i];
00491 qrvec[2] += framepos[ind + 2] * q[i];
00492
00493 mrvec[0] += framepos[ind ] * m[i];
00494 mrvec[1] += framepos[ind + 1] * m[i];
00495 mrvec[2] += framepos[ind + 2] * m[i];
00496
00497 totalq += q[i];
00498 totalm += m[i];
00499 }
00500 }
00501
00502
00503 if (totalm < 0.0001)
00504 usecenter=1;
00505
00506 switch (usecenter) {
00507 case 1:
00508 {
00509 double rscale = totalq / sel->selected;
00510 dipole[0] = (float) (qrvec[0] - (rvec[0] * rscale));
00511 dipole[1] = (float) (qrvec[1] - (rvec[1] * rscale));
00512 dipole[2] = (float) (qrvec[2] - (rvec[2] * rscale));
00513 break;
00514 }
00515
00516 case -1:
00517 {
00518 double mscale = totalq / totalm;
00519 dipole[0] = (float) (qrvec[0] - (mrvec[0] * mscale));
00520 dipole[1] = (float) (qrvec[1] - (mrvec[1] * mscale));
00521 dipole[2] = (float) (qrvec[2] - (mrvec[2] * mscale));
00522 break;
00523 }
00524
00525 case 0:
00526 default:
00527 {
00528 dipole[0] = (float) qrvec[0];
00529 dipole[1] = (float) qrvec[1];
00530 dipole[2] = (float) qrvec[2];
00531 break;
00532 }
00533 }
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 if (unitsdebye) {
00545
00546
00547
00548 dipole[0] *= 4.80320425132f;
00549 dipole[1] *= 4.80320425132f;
00550 dipole[2] *= 4.80320425132f;
00551 }
00552
00553 return MEASURE_NOERR;
00554 }
00555
00556
00557 extern int measure_hbonds(Molecule *mol, AtomSel *sel1, AtomSel *sel2, double cutoff, double maxangle, int *donlist, int *hydlist, int *acclist, int maxsize) {
00558 int hbondcount = 0;
00559 const float *pos = sel1->coordinates(mol->app->moleculeList);
00560 const int *A = sel1->on;
00561 const int *B = sel2 ? sel2->on : sel1->on;
00562 GridSearchPair *pairlist = vmd_gridsearch2(pos, sel1->num_atoms, A, B, (float) cutoff, sel1->num_atoms * 27);
00563 GridSearchPair *p, *tmp;
00564 float donortoH[3], Htoacceptor[3];
00565
00566 for (p=pairlist; p != NULL; p=tmp) {
00567 MolAtom *a1 = mol->atom(p->ind1);
00568 MolAtom *a2 = mol->atom(p->ind2);
00569
00570
00571 if (mol->atom(p->ind1)->atomType == ATOMHYDROGEN ||
00572 mol->atom(p->ind2)->atomType == ATOMHYDROGEN) {
00573 tmp = p->next;
00574 free(p);
00575 continue;
00576 }
00577 if (!a1->bonded(p->ind2)) {
00578 int b1 = a1->bonds;
00579 int b2 = a2->bonds;
00580 const float *coor1 = pos + 3*p->ind1;
00581 const float *coor2 = pos + 3*p->ind2;
00582 int k;
00583
00584 for (k=0; k<b1; k++) {
00585 const int hindex = a1->bondTo[k];
00586 if (mol->atom(hindex)->atomType == ATOMHYDROGEN) {
00587 const float *hydrogen = pos + 3*hindex;
00588 vec_sub(donortoH,hydrogen,coor1);
00589 vec_sub(Htoacceptor,coor2,hydrogen);
00590 if (angle(donortoH, Htoacceptor) < maxangle ) {
00591 if (hbondcount < maxsize) {
00592 donlist[hbondcount] = p->ind1;
00593 acclist[hbondcount] = p->ind2;
00594 hydlist[hbondcount] = hindex;
00595 }
00596 hbondcount++;
00597 }
00598 }
00599 }
00600
00601 if (!sel2) {
00602 for (k=0; k<b2; k++) {
00603 const int hindex = a2->bondTo[k];
00604 if (mol->atom(hindex)->atomType == ATOMHYDROGEN) {
00605 const float *hydrogen = pos + 3*hindex;
00606 vec_sub(donortoH,hydrogen,coor2);
00607 vec_sub(Htoacceptor,coor1,hydrogen);
00608 if (angle(donortoH, Htoacceptor) < maxangle ) {
00609 if (hbondcount < maxsize) {
00610 donlist[hbondcount] = p->ind2;
00611 acclist[hbondcount] = p->ind1;
00612 hydlist[hbondcount] = hindex;
00613 }
00614 hbondcount++;
00615 }
00616 }
00617 }
00618 }
00619 }
00620 tmp = p->next;
00621 free(p);
00622 }
00623 return hbondcount;
00624 }
00625
00626 int measure_rmsf_perresidue(const AtomSel *sel, MoleculeList *mlist,
00627 int start, int end, int step, float *rmsf) {
00628 if (!sel) return MEASURE_ERR_NOSEL;
00629 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00630
00631 Molecule *mymol = mlist->mol_from_id(sel->molid());
00632 int maxframes = mymol->numframes();
00633
00634
00635 if (end == -1)
00636 end = maxframes-1;
00637
00638 if (maxframes == 0 || start < 0 || start > end ||
00639 end >= maxframes || step <= 0)
00640 return MEASURE_ERR_BADFRAMERANGE;
00641
00642 int i;
00643 for (i=0; i<sel->selected; i++)
00644 rmsf[i] = 0.0f;
00645
00646 int rc;
00647 float *avpos = new float[3*sel->selected];
00648
00649 rc = measure_avpos_perresidue(sel, mlist, start, end, step, avpos);
00650 if (rc <= 0) {
00651 delete [] avpos;
00652 return rc;
00653 }
00654
00655 int frame, avcount;
00656 float *center = new float[3*rc];
00657 float *weights = new float[sel->selected];
00658 for (i = 0; i < sel->selected; i++) {
00659 weights[i] = 1.0;
00660 }
00661
00662 for (avcount=0,frame=start; frame<=end; avcount++,frame+=step) {
00663 const float *framepos = (mymol->get_frame(frame))->pos;
00664 measure_center_perresidue(mlist, sel, framepos, weights, center);
00665 for (i = 0; i < rc; i++) {
00666 rmsf[i] += distance2(&avpos[3*i], ¢er[3*i]);
00667 }
00668 }
00669 delete [] center;
00670 delete [] weights;
00671
00672 float avinv = 1.0f / (float) avcount;
00673 for (i=0; i<rc; i++) {
00674 rmsf[i] = sqrtf(rmsf[i] * avinv);
00675 }
00676
00677 delete [] avpos;
00678 return rc;
00679 }
00680
00681
00682 extern int measure_rmsf(const AtomSel *sel, MoleculeList *mlist,
00683 int start, int end, int step, float *rmsf) {
00684 if (!sel) return MEASURE_ERR_NOSEL;
00685 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
00686
00687 Molecule *mymol = mlist->mol_from_id(sel->molid());
00688 int maxframes = mymol->numframes();
00689
00690
00691 if (end == -1)
00692 end = maxframes-1;
00693
00694 if (maxframes == 0 || start < 0 || start > end ||
00695 end >= maxframes || step <= 0)
00696 return MEASURE_ERR_BADFRAMERANGE;
00697
00698 int i;
00699 for (i=0; i<sel->selected; i++)
00700 rmsf[i] = 0.0f;
00701
00702 int rc;
00703 float *avpos = new float[3L*sel->selected];
00704 rc = measure_avpos(sel, mlist, start, end, step, avpos);
00705
00706 if (rc != MEASURE_NOERR) {
00707 delete [] avpos;
00708 return rc;
00709 }
00710
00711
00712 int frame, avcount, j;
00713 for (avcount=0,frame=start; frame<=end; avcount++,frame+=step) {
00714 const float *framepos = (mymol->get_frame(frame))->pos;
00715 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00716 if (sel->on[i]) {
00717 rmsf[j] += distance2(&avpos[3L*j], &framepos[3L*i]);
00718 j++;
00719 }
00720 }
00721 }
00722
00723 float avinv = 1.0f / (float) avcount;
00724 for (j=0; j<sel->selected; j++) {
00725 rmsf[j] = sqrtf(rmsf[j] * avinv);
00726 }
00727
00728 delete [] avpos;
00729 return MEASURE_NOERR;
00730 }
00731
00732
00734
00735
00736
00737 int measure_rgyr(const AtomSel *sel, MoleculeList *mlist, const float *weight,
00738 float *rgyr) {
00739 if (!rgyr) return MEASURE_ERR_NORGYR;
00740 if (!sel) return MEASURE_ERR_NOSEL;
00741 if (!mlist) return MEASURE_ERR_GENERAL;
00742
00743 const float *framepos = sel->coordinates(mlist);
00744
00745
00746 float com[3];
00747 int ret_val = measure_center(sel, framepos, weight, com);
00748 if (ret_val < 0)
00749 return ret_val;
00750
00751
00752 int i, j;
00753 float total_w, sum;
00754
00755 total_w=sum=0;
00756 for (j=0,i=sel->firstsel; i<=sel->lastsel; i++) {
00757 if (sel->on[i]) {
00758 float w = weight[j];
00759 total_w += w;
00760 sum += w * distance2(framepos + 3L*i, com);
00761 j++;
00762 }
00763 }
00764
00765 if (total_w == 0) {
00766 return MEASURE_ERR_BADWEIGHTSUM;
00767 }
00768
00769
00770 *rgyr = sqrtf(sum/total_w);
00771
00772 return MEASURE_NOERR;
00773 }
00774
00775
00776
00777
00778
00779
00780 int measure_rmsd_perresidue(const AtomSel *sel1, const AtomSel *sel2, MoleculeList *mlist,
00781 int num,
00782 float *weight, float *rmsd) {
00783 if (!sel1 || !sel2) return MEASURE_ERR_NOSEL;
00784 if (sel1->selected < 1 || sel2->selected < 1) return MEASURE_ERR_NOSEL;
00785 if (!weight || !rmsd) return MEASURE_ERR_NOWEIGHT;
00786
00787
00788 if (sel1->selected != sel2->selected) return MEASURE_ERR_MISMATCHEDCNT;
00789
00790
00791
00792
00793 int sel_flg;
00794 if (num == sel1->num_atoms) {
00795 sel_flg = 1;
00796 } else {
00797 sel_flg = 0;
00798 }
00799
00800
00801 float tmp_w;
00802 int w_index = 0;
00803 int sel1ind = sel1->firstsel;
00804 int sel2ind = sel2->firstsel;
00805 float wsum = 0;
00806 float twsum = 0;
00807 float rmsdsum = 0;
00808 const float *framepos1 = sel1->coordinates(mlist);
00809 const float *framepos2 = sel2->coordinates(mlist);
00810 Molecule *mol = mlist->mol_from_id(sel1->molid());
00811
00812
00813 int count = sel1->selected;
00814 int residue = mol->atom(sel1ind)->uniq_resid;
00815 int rescount = 0;
00816 while (count-- > 0) {
00817
00818
00819 while (!sel1->on[sel1ind])
00820 sel1ind++;
00821 while (!sel2->on[sel2ind])
00822 sel2ind++;
00823 if (residue != mol->atom(sel1ind)->uniq_resid) {
00824 rmsd[rescount] = sqrtf(rmsdsum / wsum);
00825 rmsdsum = 0;
00826 twsum += wsum;
00827 wsum = 0;
00828 residue = mol->atom(sel1ind)->uniq_resid;
00829 rescount++;
00830 }
00831
00832 if (sel_flg == 0) {
00833 tmp_w = weight[w_index++];
00834 } else {
00835 tmp_w = weight[sel1ind];
00836 }
00837
00838
00839 rmsdsum += tmp_w * distance2(framepos1 + 3*sel1ind, framepos2 + 3*sel2ind);
00840 wsum += tmp_w;
00841
00842
00843 sel1ind++;
00844 sel2ind++;
00845 }
00846 twsum += wsum;
00847
00848 if (twsum == 0) {
00849 return MEASURE_ERR_BADWEIGHTSUM;
00850 }
00851
00852
00853 rmsd[rescount++] = sqrtf(rmsdsum / wsum);
00854
00855 return rescount;
00856 }
00857
00859
00860
00861
00862
00863
00864
00865
00866 int measure_rmsd(const AtomSel *sel1, const AtomSel *sel2,
00867 int num, const float *framepos1, const float *framepos2,
00868 float *weight, float *rmsd) {
00869 if (!sel1 || !sel2) return MEASURE_ERR_NOSEL;
00870 if (sel1->selected < 1 || sel2->selected < 1) return MEASURE_ERR_NOSEL;
00871 if (!weight || !rmsd) return MEASURE_ERR_NOWEIGHT;
00872
00873
00874 if (sel1->selected != sel2->selected) return MEASURE_ERR_MISMATCHEDCNT;
00875
00876
00877
00878
00879 int sel_flg;
00880 if (num == sel1->num_atoms) {
00881 sel_flg = 1;
00882 } else {
00883 sel_flg = 0;
00884 }
00885
00886
00887 float tmp_w;
00888 int w_index = 0;
00889 int sel1ind = sel1->firstsel;
00890 int sel2ind = sel2->firstsel;
00891 float wsum = 0;
00892 float rmsdsum = 0;
00893
00894 *rmsd = 10000000;
00895
00896
00897 int count = sel1->selected;
00898 while (count-- > 0) {
00899
00900
00901 while (!sel1->on[sel1ind])
00902 sel1ind++;
00903 while (!sel2->on[sel2ind])
00904 sel2ind++;
00905
00906
00907 if (sel_flg == 0) {
00908 tmp_w = weight[w_index++];
00909 } else {
00910 tmp_w = weight[sel1ind];
00911 }
00912
00913
00914 rmsdsum += tmp_w * distance2(framepos1 + 3L*sel1ind, framepos2 + 3L*sel2ind);
00915 wsum += tmp_w;
00916
00917
00918 sel1ind++;
00919 sel2ind++;
00920 }
00921
00922
00923 if (wsum == 0) {
00924 return MEASURE_ERR_BADWEIGHTSUM;
00925 }
00926
00927
00928 *rmsd = sqrtf(rmsdsum / wsum);
00929
00930 return MEASURE_NOERR;
00931 }
00932
00933
00934
00935 #define ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\
00936 a[k][l]=h+s*(g-h*tau);
00937
00938 static int jacobi(float a[4][4], float d[3], float v[3][3])
00939 {
00940 int n=3;
00941 int j,iq,ip,i;
00942 float tresh,theta,tau,t,sm,s,h,g,c,*b,*z;
00943
00944 b=new float[n];
00945 z=new float[n];
00946 for (ip=0;ip<n;ip++) {
00947 for (iq=0;iq<n;iq++) v[ip][iq]=0.0;
00948 v[ip][ip]=1.0;
00949 }
00950 for (ip=0;ip<n;ip++) {
00951 b[ip]=d[ip]=a[ip][ip];
00952 z[ip]=0.0;
00953 }
00954 for (i=1;i<=50;i++) {
00955 sm=0.0;
00956 for (ip=0;ip<n-1;ip++) {
00957 for (iq=ip+1;iq<n;iq++)
00958 sm += (float) fabs(a[ip][iq]);
00959 }
00960 if (sm == 0.0) {
00961 delete [] z;
00962 delete [] b;
00963 return 0;
00964 }
00965 if (i < 4)
00966 tresh=0.2f*sm/(n*n);
00967 else
00968 tresh=0.0f;
00969 for (ip=0;ip<n-1;ip++) {
00970 for (iq=ip+1;iq<n;iq++) {
00971 g=100.0f * fabsf(a[ip][iq]);
00972 if (i > 4 && (float)(fabs(d[ip])+g) == (float)fabs(d[ip])
00973 && (float)(fabs(d[iq])+g) == (float)fabs(d[iq]))
00974 a[ip][iq]=0.0;
00975 else if (fabs(a[ip][iq]) > tresh) {
00976 h=d[iq]-d[ip];
00977 if ((float)(fabs(h)+g) == (float)fabs(h))
00978 t=(a[ip][iq])/h;
00979 else {
00980 theta=0.5f*h/(a[ip][iq]);
00981 t=1.0f/(fabsf(theta)+sqrtf(1.0f+theta*theta));
00982 if (theta < 0.0f) t = -t;
00983 }
00984 c=1.0f/sqrtf(1+t*t);
00985 s=t*c;
00986 tau=s/(1.0f+c);
00987 h=t*a[ip][iq];
00988 z[ip] -= h;
00989 z[iq] += h;
00990 d[ip] -= h;
00991 d[iq] += h;
00992 a[ip][iq]=0.0;
00993 for (j=0;j<=ip-1;j++) {
00994 ROTATE(a,j,ip,j,iq)
00995 }
00996 for (j=ip+1;j<=iq-1;j++) {
00997 ROTATE(a,ip,j,j,iq)
00998 }
00999 for (j=iq+1;j<n;j++) {
01000 ROTATE(a,ip,j,iq,j)
01001 }
01002 for (j=0;j<n;j++) {
01003 ROTATE(v,j,ip,j,iq)
01004 }
01005 }
01006 }
01007 }
01008 for (ip=0;ip<n;ip++) {
01009 b[ip] += z[ip];
01010 d[ip]=b[ip];
01011 z[ip]=0.0;
01012 }
01013 }
01014 delete [] b;
01015 delete [] z;
01016 return 1;
01017 }
01018 #undef ROTATE
01019
01020 static int transvecinv(const double *v, Matrix4 &res) {
01021 double x, y, z;
01022 x=v[0];
01023 y=v[1];
01024 z=v[2];
01025 if (x == 0.0 && y == 0.0) {
01026 if (z == 0.0) {
01027 return -1;
01028 }
01029 if (z > 0)
01030 res.rot(90, 'y');
01031 else
01032 res.rot(-90, 'y');
01033 return 0;
01034 }
01035 double theta = atan2(y,x);
01036 double length = sqrt(x*x + y*y);
01037 double phi = atan2(z,length);
01038 res.rot((float) RADTODEG(phi), 'y');
01039 res.rot((float) RADTODEG(-theta), 'z');
01040 return 0;
01041 }
01042
01043 static int transvec(const double *v, Matrix4 &res) {
01044 double x, y, z;
01045 x=v[0];
01046 y=v[1];
01047 z=v[2];
01048 if (x == 0.0 && y == 0.0) {
01049 if (z == 0.0) {
01050 return -1;
01051 }
01052 if (z > 0)
01053 res.rot(-90, 'y');
01054 else
01055 res.rot(90, 'y');
01056 return 0;
01057 }
01058 double theta = atan2(y,x);
01059 double length = sqrt(x*x + y*y);
01060 double phi = atan2(z,length);
01061 res.rot((float) RADTODEG(theta), 'z');
01062 res.rot((float) RADTODEG(-phi), 'y');
01063 return 0;
01064 }
01065
01066 static Matrix4 myfit2(const float *x, const float *y,
01067 const float *comx, const float *comy) {
01068
01069 Matrix4 res;
01070 double dx[3], dy[3];
01071 dx[0] = x[0] - comx[0];
01072 dx[1] = x[1] - comx[1];
01073 dx[2] = x[2] - comx[2];
01074 dy[0] = y[0] - comy[0];
01075 dy[1] = y[1] - comy[1];
01076 dy[2] = y[2] - comy[2];
01077
01078 res.translate(comy[0], comy[1], comy[2]);
01079 transvec(dy, res);
01080 transvecinv(dx, res);
01081 res.translate(-comx[0], -comx[1], -comx[2]);
01082 return res;
01083 }
01084
01085 static Matrix4 myfit3(const float *x1, const float *x2,
01086 const float *y1, const float *y2,
01087 const float *comx, const float *comy) {
01088
01089 Matrix4 mx, my, rx1, ry1;
01090 double dx1[3], dy1[3], angle;
01091 float dx2[3], dy2[3], x2t[3], y2t[3];
01092
01093 for (int i=0; i<3; i++) {
01094 dx1[i] = x1[i] - comx[i];
01095 dx2[i] = x2[i] - comx[i];
01096 dy1[i] = y1[i] - comy[i];
01097 dy2[i] = y2[i] - comy[i];
01098 }
01099
01100
01101
01102
01103
01104
01105
01106 transvecinv(dx1, rx1);
01107 rx1.multpoint3d(dx2, x2t);
01108 angle = atan2(x2t[2], x2t[1]);
01109 mx.rot((float) RADTODEG(angle), 'x');
01110 mx.multmatrix(rx1);
01111 mx.translate(-comx[0], -comx[1], -comx[2]);
01112
01113 transvecinv(dy1, ry1);
01114 ry1.multpoint3d(dy2, y2t);
01115 angle = atan2(y2t[2], y2t[1]);
01116 my.rot((float) RADTODEG(angle), 'x');
01117 my.multmatrix(ry1);
01118 my.translate(-comy[0], -comy[1], -comy[2]);
01119 my.inverse();
01120 my.multmatrix(mx);
01121 return my;
01122 }
01123
01124
01125
01126
01127
01128 int measure_fit(const AtomSel *sel1, const AtomSel *sel2, const float *x,
01129 const float *y, const float *weight,
01130 const int *order, Matrix4 *mat) {
01131 float comx[3];
01132 float comy[3];
01133 int num = sel1->selected;
01134 int ret_val;
01135 ret_val = measure_center(sel1, x, weight, comx);
01136 if (ret_val < 0) {
01137 return ret_val;
01138 }
01139 ret_val = measure_center(sel2, y, weight, comy);
01140 if (ret_val < 0) {
01141 return ret_val;
01142 }
01143
01144
01145
01146
01147 switch (sel1->selected) {
01148 case 1: {
01149 Matrix4 tmp;
01150 tmp.translate(-comx[0], -comx[1], -comx[2]);
01151 tmp.translate(comy[0], comy[1], comy[2]);
01152 memcpy(mat->mat, tmp.mat, 16L*sizeof(float));
01153 return MEASURE_NOERR;
01154 }
01155 case 3:
01156 case 2: {
01157
01158 int pts[6], count = 0;
01159 int n;
01160 for (n=sel1->firstsel; n<=sel1->lastsel; n++) {
01161 if (sel1->on[n]) {
01162 pts[count++] = n;
01163 if (sel1->selected == 2) {
01164 count++;
01165 break;
01166 }
01167 if (count == 2) break;
01168 }
01169 }
01170 for (n=sel2->firstsel; n<=sel2->lastsel; n++) {
01171 if (sel2->on[n]) {
01172 pts[count++] = n;
01173 if (sel1->selected == 2) {
01174 count++;
01175 break;
01176 }
01177 if (count == 4) break;
01178 }
01179 }
01180 if (count != 4) {
01181 return MEASURE_ERR_MISMATCHEDCNT;
01182 }
01183
01184
01185 if (order != NULL) {
01186 int i;
01187 int tmp[6];
01188 memcpy(tmp, pts, sizeof(pts));
01189 for (i=0; i<num; i++) {
01190 pts[i + num] = tmp[num + order[i]];
01191 }
01192 }
01193
01194 if (sel1->selected == 2) {
01195 *mat = myfit2(x+3L*pts[0], y+3L*pts[2], comx, comy);
01196 ret_val = 0;
01197 } else {
01198 *mat = myfit3(x+3L*pts[0], x+3L*pts[1], y+3L*pts[2], y+3L*pts[3], comx, comy);
01199 ret_val = 0;
01200 }
01201 if (ret_val != 0) {
01202 return MEASURE_ERR_GENERAL;
01203 }
01204
01205 return 0;
01206 }
01207 default:
01208 break;
01209 }
01210
01211
01212
01213
01214 char *opt = getenv("VMDRMSFITMETHOD");
01215 if (!opt || strcmp(opt, "oldvmd")) {
01216 int i, k;
01217 float *v1, *v2;
01218 v1 = new float[3L*num];
01219 v2 = new float[3L*num];
01220 for (k=0, i=sel1->firstsel; i<=sel1->lastsel; i++) {
01221 if (sel1->on[i]) {
01222 long ind = 3L * i;
01223 v1[k++] = x[ind ];
01224 v1[k++] = x[ind + 1];
01225 v1[k++] = x[ind + 2];
01226 }
01227 }
01228 for (k=0, i=sel2->firstsel; i<=sel2->lastsel; i++) {
01229 if (sel2->on[i]) {
01230 long ind = 3L * i;
01231 v2[k++] = y[ind ];
01232 v2[k++] = y[ind + 1];
01233 v2[k++] = y[ind + 2];
01234 }
01235 }
01236
01237
01238 if (order != NULL) {
01239 int i;
01240 float *tmp = new float[3L*num];
01241 memcpy(tmp, v2, 3L*num*sizeof(float));
01242 for (i=0; i<num; i++) {
01243 long ind = 3L * i;
01244 long idx = 3L * order[i];
01245 v2[ind ] = tmp[idx ];
01246 v2[ind + 1] = tmp[idx + 1];
01247 v2[ind + 2] = tmp[idx + 2];
01248 }
01249 delete[] tmp;
01250 }
01251
01252 float tmp[16];
01253
01254
01255
01256
01257 MatrixFitRMS(num, v1, v2, weight, tmp);
01258
01259 delete [] v1;
01260 delete [] v2;
01261
01262
01263
01264 float pre[3], post[3];
01265 for (i=0; i<3; i++) {
01266 post[i] = tmp[4L*i+3];
01267 tmp[4L*i+3] = 0;
01268 }
01269 for (i=0; i<3; i++) {
01270 pre[i] = tmp[12+i];
01271 tmp[12+i] = 0;
01272 }
01273 Matrix4 result;
01274 result.translate(pre);
01275 result.multmatrix(Matrix4(tmp));
01276 result.translate(post);
01277 memcpy(mat->mat, result.mat, 16L*sizeof(float));
01278 return 0;
01279 }
01280
01281
01282 if (order != NULL) {
01283 return MEASURE_ERR_NOTSUP;
01284 }
01285
01286
01287 Matrix4 R;
01288 int i,j;
01289 float scale = (float) num * num;
01290 for (i=0; i<3; i++) {
01291 for (j=0; j<3; j++) {
01292 float tmp = 0;
01293 int nx = 0, ny = 0, k = 0;
01294 while (nx < sel1->num_atoms && ny < sel2->num_atoms) {
01295 if (!sel1->on[nx]) {
01296 nx++;
01297 continue;
01298 }
01299 if (!sel2->on[ny]) {
01300 ny++;
01301 continue;
01302 }
01303
01304
01305
01306 tmp += weight[k] * (y[3L*ny+i] - comy[i]) * (x[3L*nx+j] - comx[j]) /
01307 scale;
01308 nx++;
01309 ny++;
01310 k++;
01311 }
01312 R.mat[4L*i+j] = tmp;
01313 }
01314 }
01315
01316
01317 Matrix4 Rt;
01318 for (i=0; i<3; i++) {
01319 for (j=0; j<3; j++) {
01320 Rt.mat[4L*i+j] = R.mat[4L*j+i];
01321 }
01322 }
01323 Matrix4 RtR(R);
01324 RtR.multmatrix(Rt);
01325
01326
01327 float evalue[3];
01328 float evector[3][3];
01329 float tmpmat[4][4];
01330 for (i=0; i<4; i++)
01331 for (j=0; j<4; j++)
01332 tmpmat[i][j]=RtR.mat[4L*i+j];
01333
01334 if(jacobi(tmpmat,evalue,evector) != 0) return MEASURE_ERR_NONZEROJACOBI;
01335
01336 float vectmp;
01337 vectmp=evector[0][1]; evector[0][1]=evector[1][0]; evector[1][0]=vectmp;
01338 vectmp=evector[0][2]; evector[0][2]=evector[2][0]; evector[2][0]=vectmp;
01339 vectmp=evector[2][1]; evector[2][1]=evector[1][2]; evector[1][2]=vectmp;
01340
01341
01342
01343
01344 float *a[3];
01345 a[0] = evector[0];
01346 a[1] = evector[1];
01347 a[2] = evector[2];
01348 #define SWAP(qq,ww) { \
01349 float v; float *v1; \
01350 v = evalue[qq]; evalue[qq] = evalue[ww]; evalue[ww] = v; \
01351 v1 = a[qq]; a[qq] = a[ww]; a[ww] = v1; \
01352 }
01353 if (evalue[0] < evalue[1]) {
01354 SWAP(0, 1);
01355 }
01356 if (evalue[0] < evalue[2]) {
01357 SWAP(0, 2);
01358 }
01359 if (evalue[1] < evalue[2]) {
01360 SWAP(1, 2);
01361 }
01362
01363
01364
01365 float b[3][3];
01366
01367 Rt.multpoint3d(a[0], b[0]);
01368 vec_normalize(b[0]);
01369
01370 Rt.multpoint3d(a[1], b[1]);
01371 vec_normalize(b[1]);
01372
01373 Rt.multpoint3d(a[2], b[2]);
01374 vec_normalize(b[2]);
01375
01376
01377 Matrix4 U;
01378 for (i=0; i<3; i++) {
01379 for (j=0; j<3; j++) {
01380 float *tmp = &(U.mat[4L*j+i]);
01381 *tmp = 0;
01382 for (int k=0; k<3; k++) {
01383 *tmp += b[k][i] * a[k][j];
01384 }
01385 }
01386 }
01387
01388
01389
01390 float *um = U.mat;
01391 float det =
01392 um[0]*(um[4+1]*um[8+2] - um[4+2]*um[8+1]) -
01393 um[1]*(um[4+0]*um[8+2] - um[4+2]*um[8+0]) +
01394 um[2]*(um[4+0]*um[8+1] - um[4+1]*um[8+0]);
01395 if (det < 0) {
01396 for (int q=0; q<3; q++) um[8+q] = -um[8+q];
01397 }
01398
01399
01400 Matrix4 tx;
01401 tx.translate(-comx[0], -comx[1], -comx[2]);
01402 Matrix4 ty;
01403 ty.translate(comy[0], comy[1], comy[2]);
01404
01405 ty.multmatrix(U);
01406 ty.multmatrix(tx);
01407 memcpy(mat->mat, ty.mat, 16L*sizeof(float));
01408 return MEASURE_NOERR;
01409 }
01410
01411
01412
01413
01414 #define NPTS 500
01415
01416 extern int measure_sasa_perresidue(const AtomSel *sel, const float *framepos,
01417 const float *radius, float srad, float *sasa,
01418 ResizeArray<float> *sasapts, const AtomSel *restrictsel,
01419 const int *nsamples, int *rescount,MoleculeList *mlist) {
01420
01421
01422 if (!sel) return MEASURE_ERR_NOSEL;
01423 if (!sel->selected) {
01424 *sasa = 0;
01425 return MEASURE_NOERR;
01426 }
01427 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
01428 if (!radius) return MEASURE_ERR_NORADII;
01429 if (restrictsel && restrictsel->num_atoms != sel->num_atoms)
01430 return MEASURE_ERR_MISMATCHEDCNT;
01431
01432 Molecule *mol = mlist->mol_from_id(sel->molid());
01433 int residue = mol->atom(sel->firstsel)->uniq_resid;
01434 if (restrictsel)
01435 residue = mol->atom(restrictsel->firstsel)->uniq_resid;
01436 *rescount = 0;
01437
01438
01439
01440 if (!restrictsel)
01441 restrictsel = sel;
01442
01443 int i;
01444 int npts = nsamples ? *nsamples : NPTS;
01445 float maxrad = -1;
01446
01447 #if 0
01448
01449 mol->get_radii_minmax(minrad, maxrad);
01450 #endif
01451
01452
01453 for (i=0; i<sel->num_atoms; i++) {
01454 float rad = radius[i];
01455 if (maxrad < rad) maxrad = rad;
01456 }
01457
01458
01459
01460 ResizeArray<int> *pairlist = new ResizeArray<int>[sel->num_atoms];
01461 {
01462 GridSearchPair *pairs;
01463 pairs = vmd_gridsearch1(framepos, sel->num_atoms, sel->on,
01464 2.0f * (maxrad + srad), 0, sel->num_atoms * 1000);
01465
01466 GridSearchPair *p, *tmp;
01467 for (p = pairs; p != NULL; p = tmp) {
01468 int ind1=p->ind1;
01469 int ind2=p->ind2;
01470 pairlist[ind1].append(ind2);
01471 pairlist[ind2].append(ind1);
01472 tmp = p->next;
01473 free(p);
01474 }
01475 }
01476
01477 static const float RAND_MAX_INV = 1.0f/float(VMD_RAND_MAX);
01478
01479
01480
01481
01482 vmd_srandom(38572111);
01483
01484
01485 float *spherepts = new float[3L*npts];
01486 for (i=0; i<npts; i++) {
01487 float u1 = (float) vmd_random();
01488 float u2 = (float) vmd_random();
01489 float z = 2.0f*u1*RAND_MAX_INV -1.0f;
01490 float phi = (float) (2.0f*VMD_PI*u2*RAND_MAX_INV);
01491 float R = sqrtf(1.0f-z*z);
01492 float sphi, cphi;
01493 sincosf(phi, &sphi, &cphi);
01494 spherepts[3L*i ] = R*cphi;
01495 spherepts[3L*i+1] = R*sphi;
01496 spherepts[3L*i+2] = z;
01497 }
01498
01499 const float prefac = (float) (4 * VMD_PI / npts);
01500 float totarea = 0.0f;
01501
01502 for (i=sel->firstsel; i<=sel->lastsel; i++) {
01503 if (sel->on[i]) {
01504
01505 if (restrictsel && !restrictsel->on[i]) continue;
01506 if (residue != mol->atom(i)->uniq_resid) {
01507
01508 sasa[*rescount] = totarea;
01509 totarea = 0.0f;
01510 (*rescount)++;
01511 residue = mol->atom(i)->uniq_resid;
01512 }
01513
01514 const float *loc = framepos+3L*i;
01515 float rad = radius[i]+srad;
01516 float surfpos[3];
01517 int surfpts = npts;
01518 const ResizeArray<int> &nbrs = pairlist[i];
01519 for (int j=0; j<npts; j++) {
01520 surfpos[0] = loc[0] + rad*spherepts[3L*j ];
01521 surfpos[1] = loc[1] + rad*spherepts[3L*j+1];
01522 surfpos[2] = loc[2] + rad*spherepts[3L*j+2];
01523 int on = 1;
01524 for (int k=0; k<nbrs.num(); k++) {
01525 int ind = nbrs[k];
01526 const float *nbrloc = framepos+3L*ind;
01527 float radsq = radius[ind]+srad; radsq *= radsq;
01528 float dx = surfpos[0]-nbrloc[0];
01529 float dy = surfpos[1]-nbrloc[1];
01530 float dz = surfpos[2]-nbrloc[2];
01531 if (dx*dx + dy*dy + dz*dz <= radsq) {
01532 on = 0;
01533 break;
01534 }
01535 }
01536 if (on) {
01537 if (sasapts) {
01538 sasapts->append3(&surfpos[0]);
01539 }
01540 } else {
01541 surfpts--;
01542 }
01543 }
01544 float atomarea = prefac * rad * rad * surfpts;
01545 totarea += atomarea;
01546 }
01547 }
01548
01549 delete [] pairlist;
01550 delete [] spherepts;
01551 sasa[*rescount] = totarea;
01552 (*rescount)++;
01553 return 0;
01554 }
01555
01556 extern int measure_sasa(const AtomSel *sel, const float *framepos,
01557 const float *radius, float srad, float *sasa,
01558 ResizeArray<float> *sasapts, const AtomSel *restrictsel,
01559 const int *nsamples) {
01560
01561
01562 if (!sel) return MEASURE_ERR_NOSEL;
01563 if (!sel->selected) {
01564 *sasa = 0;
01565 return MEASURE_NOERR;
01566 }
01567 if (!framepos) return MEASURE_ERR_NOFRAMEPOS;
01568 if (!radius) return MEASURE_ERR_NORADII;
01569 if (restrictsel && restrictsel->num_atoms != sel->num_atoms)
01570 return MEASURE_ERR_MISMATCHEDCNT;
01571
01572 int i;
01573 int npts = nsamples ? *nsamples : NPTS;
01574 float maxrad = -1;
01575
01576 #if 0
01577
01578 mol->get_radii_minmax(minrad, maxrad);
01579 #endif
01580
01581
01582 for (i=0; i<sel->num_atoms; i++) {
01583 float rad = radius[i];
01584 if (maxrad < rad) maxrad = rad;
01585 }
01586
01587
01588
01589 ResizeArray<int> *pairlist = new ResizeArray<int>[sel->num_atoms];
01590 {
01591 GridSearchPair *pairs;
01592 pairs = vmd_gridsearch1(framepos, sel->num_atoms, sel->on,
01593 2.0f * (maxrad + srad), 0, sel->num_atoms * 1000);
01594
01595 GridSearchPair *p, *tmp;
01596 for (p = pairs; p != NULL; p = tmp) {
01597 int ind1=p->ind1;
01598 int ind2=p->ind2;
01599 pairlist[ind1].append(ind2);
01600 pairlist[ind2].append(ind1);
01601 tmp = p->next;
01602 free(p);
01603 }
01604 }
01605
01606 static const float RAND_MAX_INV = 1.0f/float(VMD_RAND_MAX);
01607
01608
01609
01610
01611 vmd_srandom(38572111);
01612
01613
01614 float *spherepts = new float[3L*npts];
01615 for (i=0; i<npts; i++) {
01616 float u1 = (float) vmd_random();
01617 float u2 = (float) vmd_random();
01618 float z = 2.0f*u1*RAND_MAX_INV -1.0f;
01619 float phi = (float) (2.0f*VMD_PI*u2*RAND_MAX_INV);
01620 float R = sqrtf(1.0f-z*z);
01621 float sphi, cphi;
01622 sincosf(phi, &sphi, &cphi);
01623 spherepts[3L*i ] = R*cphi;
01624 spherepts[3L*i+1] = R*sphi;
01625 spherepts[3L*i+2] = z;
01626 }
01627
01628 const float prefac = (float) (4 * VMD_PI / npts);
01629 float totarea = 0.0f;
01630
01631 for (i=sel->firstsel; i<=sel->lastsel; i++) {
01632 if (sel->on[i]) {
01633
01634 if (restrictsel && !restrictsel->on[i]) continue;
01635 const float *loc = framepos+3L*i;
01636 float rad = radius[i]+srad;
01637 float surfpos[3];
01638 int surfpts = npts;
01639 const ResizeArray<int> &nbrs = pairlist[i];
01640 for (int j=0; j<npts; j++) {
01641 surfpos[0] = loc[0] + rad*spherepts[3L*j ];
01642 surfpos[1] = loc[1] + rad*spherepts[3L*j+1];
01643 surfpos[2] = loc[2] + rad*spherepts[3L*j+2];
01644 int on = 1;
01645 for (int k=0; k<nbrs.num(); k++) {
01646 int ind = nbrs[k];
01647 const float *nbrloc = framepos+3L*ind;
01648 float radsq = radius[ind]+srad; radsq *= radsq;
01649 float dx = surfpos[0]-nbrloc[0];
01650 float dy = surfpos[1]-nbrloc[1];
01651 float dz = surfpos[2]-nbrloc[2];
01652 if (dx*dx + dy*dy + dz*dz <= radsq) {
01653 on = 0;
01654 break;
01655 }
01656 }
01657 if (on) {
01658 if (sasapts) {
01659 sasapts->append3(&surfpos[0]);
01660 }
01661 } else {
01662 surfpts--;
01663 }
01664 }
01665 float atomarea = prefac * rad * rad * surfpts;
01666 totarea += atomarea;
01667 }
01668 }
01669
01670 delete [] pairlist;
01671 delete [] spherepts;
01672 *sasa = totarea;
01673 return 0;
01674 }
01675
01676
01677
01678 #if 1
01679
01680
01681
01682 typedef struct {
01683 MoleculeList *mlist;
01684 const AtomSel **sellist;
01685 int numsels;
01686 float srad;
01687 float *sasalist;
01688 int nsamples;
01689 float *spherepts;
01690 } sasathreadparms;
01691
01692
01693
01694
01695 static void * measure_sasa_thread(void *voidparms) {
01696 int threadid;
01697 sasathreadparms *parms = NULL;
01698 wkf_threadlaunch_getdata(voidparms, (void **) &parms);
01699 wkf_threadlaunch_getid(voidparms, &threadid, NULL);
01700 #if defined(DEBUGSASATHR)
01701 printf("sasathread[%d] running...\n", threadid);
01702 #endif
01703
01704
01705
01706
01707 MoleculeList *mlist = parms->mlist;
01708 const AtomSel **sellist = parms->sellist;
01709
01710 float srad = parms->srad;
01711 float *sasalist = parms->sasalist;
01712 const int npts = parms->nsamples;
01713 float *spherepts = parms->spherepts;
01714
01715 int i, selidx;
01716 wkf_tasktile_t tile;
01717 while (wkf_threadlaunch_next_tile(voidparms, 1, &tile) != WKF_SCHED_DONE) {
01718 #if defined(DEBUGSASATHR)
01719 printf("sasathread[%d] running idx %d to %d\n", threadid, tile.start, tile.end);
01720 #endif
01721 for (selidx=tile.start; selidx<tile.end; selidx++) {
01722 const AtomSel *sel = sellist[selidx];
01723 Molecule *mol = mlist->mol_from_id(sel->molid());
01724
01725 if (!sel->selected) {
01726 sasalist[selidx] = 0;
01727 continue;
01728 }
01729
01730 const float *framepos = sel->coordinates(mlist);
01731 if (!framepos) {
01732 #if defined(DEBUGSASATHR)
01733 printf("measure_sasalist: failed to get coords!!!\n");
01734 #endif
01735 return NULL;
01736 }
01737
01738 const float *radius = mol->extraflt.data("radius");
01739 if (!radius) {
01740 #if defined(DEBUGSASATHR)
01741 printf("measure_sasalist: failed to get radii!!!\n");
01742 #endif
01743 return NULL;
01744 }
01745
01746
01747 float minrad=-1, maxrad=-1;
01748 #if 1
01749
01750 mol->get_radii_minmax(minrad, maxrad);
01751 #else
01752
01753 for (i=0; i<sel->num_atoms; i++) {
01754 float rad = radius[i];
01755 if (maxrad < rad) maxrad = rad;
01756 }
01757 #endif
01758
01759
01760
01761 ResizeArray<int> *pairlist = new ResizeArray<int>[sel->num_atoms];
01762 {
01763 GridSearchPair *pairs;
01764 pairs = vmd_gridsearch1(framepos, sel->num_atoms, sel->on,
01765 2.0f * (maxrad + srad), 0,
01766 sel->num_atoms * 1000);
01767
01768 GridSearchPair *p, *tmp;
01769 for (p = pairs; p != NULL; p = tmp) {
01770 int ind1=p->ind1;
01771 int ind2=p->ind2;
01772 pairlist[ind1].append(ind2);
01773 pairlist[ind2].append(ind1);
01774 tmp = p->next;
01775 free(p);
01776 }
01777 }
01778
01779 const float prefac = (float) (4 * VMD_PI / npts);
01780 float totarea = 0.0f;
01781
01782 for (i=sel->firstsel; i<=sel->lastsel; i++) {
01783 if (sel->on[i]) {
01784 const float *loc = framepos+3L*i;
01785 float rad = radius[i]+srad;
01786 float surfpos[3];
01787 int surfpts = npts;
01788 const ResizeArray<int> &nbrs = pairlist[i];
01789 for (int j=0; j<npts; j++) {
01790 surfpos[0] = loc[0] + rad*spherepts[3L*j ];
01791 surfpos[1] = loc[1] + rad*spherepts[3L*j+1];
01792 surfpos[2] = loc[2] + rad*spherepts[3L*j+2];
01793 int on = 1;
01794 for (int k=0; k<nbrs.num(); k++) {
01795 int ind = nbrs[k];
01796 const float *nbrloc = framepos+3L*ind;
01797 float radsq = radius[ind]+srad; radsq *= radsq;
01798 float dx = surfpos[0]-nbrloc[0];
01799 float dy = surfpos[1]-nbrloc[1];
01800 float dz = surfpos[2]-nbrloc[2];
01801 if (dx*dx + dy*dy + dz*dz <= radsq) {
01802 on = 0;
01803 break;
01804 }
01805 }
01806 if (!on) {
01807 surfpts--;
01808 }
01809 }
01810 float atomarea = prefac * rad * rad * surfpts;
01811 totarea += atomarea;
01812 }
01813 }
01814
01815 delete [] pairlist;
01816 sasalist[selidx] = totarea;
01817 }
01818 }
01819
01820 return NULL;
01821 }
01822
01823 #if 1
01824
01825
01826
01827
01828 extern int measure_sasalist(MoleculeList *mlist,
01829 const AtomSel **sellist, int numsels,
01830 float srad, float *sasalist, const int *nsamples) {
01831
01832
01833 if (!sellist) return MEASURE_ERR_NOSEL;
01834
01835 int i, rc;
01836 int npts = nsamples ? *nsamples : NPTS;
01837
01838 #if defined(VMDTHREADS)
01839 int numprocs = wkf_thread_numprocessors();
01840 #else
01841 int numprocs = 1;
01842 #endif
01843
01844 #if defined(DEBUGSASATHR)
01845 printf("sasaprocs: %d\n", numprocs);
01846 #endif
01847
01848 static const float RAND_MAX_INV = 1.0f/float(VMD_RAND_MAX);
01849
01850
01851
01852
01853
01854 vmd_srandom(38572111);
01855
01856
01857 float *spherepts = new float[3L*npts];
01858 for (i=0; i<npts; i++) {
01859 float u1 = (float) vmd_random();
01860 float u2 = (float) vmd_random();
01861 float z = 2.0f*u1*RAND_MAX_INV -1.0f;
01862 float phi = (float) (2.0f*VMD_PI*u2*RAND_MAX_INV);
01863 float R = sqrtf(1.0f-z*z);
01864 float sphi, cphi;
01865 sincosf(phi, &sphi, &cphi);
01866 spherepts[3L*i ] = R*cphi;
01867 spherepts[3L*i+1] = R*sphi;
01868 spherepts[3L*i+2] = z;
01869 }
01870
01871 sasathreadparms parms;
01872 parms.mlist = mlist;
01873 parms.sellist = sellist;
01874 parms.numsels = numsels;
01875 parms.srad = srad;
01876 parms.sasalist = sasalist;
01877 parms.nsamples = npts;
01878 parms.spherepts = spherepts;
01879
01880
01881
01882 wkf_tasktile_t tile;
01883 tile.start=0;
01884 tile.end=numsels;
01885 rc = wkf_threadlaunch(numprocs, &parms, measure_sasa_thread, &tile);
01886
01887 delete [] spherepts;
01888
01889 return rc;
01890 }
01891
01892
01893 #else
01894
01895
01896
01897
01898 extern int measure_sasalist(MoleculeList *mlist,
01899 const AtomSel **sellist, int numsels,
01900 float srad, float *sasalist, const int *nsamples) {
01901
01902
01903 if (!sellist) return MEASURE_ERR_NOSEL;
01904
01905 int i;
01906 int npts = nsamples ? *nsamples : NPTS;
01907
01908 int selidx;
01909 for (selidx=0; selidx<numsels; selidx++) {
01910 const AtomSel *sel = sellist[selidx];
01911 Molecule *mol = mlist->mol_from_id(sel->molid());
01912
01913 if (!sel->selected) {
01914 sasalist[selidx] = 0;
01915 continue;
01916 }
01917
01918 const float *framepos = sel->coordinates(mlist);
01919 if (!framepos) {
01920 #if defined(DEBUGSASATHR)
01921 printf("measure_sasalist: failed to get coords!!!\n");
01922 #endif
01923 return MEASURE_ERR_NOFRAMEPOS;
01924 }
01925
01926 const float *radius = mol->extraflt.data("radius");
01927 if (!radius) {
01928 #if defined(DEBUGSASATHR)
01929 printf("measure_sasalist: failed to get radii!!!\n");
01930 #endif
01931 return MEASURE_ERR_NORADII;
01932 }
01933
01934 float minrad=-1, maxrad=-1;
01935 #if 1
01936
01937 mol->get_radii_minmax(minrad, maxrad);
01938 #else
01939
01940 for (i=0; i<sel->num_atoms; i++) {
01941 float rad = radius[i];
01942 if (maxrad < rad) maxrad = rad;
01943 }
01944 #endif
01945
01946
01947
01948 ResizeArray<int> *pairlist = new ResizeArray<int>[sel->num_atoms];
01949 {
01950 GridSearchPair *pairs;
01951 pairs = vmd_gridsearch1(framepos, sel->num_atoms, sel->on,
01952 2.0f * (maxrad + srad), 0, sel->num_atoms * 1000);
01953
01954 GridSearchPair *p, *tmp;
01955 for (p = pairs; p != NULL; p = tmp) {
01956 int ind1=p->ind1;
01957 int ind2=p->ind2;
01958 pairlist[ind1].append(ind2);
01959 pairlist[ind2].append(ind1);
01960 tmp = p->next;
01961 free(p);
01962 }
01963 }
01964
01965 static const float RAND_MAX_INV = 1.0f/VMD_RAND_MAX;
01966
01967
01968
01969
01970 vmd_srandom(38572111);
01971
01972
01973 float *spherepts = new float[3L*npts];
01974 for (i=0; i<npts; i++) {
01975 float u1 = (float) vmd_random();
01976 float u2 = (float) vmd_random();
01977 float z = 2.0f*u1*RAND_MAX_INV -1.0f;
01978 float phi = (float) (2.0f*VMD_PI*u2*RAND_MAX_INV);
01979 float R = sqrtf(1.0f-z*z);
01980 float sphi, cphi;
01981 sincosf(phi, &sphi, &cphi);
01982 spherepts[3L*i ] = R*cphi;
01983 spherepts[3L*i+1] = R*sphi;
01984 spherepts[3L*i+2] = z;
01985 }
01986
01987 const float prefac = (float) (4 * VMD_PI / npts);
01988 float totarea = 0.0f;
01989
01990 for (i=sel->firstsel; i<=sel->lastsel; i++) {
01991 if (sel->on[i]) {
01992 const float *loc = framepos+3L*i;
01993 float rad = radius[i]+srad;
01994 float surfpos[3];
01995 int surfpts = npts;
01996 const ResizeArray<int> &nbrs = pairlist[i];
01997 for (int j=0; j<npts; j++) {
01998 surfpos[0] = loc[0] + rad*spherepts[3L*j ];
01999 surfpos[1] = loc[1] + rad*spherepts[3L*j+1];
02000 surfpos[2] = loc[2] + rad*spherepts[3L*j+2];
02001 int on = 1;
02002 for (int k=0; k<nbrs.num(); k++) {
02003 int ind = nbrs[k];
02004 const float *nbrloc = framepos+3L*ind;
02005 float radsq = radius[ind]+srad; radsq *= radsq;
02006 float dx = surfpos[0]-nbrloc[0];
02007 float dy = surfpos[1]-nbrloc[1];
02008 float dz = surfpos[2]-nbrloc[2];
02009 if (dx*dx + dy*dy + dz*dz <= radsq) {
02010 on = 0;
02011 break;
02012 }
02013 }
02014 if (!on) {
02015 surfpts--;
02016 }
02017 }
02018 float atomarea = prefac * rad * rad * surfpts;
02019 totarea += atomarea;
02020 }
02021 }
02022
02023 delete [] pairlist;
02024 delete [] spherepts;
02025 sasalist[selidx] = totarea;
02026 }
02027
02028 return 0;
02029 }
02030
02031 #endif
02032 #endif
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042 static float fix_pbc_n_sqr(float delta, const float boxby2) {
02043 while (delta >= boxby2) { delta -= 2.0f * boxby2; }
02044 while (delta < -boxby2) { delta += 2.0f * boxby2; }
02045 return delta * delta;
02046 }
02047
02048
02049
02050 static float min_dist_with_pbc(const float *a, const float *b,
02051 const float *boxby2) {
02052 float distsqr;
02053 distsqr = fix_pbc_n_sqr(a[0] - b[0], boxby2[0]);
02054 distsqr += fix_pbc_n_sqr(a[1] - b[1], boxby2[1]);
02055 distsqr += fix_pbc_n_sqr(a[2] - b[2], boxby2[2]);
02056 return sqrtf(distsqr);
02057 }
02058
02063 static inline double spherical_cap(const double &radius, const double &boxby2) {
02064 return (VMD_PI / 3.0 * (radius - boxby2) * (radius - boxby2)
02065 * ( 2.0 * radius + boxby2));
02066 }
02067
02068
02069 typedef struct {
02070 int threadid;
02071 int threadcount;
02072 int count_o_start;
02073 int count_o_end;
02074 const float *olist;
02075 int count_i;
02076 const float *ilist;
02077 int count_h;
02078 int *hlist;
02079 float delta;
02080 const float *boxby2;
02081 wkfmsgtimer *msgtp;
02082 int curframe;
02083 int maxframe;
02084 } gofrparms_t;
02085
02086
02087
02088
02089
02090
02091
02092
02093 extern "C" void * measure_gofr_orth(void *voidparms) {
02094
02095 gofrparms_t *parms = (gofrparms_t *) voidparms;
02096 const int count_o_start = parms->count_o_start;
02097 const int count_o_end = parms->count_o_end;
02098 const int count_i = parms->count_i;
02099 const int count_h = parms->count_h;
02100 const float *olist = parms->olist;
02101 const float *ilist = parms->ilist;
02102 const float *boxby2 = parms->boxby2;
02103 wkfmsgtimer *msgtp = parms->msgtp;
02104 const int curframe = parms->curframe;
02105 const int maxframe = parms->maxframe;
02106 int *hlist = parms->hlist;
02107
02108 int i, j, idx;
02109 float dist;
02110 const float deltascale = 1.0f / parms->delta;
02111 int msgcnt=0;
02112
02113
02114 for (i=count_o_start; i<count_o_end; ++i) {
02115
02116
02117
02118 if (msgtp && wkf_msg_timer_timeout(msgtp)) {
02119 char tmpbuf[1024];
02120 if (msgcnt==0)
02121 sprintf(tmpbuf, "timestep %d of %d", curframe, maxframe);
02122 else
02123 sprintf(tmpbuf, "timestep %d of %d: (%6.2f %% complete)", curframe, maxframe,
02124 (100.0f * i) / (float) (count_o_end - count_o_start + 1));
02125 msgInfo << "vmd_measure_gofr_orth: " << tmpbuf << sendmsg;
02126 msgcnt++;
02127
02128 }
02129
02130 for (j=0; j<count_i; ++j) {
02131
02132 dist = min_dist_with_pbc(&olist[i*3L], &ilist[j*3L], boxby2);
02133 idx = (int) (dist * deltascale);
02134 if ((idx >= 0) && (idx < count_h))
02135 ++hlist[idx];
02136 }
02137 }
02138
02139 return MEASURE_NOERR;
02140 }
02141
02142
02143
02144
02145
02146 int measure_gofr(AtomSel *sel1, AtomSel *sel2, MoleculeList *mlist,
02147 const int count_h, double *gofr, double *numint, double *histog,
02148 const float delta, int first, int last, int step, int *framecntr,
02149 int usepbc, int selupdate) {
02150 int i, j, frame;
02151 float a, b, c, alpha, beta, gamma;
02152 int isortho=0;
02153 int duplicates=0;
02154
02155
02156 a=b=c=9999999.0;
02157 alpha=beta=gamma=90.0;
02158
02159
02160 framecntr[0]=framecntr[1]=framecntr[2]=0;
02161
02162
02163
02164 if (!sel1 || !sel2 ) {
02165 return MEASURE_ERR_NOSEL;
02166 }
02167
02168
02169
02170 if (sel2->molid() != sel1->molid()) {
02171 return MEASURE_ERR_MISMATCHEDMOLS;
02172 }
02173
02174 Molecule *mymol = mlist->mol_from_id(sel1->molid());
02175 int maxframe = mymol->numframes() - 1;
02176 int nframes = 0;
02177
02178 if (last == -1)
02179 last = maxframe;
02180
02181 if ((last < first) || (last < 0) || (step <=0) || (first < -1)
02182 || (maxframe < 0) || (last > maxframe)) {
02183 msgErr << "measure gofr: bad frame range given."
02184 << " max. allowed frame#: " << maxframe << sendmsg;
02185 return MEASURE_ERR_BADFRAMERANGE;
02186 }
02187
02188
02189 if (usepbc) {
02190 for (isortho=1, nframes=0, frame=first; frame <=last; ++nframes, frame += step) {
02191 const Timestep *ts;
02192
02193 if (first == -1) {
02194
02195 ts = sel1->timestep(mlist);
02196 frame=last;
02197 } else {
02198 ts = mymol->get_frame(frame);
02199 }
02200
02201 a = ts->a_length;
02202 b = ts->b_length;
02203 c = ts->c_length;
02204 alpha = ts->alpha;
02205 beta = ts->beta;
02206 gamma = ts->gamma;
02207
02208
02209 if (fabsf(a*b*c) < 0.0001) {
02210 msgErr << "measure gofr: unit cell volume is zero." << sendmsg;
02211 return MEASURE_ERR_GENERAL;
02212 }
02213
02214
02215 if ((alpha != 90.0) || (beta != 90.0) || (gamma != 90.0)) {
02216 isortho=0;
02217 }
02218 }
02219 } else {
02220
02221 isortho=1;
02222 a=b=c=9999999.0;
02223 alpha=beta=gamma=90.0;
02224 }
02225
02226
02227 if (!isortho) {
02228 msgErr << "measure gofr: only orthorhombic cells are supported (for now)." << sendmsg;
02229 return MEASURE_ERR_GENERAL;
02230 }
02231
02232
02233 for (i=0; i<count_h; ++i) {
02234 gofr[i] = numint[i] = histog[i] = 0.0;
02235 }
02236
02237
02238
02239
02240 float *sel1coords = new float[3L*sel1->num_atoms];
02241 float *sel2coords = new float[3L*sel2->num_atoms];
02242
02243
02244 wkfmsgtimer *msgt = wkf_msg_timer_create(5);
02245
02246
02247 wkf_thread_t *threads;
02248 gofrparms_t *parms;
02249 #if defined(VMDTHREADS)
02250 int numprocs = wkf_thread_numprocessors();
02251 #else
02252 int numprocs = 1;
02253 #endif
02254
02255 threads = new wkf_thread_t[numprocs];
02256 memset(threads, 0, numprocs * sizeof(wkf_thread_t));
02257
02258
02259 parms = new gofrparms_t[numprocs];
02260 for (i=0; i<numprocs; ++i) {
02261 parms[i].threadid = i;
02262 parms[i].threadcount = numprocs;
02263 parms[i].delta = (float) delta;
02264 parms[i].msgtp = NULL;
02265 parms[i].count_h = count_h;
02266 parms[i].hlist = new int[count_h];
02267 }
02268
02269 msgInfo << "measure gofr: using multi-threaded implementation with "
02270 << numprocs << ((numprocs > 1) ? " CPUs" : " CPU") << sendmsg;
02271
02272 for (nframes=0,frame=first; frame <=last; ++nframes, frame += step) {
02273 const Timestep *ts1, *ts2;
02274
02275 if (frame == -1) {
02276
02277 ts1 = sel1->timestep(mlist);
02278 ts2 = sel2->timestep(mlist);
02279 frame=last;
02280 } else {
02281 sel1->which_frame = frame;
02282 sel2->which_frame = frame;
02283 ts1 = ts2 = mymol->get_frame(frame);
02284 }
02285
02286 if (usepbc) {
02287
02288 a = ts1->a_length;
02289 b = ts1->b_length;
02290 c = ts1->c_length;
02291 alpha = ts1->alpha;
02292 beta = ts1->beta;
02293 gamma = ts1->gamma;
02294 }
02295
02296
02297 float boxby2[3];
02298 boxby2[0] = 0.5f * a;
02299 boxby2[1] = 0.5f * b;
02300 boxby2[2] = 0.5f * c;
02301
02302
02303 if (selupdate) {
02304 if (sel1->change(NULL, mymol) != AtomSel::PARSE_SUCCESS)
02305 msgErr << "measure gofr: failed to evaluate atom selection update";
02306 if (sel2->change(NULL, mymol) != AtomSel::PARSE_SUCCESS)
02307 msgErr << "measure gofr: failed to evaluate atom selection update";
02308 }
02309
02310
02311
02312 if (sel2->molid() == sel1->molid()) {
02313 int i;
02314 for (i=0, duplicates=0; i<sel1->num_atoms; ++i) {
02315 if (sel1->on[i] && sel2->on[i])
02316 ++duplicates;
02317 }
02318 }
02319
02320
02321
02322 const float *framepos = ts1->pos;
02323 for (i=0, j=0; i<sel1->num_atoms; ++i) {
02324 if (sel1->on[i]) {
02325 long a = i*3L;
02326 sel1coords[j ] = framepos[a ];
02327 sel1coords[j + 1] = framepos[a + 1];
02328 sel1coords[j + 2] = framepos[a + 2];
02329 j+=3;
02330 }
02331 }
02332 framepos = ts2->pos;
02333 for (i=0, j=0; i<sel2->num_atoms; ++i) {
02334 if (sel2->on[i]) {
02335 long a = i*3L;
02336 sel2coords[j ] = framepos[a ];
02337 sel2coords[j + 1] = framepos[a + 1];
02338 sel2coords[j + 2] = framepos[a + 2];
02339 j+=3;
02340 }
02341 }
02342
02343
02344
02345 int maxframe = (int) ((last - first + 1) / ((float) step));
02346 for (i=0; i<numprocs; ++i) {
02347 memset(parms[i].hlist, 0, count_h * sizeof(int));
02348 parms[i].boxby2 = boxby2;
02349 parms[i].curframe = frame;
02350 parms[i].maxframe = maxframe;
02351 }
02352 parms[0].msgtp = msgt;
02353
02354 if (isortho && sel1->selected && sel2->selected) {
02355 int count_o = sel1->selected;
02356 int count_i = sel2->selected;
02357 const float *olist = sel1coords;
02358 const float *ilist = sel2coords;
02359
02360
02361 if (count_o < count_i) {
02362 count_o = sel2->selected;
02363 count_i = sel1->selected;
02364 olist = sel2coords;
02365 ilist = sel1coords;
02366 }
02367
02368
02369
02370
02371
02372 int thrdelta = (count_o + (numprocs-1)) / numprocs;
02373 int o_min = 0;
02374 int o_max = thrdelta;
02375 for (i=0; i<numprocs; ++i, o_min += thrdelta, o_max += thrdelta) {
02376 if (o_max > count_o) o_max = count_o;
02377 if (o_min >= count_o) o_max = - 1;
02378 parms[i].count_o_start = o_min;
02379 parms[i].count_o_end = o_max;
02380 parms[i].count_i = count_i;
02381 parms[i].olist = olist;
02382 parms[i].ilist = ilist;
02383 }
02384
02385
02386
02387 #if defined(VMDTHREADS)
02388 for (i=0; i<numprocs; ++i) {
02389 wkf_thread_create(&threads[i], measure_gofr_orth, &parms[i]);
02390 }
02391 for (i=0; i<numprocs; ++i) {
02392 wkf_thread_join(threads[i], NULL);
02393 }
02394 #else
02395 measure_gofr_orth((void *) &parms[0]);
02396 #endif
02397 ++framecntr[2];
02398 } else {
02399 ++framecntr[1];
02400 }
02401 ++framecntr[0];
02402
02403
02404
02405
02406 parms[0].hlist[0] -= duplicates;
02407
02408
02409
02410
02411 int h_max=count_h;
02412 float smallside=a;
02413 if (isortho && usepbc) {
02414 if(b < smallside) {
02415 smallside=b;
02416 }
02417 if(c < smallside) {
02418 smallside=c;
02419 }
02420 h_max=(int) (sqrtf(0.5f)*smallside/delta) +1;
02421 if (h_max > count_h) {
02422 h_max=count_h;
02423 }
02424 }
02425
02426 double all=0.0;
02427 double pair_dens = 0.0;
02428 if (sel1->selected && sel2->selected) {
02429 if (usepbc) {
02430 pair_dens = a * b * c / ((double)sel1->selected * (double)sel2->selected - (double)duplicates);
02431 } else {
02432 pair_dens = 30.0 * (double)sel1->selected /
02433 ((double)sel1->selected * (double)sel2->selected - (double)duplicates);
02434 }
02435 }
02436
02437
02438 for (i=0; i<h_max; ++i) {
02439
02440 double r_in = delta * (double)i;
02441 double r_out = delta * (double)(i+1);
02442 double slice_vol = 4.0 / 3.0 * VMD_PI
02443 * ((r_out * r_out * r_out) - (r_in * r_in * r_in));
02444
02445 if (isortho && usepbc) {
02446
02447 if (r_out > boxby2[0]) {
02448 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[0]);
02449 }
02450 if (r_out > boxby2[1]) {
02451 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[1]);
02452 }
02453 if (r_out > boxby2[2]) {
02454 slice_vol -= 2.0 * spherical_cap(r_out, boxby2[2]);
02455 }
02456 if (r_in > boxby2[0]) {
02457 slice_vol += 2.0 * spherical_cap(r_in, boxby2[0]);
02458 }
02459 if (r_in > boxby2[1]) {
02460 slice_vol += 2.0 * spherical_cap(r_in, boxby2[1]);
02461 }
02462 if (r_in > boxby2[2]) {
02463 slice_vol += 2.0 * spherical_cap(r_in, boxby2[2]);
02464 }
02465 }
02466
02467 double normf = pair_dens / slice_vol;
02468 double histv = 0.0;
02469 for (j=0; j<numprocs; ++j) {
02470 histv += (double) parms[j].hlist[i];
02471 }
02472 gofr[i] += normf * histv;
02473 all += histv;
02474 if (sel1->selected) {
02475 numint[i] += all / (double)(sel1->selected);
02476 }
02477 histog[i] += histv;
02478 }
02479 }
02480 delete [] sel1coords;
02481 delete [] sel2coords;
02482
02483 double norm = 1.0 / (double) nframes;
02484 for (i=0; i<count_h; ++i) {
02485 gofr[i] *= norm;
02486 numint[i] *= norm;
02487 histog[i] *= norm;
02488 }
02489 wkf_msg_timer_destroy(msgt);
02490
02491
02492 for (i=0; i<numprocs; ++i) {
02493 delete [] parms[i].hlist;
02494 }
02495 delete [] threads;
02496 delete [] parms;
02497
02498 return MEASURE_NOERR;
02499 }
02500
02501
02502 int measure_geom(MoleculeList *mlist, int *molid, int *atmid, ResizeArray<float> *gValues,
02503 int frame, int first, int last, int defmolid, int geomtype) {
02504 int i, ret_val;
02505 for(i=0; i < geomtype; i++) {
02506
02507 if(i > 0 && molid[i-1]==molid[i] && atmid[i-1]==atmid[i]) {
02508 printf("measure_geom: %i/%i %i/%i\n", molid[i-1],atmid[i-1],molid[i],atmid[i]);
02509 return MEASURE_ERR_REPEATEDATOM;
02510 }
02511 }
02512
02513 float value;
02514 int max_ts, orig_ts;
02515
02516
02517 Molecule *mol = mlist->mol_from_id(defmolid);
02518 if( !mol )
02519 return MEASURE_ERR_NOMOLECULE;
02520
02521
02522 if((orig_ts = mol->frame()) < 0)
02523 return MEASURE_ERR_NOFRAMES;
02524
02525
02526 max_ts = mol->numframes()-1;
02527 if (frame<0) {
02528 if (first<0 && last<0) first = last = orig_ts;
02529 if (last<0 || last>max_ts) last = max_ts;
02530 if (first<0) first = 0;
02531 } else {
02532 if (frame>max_ts) frame = max_ts;
02533 first = last = frame;
02534 }
02535
02536
02537 for(i=first; i <= last; i++) {
02538 mol->override_current_frame(i);
02539 switch (geomtype) {
02540 case MEASURE_BOND:
02541 if ((ret_val=calculate_bond(mlist, molid, atmid, &value))<0)
02542 return ret_val;
02543 gValues->append(value);
02544 break;
02545 case MEASURE_ANGLE:
02546 if ((ret_val=calculate_angle(mlist, molid, atmid, &value))<0)
02547 return ret_val;
02548 gValues->append(value);
02549 break;
02550 case MEASURE_DIHED:
02551 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
02552 return ret_val;
02553 gValues->append(value);
02554 break;
02555 }
02556 }
02557
02558
02559 mol->override_current_frame(orig_ts);
02560
02561 return MEASURE_NOERR;
02562 }
02563
02564
02565
02566 int calculate_bond(MoleculeList *mlist, int *molid, int *atmid, float *value) {
02567
02568
02569 int ret_val;
02570 float pos1[3], pos2[3];
02571 if ((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
02572 return ret_val;
02573 if ((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
02574 return ret_val;
02575
02576 vec_sub(pos2, pos2, pos1);
02577 *value = norm(pos2);
02578
02579 return MEASURE_NOERR;
02580 }
02581
02582
02583 int calculate_angle(MoleculeList *mlist, int *molid, int *atmid, float *value) {
02584
02585
02586 int ret_val;
02587 float pos1[3], pos2[3], pos3[3], r1[3], r2[3];
02588 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
02589 return ret_val;
02590 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
02591 return ret_val;
02592 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[2]), atmid[2], pos3))<0)
02593 return ret_val;
02594
02595 vec_sub(r1, pos1, pos2);
02596 vec_sub(r2, pos3, pos2);
02597 *value = angle(r1, r2);
02598
02599 return MEASURE_NOERR;
02600 }
02601
02602
02603 int calculate_dihed(MoleculeList *mlist, int *molid, int *atmid, float *value) {
02604
02605
02606 int ret_val;
02607 float pos1[3], pos2[3], pos3[3], pos4[3];
02608 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[0]), atmid[0], pos1))<0)
02609 return ret_val;
02610 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[1]), atmid[1], pos2))<0)
02611 return ret_val;
02612 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[2]), atmid[2], pos3))<0)
02613 return ret_val;
02614 if((ret_val=normal_atom_coord(mlist->mol_from_id(molid[3]), atmid[3], pos4))<0)
02615 return ret_val;
02616
02617 *value = dihedral(pos1, pos2, pos3, pos4);
02618
02619 return MEASURE_NOERR;
02620 }
02621
02622
02623
02624
02625 int normal_atom_coord(Molecule *mol, int a, float *pos) {
02626 Timestep *now;
02627
02628 int cell[3];
02629 memset(cell, 0, 3L*sizeof(int));
02630
02631
02632 int ret_val = check_mol(mol, a);
02633 if (ret_val<0)
02634 return ret_val;
02635
02636 if ((now = mol->current())) {
02637 memcpy((void *)pos, (void *)(now->pos + 3L*a), 3L*sizeof(float));
02638
02639
02640 Matrix4 mat;
02641 now->get_transform_from_cell(cell, mat);
02642 mat.multpoint3d(pos, pos);
02643
02644 return MEASURE_NOERR;
02645 }
02646
02647
02648 return MEASURE_ERR_NOFRAMES;
02649 }
02650
02651
02652
02653
02654 int check_mol(Molecule *mol, int a) {
02655
02656 if (!mol)
02657 return MEASURE_ERR_NOMOLECULE;
02658 if (a < 0 || a >= mol->nAtoms)
02659 return MEASURE_ERR_BADATOMID;
02660
02661 return MEASURE_NOERR;
02662 }
02663
02664
02665 int measure_energy(MoleculeList *mlist, int *molid, int *atmid, int natoms, ResizeArray<float> *gValues,
02666 int frame, int first, int last, int defmolid, double *params, int geomtype) {
02667 int i, ret_val;
02668 for(i=0; i < natoms; i++) {
02669
02670 if(i > 0 && molid[i-1]==molid[i] && atmid[i-1]==atmid[i]) {
02671 printf("measure_energy: %i/%i %i/%i\n", molid[i-1],atmid[i-1],molid[i],atmid[i]);
02672 return MEASURE_ERR_REPEATEDATOM;
02673 }
02674 }
02675
02676 float value;
02677 int max_ts, orig_ts;
02678
02679
02680 Molecule *mol = mlist->mol_from_id(defmolid);
02681 if( !mol )
02682 return MEASURE_ERR_NOMOLECULE;
02683
02684
02685 if((orig_ts = mol->frame()) < 0)
02686 return MEASURE_ERR_NOFRAMES;
02687
02688
02689 max_ts = mol->numframes()-1;
02690 if (frame==-1) {
02691 if (first<0 && last<0) first = last = orig_ts;
02692 if (last<0 || last>max_ts) last = max_ts;
02693 if (first<0) first = 0;
02694 } else {
02695 if (frame>max_ts || frame==-2) frame = max_ts;
02696 first = last = frame;
02697 }
02698
02699
02700 for(i=first; i <= last; i++) {
02701 mol->override_current_frame(i);
02702 switch (geomtype) {
02703 case MEASURE_BOND:
02704 if ((ret_val=compute_bond_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1]))<0)
02705 return ret_val;
02706 gValues->append(value);
02707 break;
02708 case MEASURE_ANGLE:
02709 if ((ret_val=compute_angle_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1], (float) params[2], (float) params[3]))<0)
02710 return ret_val;
02711 gValues->append(value);
02712 break;
02713 case MEASURE_DIHED:
02714 if ((ret_val=compute_dihed_energy(mlist, molid, atmid, &value, (float) params[0], int(params[1]), (float) params[2]))<0)
02715 return ret_val;
02716 gValues->append(value);
02717 break;
02718 case MEASURE_IMPRP:
02719 if ((ret_val=compute_imprp_energy(mlist, molid, atmid, &value, (float) params[0], (float) params[1]))<0)
02720 return ret_val;
02721 gValues->append(value);
02722 break;
02723 case MEASURE_VDW:
02724 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)
02725 return ret_val;
02726 gValues->append(value);
02727 break;
02728 case MEASURE_ELECT:
02729 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)
02730 return ret_val;
02731 gValues->append(value);
02732 break;
02733 }
02734 }
02735
02736
02737 mol->override_current_frame(orig_ts);
02738
02739 return MEASURE_NOERR;
02740 }
02741
02742
02743 int compute_bond_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float k, float x0) {
02744 int ret_val;
02745 float dist;
02746
02747
02748 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
02749 return ret_val;
02750 float x = dist-x0;
02751 *energy = k*x*x;
02752
02753 return MEASURE_NOERR;
02754 }
02755
02756
02757 int compute_angle_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
02758 float k, float x0, float kub, float s0) {
02759 int ret_val;
02760 float value;
02761
02762
02763 if ((ret_val=calculate_angle(mlist, molid, atmid, &value))<0)
02764 return ret_val;
02765 float x = (float) DEGTORAD((value-x0));
02766 float s = 0.0f;
02767
02768 if (kub>0.0f) {
02769 int twoatoms[2];
02770 twoatoms[0] = atmid[0];
02771 twoatoms[1] = atmid[2];
02772 if ((ret_val=calculate_bond(mlist, molid, twoatoms, &value))<0)
02773 return ret_val;
02774 s = value-s0;
02775 }
02776
02777 *energy = k*x*x + kub*s*s;
02778
02779 return MEASURE_NOERR;
02780 }
02781
02782
02783 int compute_dihed_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
02784 float k, int n, float delta) {
02785 int ret_val;
02786 float value;
02787
02788
02789 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
02790 return ret_val;
02791 *energy = k*(1+cosf((float) (DEGTORAD((n*value-delta)))));
02792
02793 return MEASURE_NOERR;
02794 }
02795
02796
02797 int compute_imprp_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy,
02798 float k, float x0) {
02799 int ret_val;
02800 float value;
02801
02802
02803 if ((ret_val=calculate_dihed(mlist, molid, atmid, &value))<0)
02804 return ret_val;
02805 float x = (float) (DEGTORAD((value-x0)));
02806 *energy = k*x*x;
02807
02808 return MEASURE_NOERR;
02809 }
02810
02811
02812
02813
02814
02815 int compute_vdw_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float eps1, float rmin1,
02816 float eps2, float rmin2, float cutoff, float switchdist) {
02817 int ret_val;
02818 float dist;
02819
02820
02821 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
02822 return ret_val;
02823
02824 float sw=1.0;
02825 if (switchdist>0.0 && cutoff>0.0) {
02826 if (dist>=cutoff) {
02827 sw = 0.0;
02828 } else if (dist>=switchdist) {
02829
02830 float dist2 = dist*dist;
02831 float cut2 = cutoff*cutoff;
02832 float switch2 = switchdist*switchdist;
02833 float s = cut2-dist2;
02834 float range = cut2-switch2;
02835 sw = s*s*(cut2+2*dist2-3*switch2)/(range*range*range);
02836 }
02837 }
02838
02839 float term6 = (float) powf((rmin1+rmin2)/dist,6);
02840 *energy = sqrtf(eps1*eps2)*(term6*term6 - 2.0f*term6)*sw;
02841
02842 return MEASURE_NOERR;
02843 }
02844
02845 int compute_elect_energy(MoleculeList *mlist, int *molid, int *atmid, float *energy, float q1, float q2,
02846 bool flag1, bool flag2, float cutoff) {
02847 int ret_val;
02848 float dist;
02849
02850
02851 if ((ret_val=calculate_bond(mlist, molid, atmid, &dist))<0)
02852 return ret_val;
02853
02854
02855 if (!flag1) q1 = mlist->mol_from_id(molid[0])->charge()[atmid[0]];
02856 if (!flag2) q2 = mlist->mol_from_id(molid[0])->charge()[atmid[1]];
02857
02858 if (cutoff>0.0) {
02859 if (dist<cutoff) {
02860 float efac = 1.0f-dist*dist/(cutoff*cutoff);
02861 *energy = 332.0636f*q1*q2/dist*efac*efac;
02862 } else {
02863 *energy = 0.0f;
02864 }
02865 } else {
02866 *energy = 332.0636f*q1*q2/dist;
02867 }
02868
02869 return MEASURE_NOERR;
02870 }
02871
02872
02873
02874
02875 static void center_of_mass(AtomSel *sel, MoleculeList *mlist, float *rcom) {
02876 int i;
02877 float m = 0, mtot = 0;
02878 Molecule *mol = mlist->mol_from_id(sel->molid());
02879
02880
02881 const float *mass = mol->mass();
02882
02883
02884 const float *pos = sel->coordinates(mlist);
02885
02886 memset(rcom, 0, 3L*sizeof(float));
02887
02888
02889 for (i=sel->firstsel; i<=sel->lastsel; i++) {
02890 if (sel->on[i]) {
02891 long ind = i * 3L;
02892
02893 m = mass[i];
02894
02895 rcom[0] += m*pos[ind ];
02896 rcom[1] += m*pos[ind + 1];
02897 rcom[2] += m*pos[ind + 2];
02898
02899
02900 mtot += m;
02901 }
02902 }
02903
02904 rcom[0] /= mtot;
02905 rcom[1] /= mtot;
02906 rcom[2] /= mtot;
02907 }
02908
02909
02910
02911
02912
02913
02914
02915
02916 extern int measure_inertia(AtomSel *sel, MoleculeList *mlist, const float *coor, float rcom[3],
02917 float priaxes[3][3], float itensor[4][4], float evalue[3]) {
02918 if (!sel) return MEASURE_ERR_NOSEL;
02919 if (sel->num_atoms == 0) return MEASURE_ERR_NOATOMS;
02920
02921 Molecule *mol = mlist->mol_from_id(sel->molid());
02922
02923 float x, y, z, m;
02924 float Ixx=0, Iyy=0, Izz=0, Ixy=0, Ixz=0, Iyz=0;
02925 int i,j=0;
02926
02927
02928
02929 memset(itensor, 0, 16L*sizeof(float));
02930 itensor[3][3] = 1.0;
02931
02932
02933 center_of_mass(sel, mlist, rcom);
02934
02935
02936 const float *pos = sel->coordinates(mlist);
02937
02938
02939 const float *mass = mol->mass();
02940
02941
02942
02943 for (i=sel->firstsel; i<=sel->lastsel; i++) {
02944 if (sel->on[i]) {
02945
02946 if (coor) {
02947
02948 x = coor[j*3L ] - rcom[0];
02949 y = coor[j*3L + 1] - rcom[1];
02950 z = coor[j*3L + 2] - rcom[2];
02951 j++;
02952 } else {
02953
02954 x = pos[i*3L ] - rcom[0];
02955 y = pos[i*3L + 1] - rcom[1];
02956 z = pos[i*3L + 2] - rcom[2];
02957 }
02958
02959 m = mass[i];
02960
02961 Ixx += m*(y*y+z*z);
02962 Iyy += m*(x*x+z*z);
02963 Izz += m*(x*x+y*y);
02964 Ixy -= m*x*y;
02965 Ixz -= m*x*z;
02966 Iyz -= m*y*z;
02967 }
02968 }
02969
02970 itensor[0][0] = Ixx;
02971 itensor[1][1] = Iyy;
02972 itensor[2][2] = Izz;
02973 itensor[0][1] = Ixy;
02974 itensor[1][0] = Ixy;
02975 itensor[0][2] = Ixz;
02976 itensor[2][0] = Ixz;
02977 itensor[1][2] = Iyz;
02978 itensor[2][1] = Iyz;
02979
02980
02981
02982 float evector[3][3];
02983 if (jacobi(itensor,evalue,evector) != 0) return MEASURE_ERR_NONZEROJACOBI;
02984
02985
02986 float vectmp;
02987 vectmp=evector[0][1]; evector[0][1]=evector[1][0]; evector[1][0]=vectmp;
02988 vectmp=evector[0][2]; evector[0][2]=evector[2][0]; evector[2][0]=vectmp;
02989 vectmp=evector[2][1]; evector[2][1]=evector[1][2]; evector[1][2]=vectmp;
02990
02991
02992
02993
02994 float *a[3];
02995 a[0] = evector[0];
02996 a[1] = evector[1];
02997 a[2] = evector[2];
02998
02999
03000 #define SWAP(qq,ww) { \
03001 float v; float *v1; \
03002 v = evalue[qq]; evalue[qq] = evalue[ww]; evalue[ww] = v; \
03003 v1 = a[qq]; a[qq] = a[ww]; a[ww] = v1; \
03004 }
03005 if (evalue[0] < evalue[1]) {
03006 SWAP(0, 1);
03007 }
03008 if (evalue[0] < evalue[2]) {
03009 SWAP(0, 2);
03010 }
03011 if (evalue[1] < evalue[2]) {
03012 SWAP(1, 2);
03013 }
03014
03015 #if 0
03016
03017
03018 if (evalue[1]/evalue[0]>0.1 && fabs(evalue[1]-evalue[2])/evalue[0]<0.05
03019 && fabs(evalue[0]-evalue[1])/evalue[0]>0.05) {
03020 msgInfo << "Principal axes of inertia 2 and 3 are not unique!" << sendmsg;
03021 }
03022 #endif
03023
03024 for (i=0; i<3; i++) {
03025 for (j=0; j<3; j++)
03026 priaxes[i][j] = a[i][j];
03027 }
03028
03029 return MEASURE_NOERR;
03030 }
03031