/* Note: Doesn't handle non-existant residues. */ double AlignAlignmentBlocks(int p1, int p2, int count1, int count2, WeightedResiduePositions *r1, WeightedResiduePositions *r2, int len, Matrix *m, double minScore) { Matrix A = {0,0,0,0,0,0,0,0,0,0,0,0}; Matrix m1, m2, m3, m4; Vector com1 = {0,0,0}, com2 = {0,0,0}; double E0 = 0; double rmsd; int i, j, k; double *normalized1; double *normalized2; double buffer[2000]; /* * Only malloc when needed, which isn't often. */ if (len <= 1000) { normalized1 = buffer; } else { normalized1 = (double*) malloc(len * sizeof(double) * 2); } normalized2 = normalized1+len; for (i=0; i<len; i++) { Vector v; Vector com1delta = {0,0,0}, com2delta = {0,0,0}; normalized1[i] = 0; normalized2[i] = 0; for (j=0; j<count1; j++) { if (!r1[j].res[p1+i].exists) { /* Shouldn't ever happen. */ return -5; } normalized1[i] += r1[j].weight; addVect(&com1delta, &com1delta, mulVect(&v, &r1[j].res[p1+i].coords, r1[j].weight)); } for (j=0; j<count2; j++) { if (!r2[j].res[p2+i].exists) { /* Shouldn't ever happen. */ return -5; } normalized2[i] += r2[j].weight; addVect(&com2delta, &com2delta, mulVect(&v, &r2[j].res[p2+i].coords, r2[j].weight)); } addVect(&com1, &com1, divVect(&com1delta, &com1delta, normalized1[i])); addVect(&com2, &com2, divVect(&com2delta, &com2delta, normalized2[i])); } divVect(&com1, &com1, len); divVect(&com2, &com2, len); for (i=0; i<len; i++) { if (normalized1[i] != 0 && normalized2[i] != 0) { Vector moved1 = {0,0,0}; Vector moved2 = {0,0,0}; double E0delta1 = 0; double E0delta2 = 0; for (j=0; j<count1; j++) { if (r1[j].res[p1+i].exists) { Vector temp1, temp2; subVect(&temp1, &r1[j].res[p1+i].coords, &com1); mulVect(&temp2, &temp1, r1[j].weight); addVect(&moved1, &moved1, &temp2); E0delta1 += dotVect(&temp1, &temp2); } } E0delta1 /= normalized1[i]; divVect(&moved1, &moved1, normalized1[i]); for (j=0; j<count2; j++) { if (r2[j].res[p2+i].exists) { Vector temp1, temp2; subVect(&temp1, &r2[j].res[p2+i].coords, &com2); mulVect(&temp2, &temp1, r2[j].weight); addVect(&moved2, &moved2, &temp2); E0delta2 += dotVect(&temp1, &temp2); } } E0delta2 /= normalized2[i]; divVect(&moved2, &moved2, normalized2[i]); E0 += E0delta1 + E0delta2; for (j=0; j<3; j++) { for (k=0; k<3; k++) A.M[j][k] += moved2.v[k] * moved1.v[j]; } } } E0/=2; if (minScore > 0) { Matrix ATA; rmsd = CalcRMSD(&ATA, &A, E0, len); if (RMSDScoreSimple(rmsd, len) < minScore) { /* Don't bother with rotation. */ return rmsd; } rmsd = CalcRotation(&m3, &A, &ATA, E0, len); } else { rmsd = CalcRMSDAndRotation(&m3, &A, E0, len); } m3.M[0][3] = 0; m3.M[1][3] = 0; m3.M[2][3] = 0; m2 = m1 = identity; m2.M[0][3] = -com2.v[0]; m2.M[1][3] = -com2.v[1]; m2.M[2][3] = -com2.v[2]; m1.M[0][3] = com1.v[0]; m1.M[1][3] = com1.v[1]; m1.M[2][3] = com1.v[2]; mulMat(&m4, &m3, &m2); mulMat(m, &m1, &m4); if (normalized1 != buffer) free(normalized1); return rmsd; }
double lengthSquaredVect(const Vector *v) { return dotVect(v, v); }
double lengthVect(const Vector *v) { return sqrt(dotVect(v,v)); }
double invHalfCosQuat(const Quaternion *q1, const Quaternion *q2) { return fabs(q1->w*q2->w + dotVect(&q1->v, &q2->v)); }