static coord_t * test_points(int N) { // Golden section spiral on a sphere // from http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere double dlong = M_PI*(3-sqrt(5)), dz = 2.0/N, longitude = 0, z = 1-dz/2, r; coord_t *coord = freesasa_coord_new(); double *tp = malloc(3*N*sizeof(double)); if (tp == NULL || coord == NULL) { freesasa_coord_free(coord); free(tp); mem_fail(); return NULL; } for (double *p = tp; p-tp < 3*N; p += 3) { r = sqrt(1-z*z); p[0] = cos(longitude)*r; p[1] = sin(longitude)*r; p[2] = z; z -= dz; longitude += dlong; } if (freesasa_coord_append(coord,tp,N) == FREESASA_FAIL) { fail_msg(""); freesasa_coord_free(coord); coord = NULL; } free(tp); return coord; }
// free contents void release_sr(sr_data sr) { freesasa_coord_free(sr.srp); freesasa_nb_free(sr.nb); free(sr.r); free(sr.r2); }
// free contents void release_sr(sr_data *sr) { freesasa_coord_free(sr->srp); freesasa_nb_free(sr->nb); free(sr->r); free(sr->r2); }
int init_sr(sr_data* sr_p, double *sasa, const coord_t *xyz, const double *r, double probe_radius, int n_points) { int n_atoms = freesasa_coord_n(xyz); coord_t *srp = test_points(n_points); if (srp == NULL) return fail_msg("Failed to initialize test points."); //store parameters and reference arrays sr_data sr = {.n_atoms = n_atoms, .n_points = n_points, .probe_radius = probe_radius, .xyz = xyz, .srp = srp, .sasa = sasa}; sr.r = malloc(sizeof(double)*n_atoms); sr.r2 = malloc(sizeof(double)*n_atoms); if (sr.r == NULL || sr.r2 == NULL) { freesasa_coord_free(srp); free(sr.r); free(sr.r2); return mem_fail(); } for (int i = 0; i < n_atoms; ++i) { sr.r[i] = r[i] + probe_radius; sr.r2[i] = sr.r[i]*sr.r[i]; } //calculate distances sr.nb = freesasa_nb_new(xyz,sr.r); if (sr.nb == NULL) { freesasa_coord_free(srp); free(sr.r); free(sr.r2); return mem_fail(); } *sr_p = sr; return FREESASA_SUCCESS; }
static double sr_atom_area(int i, const sr_data sr) { const int n_points = sr.n_points; /* this array keeps track of which testpoints belonging to a certain atom do not overlap with any other atoms */ int spcount[n_points]; const int nni = sr.nb->nn[i]; const int * restrict nbi = sr.nb->nb[i]; const double ri = sr.r[i]; const double * restrict r2 = sr.r2; const double * restrict v = freesasa_coord_all(sr.xyz); const double * restrict vi = v+3*i; const double * restrict tp; int n_surface = 0, current_nb, a; double dx, dy, dz; /* testpoints for this atom */ coord_t * restrict tp_coord_ri = freesasa_coord_copy(sr.srp); freesasa_coord_scale(tp_coord_ri, ri); freesasa_coord_translate(tp_coord_ri, vi); tp = freesasa_coord_all(tp_coord_ri); // initialize with all surface points hidden memset(spcount,0,n_points*sizeof(int)); /* Using the trick from NSOL to check points one by one for all atoms, start comparing with the first neighbor. If there is no overlap for a given test-point, try with other neighbors instead. Would probably work even better if test points were organized in patches and not spirals. */ current_nb = 0; for (int j = 0; j < n_points; ++j) { //a is the index of the atom under consideration a = nbi[current_nb]; dx = tp[j*3] - v[a*3]; dy = tp[j*3+1] - v[a*3+1]; dz = tp[j*3+2] - v[a*3+2]; if (dx*dx + dy*dy + dz*dz > r2[a]) { int k = 0; for (; k < nni; ++k) { a = nbi[k]; dx = tp[j*3] - v[a*3]; dy = tp[j*3+1] - v[a*3+1]; dz = tp[j*3+2] - v[a*3+2]; if (dx*dx + dy*dy + dz*dz <= r2[a]) { current_nb = k; break; } } // we have gone through the whole list without overlap if (k == nni) spcount[j] = 1; } } for (int k = 0; k < n_points; ++k) { if (spcount[k]) ++n_surface; } freesasa_coord_free(tp_coord_ri); return (4.0*M_PI*ri*ri*n_surface)/n_points; }