int perp_line_fit (double **point, int no_of_points, double p[], double cm[], double avg[]) { /* p and the center of the mass define a line */ /* we need a new set of lines perpencidular through this one, going through the points given in the array */ int i, j; double dp, d[3], p_perp[3], p_perp_0[3], cosine, norm; double normalize (double *p); memset (avg, 0, 3*sizeof(double)); /* if d is the vector from CM to the atom O, p_perp = d -(dp)p (all vectors) */ for (i=0; i< no_of_points; i++) { dp = 0; for (j=0; j<3; j++) { d[j] = point[i][j] - cm[j]; dp += d[j]*p[j]; } norm = 0; for (j=0; j<3; j++) { p_perp[j] = d[j] - dp*p[j]; norm += p_perp[j]*p_perp[j]; } norm = sqrt (norm); for (j=0; j<3; j++) p_perp[j] /= norm; if ( i== 0 ) { for (j=0; j<3; j++) p_perp_0[j] = p_perp[j]; } unnorm_dot (p_perp_0, p_perp, &cosine); if ( cosine < 0 ) { for (j=0; j<3; j++) p_perp[j] = -p_perp[j] ; cosine = -cosine; } for (j=0; j<3; j++) avg[j] += p_perp[j]; # if 0 /* TODO - this might be the place to start cleaning up the line fit - all vectors should be parallel */ for (j=0; j<3; j++) printf (" %8.2lf", p_perp[j]); printf (" %8.2lf\n", cosine); # endif } norm = 0; for (j=0; j<3; j++) { avg[j] /= no_of_points; norm += avg[j]*avg[j]; } norm = sqrt (norm); for (j=0; j<3; j++) avg[j] /= norm; return 0; }
int store_sse_pair_score ( Representation *X_rep, Representation *Y_rep, double **R, double alpha, Map *map ){ int i,j, i_is_helix; int NX=X_rep->N_full, NY=Y_rep->N_full; double cosine; double alpha_sq = alpha*alpha; double ** x_full_rotated = NULL, **y_full = Y_rep->full; double length_dif, exponent; if ( ! (x_full_rotated=dmatrix (NX,3) ) ) return 1; rotate (x_full_rotated, X_rep->N_full, R, X_rep->full); for (i=0; i < NX; i++ ) { i_is_helix = ( X_rep->full_type[i] == HELIX); for (j=0; j < NY; j++) { if ( X_rep->full_type[i] == Y_rep->full_type[j] ) { unnorm_dot (x_full_rotated[i], y_full[j], &cosine); exponent = 2*(1.0-cosine)/alpha_sq; if ( exponent < 10 ) { map->sse_pair_score[i][j] = exp (-exponent); /* are we using the info about the length? */ if (options.use_length && cosine > 0.0) { length_dif = abs (X_rep->length[i] - Y_rep->length[j]); if ( i_is_helix ) { map->sse_pair_score[i][j] *= 1/(1.0+length_dif/options.H_length_mismatch_tol); } else { map->sse_pair_score[i][j] *= 1/(1.0+length_dif/options.S_length_mismatch_tol); } } } else { map->sse_pair_score[i][j] = 0.0; } map->cosine[i][j] = cosine; } else { map->sse_pair_score[i][j] = options.far_far_away; map->cosine[i][j] = -0.9999; } } } free_dmatrix (x_full_rotated); return 0; }
/* check that the two are not mirror images - count on it being a triple*/ int hand (Representation * X_rep, int *set_of_directions_x) { double **x = X_rep->full; double **x_cm = X_rep->cm; double cm_vector[3], avg_cm[3], cross[3], d, aux; int i, ray_a, ray_b, ray_c, a, b, c; a = 0; b = 1; c = 2; /*****************************/ /*****************************/ ray_a = set_of_directions_x[a]; ray_b = set_of_directions_x[b]; ray_c = set_of_directions_x[c]; /* I better not use the cross prod here: a small diff int he angle makeing them pointing toward each other or away from each other changes the direction of cross prod; rather, use one vector, and distance between the cm's as the other */ for (i=0; i<3; i++ ) { cm_vector[i] = x_cm[ray_b][i] - x_cm[ray_a][i]; } normalized_cross (x[ray_a], x[ray_b], cross, &aux); /* note I am making another cm vector here */ for (i=0; i<3; i++ ) { avg_cm[i] = (x_cm[ray_b][i] + x_cm[ray_a][i])/2; cm_vector[i] = x_cm[ray_c][i] - avg_cm[i]; } unnorm_dot (cm_vector, cross, &d); if ( d > 0 ) { return 0; } else { return 1; } }
/* check that the two are not mirror images - count on it being a triple*/ int same_hand_triple (Representation * X_rep, int *set_of_directions_x, Representation * Y_rep, int *set_of_directions_y, int set_size) { double **x = X_rep->full; double **x_cm = X_rep->cm; double **y = Y_rep->full; double **y_cm = Y_rep->cm; double cm_vector[3], avg_cm[3], cross[3], dx, dy, aux; int i, ray_a, ray_b, ray_c, a, b, c; if (set_size !=3 ) return 0; a = 0; b = 1; c = 2; /*****************************/ /*****************************/ ray_a = set_of_directions_x[a]; ray_b = set_of_directions_x[b]; ray_c = set_of_directions_x[c]; /* I better not use the cross prod here: a small diff int he angle makeing them pointing toward each other or away from each other changes the direction of cross prod; rather, use one vector, and distance between the cm's as the other */ for (i=0; i<3; i++ ) { cm_vector[i] = x_cm[ray_b][i] - x_cm[ray_a][i]; } /* note that the cross product here is between the direction vector of SSE labeled a, and the vector spanning the geeometric centers of a and b - this cross prod can be undefined only if the two are stacked */ if ( ! normalized_cross (x[ray_a], cm_vector, cross, &aux)) { /* the function returns 0 on success, i.e. retval==0 means the cross product can be calculated ok. */ /* note I am making another cm vector here */ for (i=0; i<3; i++ ) { avg_cm[i] = (x_cm[ray_b][i] + x_cm[ray_a][i])/2; cm_vector[i] = x_cm[ray_c][i] - avg_cm[i]; } unnorm_dot (cm_vector, cross, &dx); /*****************************/ /*****************************/ ray_a = set_of_directions_y[a]; ray_b = set_of_directions_y[b]; ray_c = set_of_directions_y[c]; for (i=0; i<3; i++ ) { cm_vector[i] = y_cm[ray_b][i] - y_cm[ray_a][i]; } if (normalized_cross (y[ray_a], cm_vector, cross, &aux)) { /* if I can calculate the cross product for one triplet but not for the other, I declare it a different hand (this will be dropped from further consideration) */ return 0; } /* note I am making another cm vector here */ for (i=0; i<3; i++ ) { avg_cm[i] = (y_cm[ray_b][i] + y_cm[ray_a][i])/2; cm_vector[i] = y_cm[ray_c][i] - avg_cm[i]; } /*note: unnorm_dot thinks it is getting unit vectors, and evrything that is >1 will be "rounded" to 1 (similarly for -1) - it doesn't do the normalization itself*/ unnorm_dot (cm_vector, cross, &dy); if ( dx*dy < 0 ) { return 0; } else { return 1; /* this isn't err value - the handedness is the same */ } } else { /* if the vectors linking cms are parallel, the hand is the same (my defintion) */ double cm_vector_2[3], dot; ray_a = set_of_directions_y[a]; ray_b = set_of_directions_y[b]; ray_c = set_of_directions_y[c]; for (i=0; i<3; i++ ) { cm_vector_2[i] = y_cm[ray_b][i] - y_cm[ray_a][i]; } unnorm_dot(cm_vector, cm_vector_2, &dot); if ( dot > 0) { return 1; } else { return 0; } /* (hey, at least I am checking the retvals of my functions) */ } return 0; /* better safe than sorry */ }
int fit_line (double **point, int no_points, double center[3], double direction[3]) { int i, j, point_ctr; double I[3][3] = {{0.0}}; double translated_point[3]; void dsyev_(char * jobz, char * uplo, int* N, double * A, int * leading_dim, double * eigenvalues, double *workspace, int *workspace_size, int * retval); if (!no_points) { fprintf (stderr, "Error in %s:%d: in fit_line() - no points given\n", __FILE__, __LINE__); exit (1); } for (i=0; i<3; i++) center[i] = 0; for (point_ctr = 0; point_ctr < no_points; point_ctr++) { for (i=0; i<3; i++) center[i] += point[point_ctr][i]; } for (i=0; i<3; i++) center[i] /= no_points; for (point_ctr = 0; point_ctr < no_points; point_ctr++) { for (i=0; i<3; i++) { translated_point[i] = point[point_ctr][i] - center[i]; } /* moments of inertia */ for (i=0; i<3; i++) { /* modulo = circular permutation */ I[i][i] += translated_point[(i+1)%3]*translated_point[(i+1)%3] + translated_point[(i+2)%3]*translated_point[(i+2)%3]; for ( j=i+1; j<3; j++) { /* offdiag elements */ I[i][j] -= translated_point[i]*translated_point[j]; } } } for (i=0; i<3; i++) { for ( j=i+1; j<3; j++) { I[j][i] = I[i][j]; } } /*****************************************/ /* diagonalize I[][], pick the direction with the smallest moment of inertia, and rotate back to the initial frame */ /*****************************************/ char jobz = 'V'; /* find evalues and evectors */ char uplo = 'L'; /* matrix is stored as lower (fortran convention) */ int N = 3; /* the order of matrix */ int leading_dim = N; int retval = 0; int workspace_size = 3*N; double A[N*N]; double eigenvalues[N]; double workspace[3*N]; double NC_direction[3]; for (i=0; i<3; i++) { for ( j=0; j<3; j++) { A[i*3+j] = I[i][j]; } } dsyev_ ( &jobz, &uplo, &N, A, &leading_dim, eigenvalues, workspace, &workspace_size, &retval); if ( retval ) { fprintf (stderr, "Error in %s:%d: dsyev() returns %d.\n", __FILE__, __LINE__, retval); exit (1); } for (i=0; i<3; i++) direction[i] = A[i]; /* sum of squared dist is egeinvalues[0]; in case we need it */ /* force the direction to be N-->C */ for (i=0; i<3; i++) { NC_direction[i] = point[no_points-1][i] - point[0][i]; } double dot; unnorm_dot (NC_direction,direction, &dot); if ( dot<0 ) { for (i=0; i<3; i++) direction[i] *= -1; } return 0; }
/* check that the two are not mirror images - count on it being a triple*/ int same_hand_triple (Representation * X_rep, int *set_of_directions_x, Representation * Y_rep, int *set_of_directions_y, int set_size) { double **x = X_rep->full; double **x_cm = X_rep->cm; double **y = Y_rep->full; double **y_cm = Y_rep->cm; double cm_vector[3], avg_cm[3], cross[3], dx, dy, aux; int i, ray_a, ray_b, ray_c, a, b, c; if (set_size !=3 ) return 0; a = 0; b = 1; c = 2; /*****************************/ /*****************************/ ray_a = set_of_directions_x[a]; ray_b = set_of_directions_x[b]; ray_c = set_of_directions_x[c]; /* I better not use the cross prod here: a small diff int he angle makeing them pointing toward each other or away from each other changes the direction of cross prod; rather, use one vector, and distance between the cm's as the other */ for (i=0; i<3; i++ ) { cm_vector[i] = x_cm[ray_b][i] - x_cm[ray_a][i]; } normalized_cross (x[ray_a], x[ray_b], cross, &aux); /* note I am makning another cm vector here */ for (i=0; i<3; i++ ) { avg_cm[i] = (x_cm[ray_b][i] + x_cm[ray_a][i])/2; cm_vector[i] = x_cm[ray_c][i] - avg_cm[i]; } unnorm_dot (cm_vector, cross, &dx); /*****************************/ /*****************************/ ray_a = set_of_directions_y[a]; ray_b = set_of_directions_y[b]; ray_c = set_of_directions_y[c]; for (i=0; i<3; i++ ) { cm_vector[i] = y_cm[ray_b][i] - y_cm[ray_a][i]; } normalized_cross (y[ray_a], y[ray_b], cross, &aux); /* note I am makning another cm vector here */ for (i=0; i<3; i++ ) { avg_cm[i] = (y_cm[ray_b][i] + y_cm[ray_a][i])/2; cm_vector[i] = y_cm[ray_c][i] - avg_cm[i]; } /*note: unnorm_dot thinks it is getting unit vectors, and evrything that is >1 will be "rounded" to 1 (similarly for -1) - it doesn't do the normalization itself*/ unnorm_dot (cm_vector, cross, &dy); if ( dx*dy < 0 ) return 0; return 1; /* this isn't err value - the handedness is the same */ }
int qmap (double *x0, double *x1, double *y0, double *y1, double * quat){ double q1[4], q2[4]; double v[3], v2[3], cosine = 0, theta =0, sine; double x_prime[3]; int i,j; int normalized_cross (double *x, double *y, double * v, double *norm_ptr); int unnorm_dot (double *x, double *y, double * dot); /* 1) find any quat for x0 --> y0 */ /* check that it is not the same vector already: */ unnorm_dot (x0, y0, &cosine); if ( 1-cosine > 0.001 ) { double ** R; if ( normalized_cross (x0, y0, v, NULL) )return 1; theta = acos (cosine); q1[0] = cos (theta/2); sine = sin(theta/2); for (i=0; i<3; i++ ) { q1[i+1] = sine*v[i]; } if ( ! (R=dmatrix(3,3) ) ) return 1; /* compiler is bugging me otherwise */ quat_to_R (q1, R); for (i=0; i<3; i++ ) { x_prime[i] = 0; for (j=0; j<3; j++ ) { x_prime[i] += R[i][j]*x1[j]; } } free_dmatrix (R); } else { memcpy (x_prime, x1, 3*sizeof(double) ); memset (q1, 0, 4*sizeof(double) ); q1[0] = 1.0; } /* 2) find quat thru y0 which maps x' to the plane <y0,y1> */ unnorm_dot (x_prime, y1, &cosine); /* determining theta: angle btw planes = angle btw the normals */ if ( 1-cosine > 0.001 ) { if ( normalized_cross (x_prime, y0,v, NULL)) return 1; if ( normalized_cross (y1, y0, v2, NULL)) return 1; unnorm_dot (v, v2, &cosine); theta = acos (cosine); /*still need to determine the sign of rotation */ if (normalized_cross (x_prime, y1,v, NULL)) return 1; unnorm_dot (v, y0, &cosine); if ( cosine > 0.0 ) { sine = sin(theta/2); } else { sine = -sin(theta/2); } for (i=0; i<3; i++ ) { v[i] = y0[i]; } q2[0] = cos (theta/2); for (i=0; i<3; i++ ) { q2[i+1] = sine*v[i]; } } else { memset (q2, 0, 4*sizeof(double) ); q2[0] = 1.0; } /* multiply the two quats */ multiply (q2, q1, 0, quat); return 0; }
int qmap_bisec (double *x0, double *x1, double *y0, double *y1, double * quat){ double q1[4], q2[4]; double v[3], cosine = 0, theta =0, sine; double bisec_x[3], bisec_y[3]; double norm_x[3], norm_y[3]; double bisec_x_prime[3]; double norm; int i,j; int normalized_cross (double *x, double *y, double * v, double *norm_ptr); int unnorm_dot (double *x, double *y, double * dot); /* 0) find normals and bisectors */ if ( normalized_cross (x0, x1, norm_x, NULL) )return 1; if ( normalized_cross (y0, y1, norm_y, NULL) )return 1; norm = 0; for (i=0; i<3; i++ ) { bisec_x[i] = (x0[i] + x1[i])/2; norm += bisec_x[i]*bisec_x[i]; } norm += sqrt(norm); if (norm) for (i=0; i<3; i++ ) bisec_x[i] /= norm; norm = 0; for (i=0; i<3; i++ ) { bisec_y[i] = (y0[i] + y1[i])/2; norm += bisec_y[i]*bisec_y[i]; } norm += sqrt(norm); if (norm) for (i=0; i<3; i++ ) bisec_y[i] /= norm; /* 1) find any quat that will match the normals */ /* check that it is not the same vector already: */ unnorm_dot (norm_x, norm_y, &cosine); if ( 1-cosine > 0.001 ) { double ** R; if ( normalized_cross (norm_x, norm_y, v, NULL) )return 1; theta = acos (cosine); q1[0] = cos (theta/2); sine = sin(theta/2); for (i=0; i<3; i++ ) { q1[i+1] = sine*v[i]; } if ( ! (R=dmatrix(3,3) ) ) return 1; /* compiler is bugging me otherwise */ quat_to_R (q1, R); for (i=0; i<3; i++ ) { bisec_x_prime[i] = 0; for (j=0; j<3; j++ ) { bisec_x_prime[i] += R[i][j]*bisec_x[j]; } } free_dmatrix (R); } else { memcpy (bisec_x_prime, bisec_x, 3*sizeof(double)); memset (q1, 0, 4*sizeof(double) ); q1[0] = 1.0; } /* 2) find quat thru norm_y which maps bisectors one onto another */ unnorm_dot (bisec_x_prime, bisec_y, &cosine); /* determining theta: angle btw planes = angle btw the normals */ if ( 1-cosine > 0.001 ) { theta = acos (cosine); /*still need to determine the sign of rotation */ if (normalized_cross (bisec_x_prime, bisec_y, v, NULL)) return 1; unnorm_dot (v, norm_y, &cosine); if ( cosine > 0.0 ) { sine = sin(theta/2); } else { sine = -sin(theta/2); } for (i=0; i<3; i++ ) { v[i] = norm_y[i]; } q2[0] = cos (theta/2); for (i=0; i<3; i++ ) { q2[i+1] = sine*v[i]; } } else { memset (q2, 0, 4*sizeof(double) ); q2[0] = 1.0; } /* multiply the two quats */ multiply (q2, q1, 0, quat); return 0; }
/* we'll need neighbrohoods as a measure of similarity between elements */ int find_neighborhoods (Representation *rep, Representation ** hood) { double **x = rep->full; double **x_cm = rep->cm; double d, hood_radius = 10; double cm_vector[3], cross[3], csq, component; int NX = rep->N_full; int max_hood_size = NX - 1; int a, b, i; int index_a, index_b; for (a=0; a<NX; a++) hood[a]->N_full = 0; // just in case for (a=0; a<NX; a++) { for (b=a+1; b<NX; b++) { csq = 0; for (i=0; i<3; i++ ) { /* from b to a */ component = x_cm[a][i] - x_cm[b][i]; cm_vector[i] = component; csq += component*component; } /* how far is it? use distance of nearest approach; if too far, move on */ /* distance from a to the nearest point in b */ normalized_cross (cm_vector, x[b], cross, &d); if (d < hood_radius) { index_a = hood[a]->N_full; /* what is the direction to this nearest point? */ /* dir = -cm - b*sqrt(csq-d*d) */ double dist_from_cm_b = sqrt(csq-d*d); for (i=0; i<3; i++ ) { hood[a]->full [index_a] [i] = -cm_vector[i] -x[b][i]*dist_from_cm_b ; } hood[a]->N_full ++; /* type */ hood[a]->full_type[index_a] = rep->full_type[b]; } /* distance from b to the nearest point in a */ normalized_cross (cm_vector, x[a], cross, &d); if (d < hood_radius) { // d is now different number then above index_b = hood[b]->N_full; /* what is the direction to this nearest point? */ /* dir = -cm - a*sqrt(csq-d*d) */ double dist_from_cm_a = sqrt(csq-d*d); for (i=0; i<3; i++ ) { // note the oopsite dir for the cm vector hood[b]->full [index_b] [i] = cm_vector[i] -x[a][i]*dist_from_cm_a ; } hood[b]->N_full ++; /* type */ hood[a]->full_type[index_b] = rep->full_type[a]; } } } /* rotate to the frame in which the sse vector is pointing up (0,0,1) */ double rotation_axis[3], z_direction[3] = {0, 0, 1}, theta, cosine, sine; double quat[4], **R; double **rotated_hood; if ( ! (R=dmatrix(3,3) )) return 1; /* compiler is bugging me otherwise */ if ( ! (rotated_hood = dmatrix(max_hood_size,3) )) return 1; for (a=0; a<NX; a++) { unnorm_dot (x[a], z_direction, &cosine); if ( 1 - cosine <= 0.0001) { // x[a] already pretty much is z-direction // do nothing: hood is already rotated } else { normalized_cross (x[a], z_direction, rotation_axis, &d); // quaternion theta = acos (cosine); quat[0] = cos (theta/2); sine = sin(theta/2); for (i=0; i<3; i++ ) { quat[i+1] = sine*rotation_axis[i]; } // rotation quat_to_R (quat, R); // rotate all hood vectors rotate(rotated_hood, hood[a]->N_full, R, hood[a]->full ); //copy rotated hood into the old one memcpy (hood[a]->full[0], rotated_hood[0], hood[a]->N_full*3*sizeof(double)); } } free_dmatrix (R); free_dmatrix (rotated_hood); return 0; }