int freesasa_shrake_rupley(double *sasa, const coord_t *xyz, const double *r, const freesasa_parameters *param) { assert(sasa); assert(xyz); assert(r); if (param == NULL) param = &freesasa_default_parameters; int n_atoms = freesasa_coord_n(xyz), n_threads = param->n_threads, resolution = param->shrake_rupley_n_points, return_value = FREESASA_SUCCESS; double probe_radius = param->probe_radius; sr_data sr; if (resolution <= 0) return freesasa_fail("in %s(): n_slices_per_atom = %f is invalid, must be > 0\n", __func__, resolution); if (n_atoms == 0) return freesasa_warn("%s(): empty coordinates", __func__); if (n_threads > n_atoms) { n_threads = n_atoms; freesasa_warn("No sense in having more threads than atoms, only using %d threads.", n_threads); } if (init_sr(&sr, sasa, xyz, r, probe_radius, resolution)) return FREESASA_FAIL; //calculate SASA if (n_threads > 1) { #if USE_THREADS return_value = sr_do_threads(n_threads, &sr); #else return_value = freesasa_warn("%s: program compiled for single-threaded use, " "but multiple threads were requested. Will " "proceed in single-threaded mode.\n", __func__); n_threads = 1; #endif } if (n_threads == 1) { // don't want the overhead of generating threads if only one is used for (int i = 0; i < n_atoms; ++i) { sasa[i] = sr_atom_area(i, &sr); } } release_sr(&sr); return return_value; }
static int select_range(expression_type range_type, expression_type parent_type, struct selection *selection, const freesasa_structure *structure, const expression *left, const expression *right) { int lower, upper, i, j; assert(range_type == E_RANGE || range_type == E_RANGE_OPEN_L || range_type == E_RANGE_OPEN_R); assert(parent_type == E_RESI || parent_type == E_CHAIN); if (parent_type == E_RESI) { /* residues have integer numbering */ if (( left && left->type != E_NUMBER) || (right && right->type != E_NUMBER)) { return freesasa_warn("select: %s: range '%s-%s' invalid, needs to be two numbers, " "will be ignored",e_str(parent_type), left->value, right->value); } } else { /* chains can be numbered by both letters (common) and numbers (uncommon) */ if (left->type != right->type || (left->type == E_ID && (strlen(left->value) > 1 || strlen(right->value) > 1))) return freesasa_warn("select: %s: range '%s-%s' invalid, should be two letters (A-C) or numbers (1-5), " "will be ignored", e_str(parent_type), left->value, right->value); } if (range_type == E_RANGE_OPEN_L) { lower = atoi(freesasa_structure_atom_res_number(structure, 0)); upper = atoi(right->value); } else if (range_type == E_RANGE_OPEN_R) { lower = atoi(left->value); upper = atoi(freesasa_structure_atom_res_number(structure, freesasa_structure_n(structure) - 1)); } else if (left->type == E_NUMBER) { lower = atoi(left->value); upper = atoi(right->value); } else { lower = (int)left->value[0]; upper = (int)right->value[0]; } for (i = 0; i < selection->size; ++i) { if (parent_type == E_RESI) j = atoi(freesasa_structure_atom_res_number(structure,i)); else j = (int)freesasa_structure_atom_chain(structure,i); if (j >= lower && j <= upper) selection->atom[i] = 1; } return FREESASA_SUCCESS; }
int freesasa_shrake_rupley(double *sasa, const coord_t *xyz, const double *r, double probe_radius, int n_points, int n_threads) { assert(sasa); assert(xyz); assert(r); assert(n_threads > 0); int n_atoms = freesasa_coord_n(xyz); int return_value = FREESASA_SUCCESS; sr_data sr; if (n_atoms == 0) return freesasa_warn("%s(): empty coordinates", __func__); if (init_sr(&sr,sasa,xyz,r,probe_radius,n_points)) return mem_fail(); //calculate SASA if (n_threads > 1) { #if USE_THREADS sr_do_threads(n_threads, sr); #else return_value = freesasa_warn("%s: program compiled for single-threaded use, " "but multiple threads were requested. Will " "proceed in single-threaded mode.\n", __func__); n_threads = 1; #endif } if (n_threads == 1) { // don't want the overhead of generating threads if only one is used for (int i = 0; i < n_atoms; ++i) { sasa[i] = sr_atom_area(i,sr); } } release_sr(sr); return return_value; }
static int select_list(expression_type parent_type, struct selection *selection, const freesasa_structure *structure, const expression *expr) { int resr, resl; expression *left, *right; if (expr == NULL) return fail_msg("NULL expression"); left = expr->left; right = expr->right; switch(expr->type) { case E_PLUS: if (left == NULL || right == NULL) return fail_msg("NULL expression"); resl = select_list(parent_type, selection, structure, left); resr = select_list(parent_type, selection, structure, right); if (resl == FREESASA_WARN || resr == FREESASA_WARN) return FREESASA_WARN; break; case E_RANGE: if (left == NULL || right == NULL) return fail_msg("NULL expression"); return select_range(E_RANGE, parent_type, selection, structure, left, right); case E_RANGE_OPEN_L: if (left != NULL || right == NULL) return fail_msg("NULL expression"); return select_range(E_RANGE_OPEN_L, parent_type, selection, structure, left, right); case E_RANGE_OPEN_R: if (left == NULL || right != NULL) return fail_msg("NULL expression"); return select_range(E_RANGE_OPEN_R, parent_type, selection, structure, left, right); case E_ID: case E_NUMBER: if (is_valid_id(parent_type, expr) == FREESASA_SUCCESS) select_id(parent_type, selection, structure, expr->value); else return freesasa_warn("select: %s: '%s' invalid %s", e_str(parent_type), expr->value, e_str(expr->type)); break; default: return freesasa_fail("select: parse error (expression: '%s %s')", e_str(parent_type), e_str(expr->type)); } return FREESASA_SUCCESS; }
/** Add type. Returns the index of the new type on success, FREESASA_FAIL if realloc/strdup fails, FREESASA_WARN if type already known (ignore duplicates). */ static int add_type(struct classifier_types *types, const char *type_name, const char *class_name, double r) { int the_class, n = types->n_types + 1; char **tn = types->name; double *tr = types->type_radius; int *tc = types->type_class; if (find_string(types->name, type_name, types->n_types) >= 0) return freesasa_warn("Ignoring duplicate entry for '%s'.", type_name); the_class = add_class(types,class_name); if (the_class == FREESASA_FAIL) { return mem_fail(); } if ((types->name = realloc(tn, sizeof(char*)*n)) == NULL) { types->name = tn; return mem_fail(); } if ((types->type_radius = realloc(tr, sizeof(double)*n)) == NULL) { types->type_radius = tr; return mem_fail(); } if ((types->type_class = realloc(tc, sizeof(int) * n)) == NULL) { types->type_class = tc; return mem_fail(); } if ((types->name[n-1] = strdup(type_name)) == NULL) { return mem_fail(); } types->n_types++; types->type_radius[types->n_types-1] = r; types->type_class[types->n_types-1] = the_class; return types->n_types-1; }
static void select_id(expression_type parent_type, struct selection *selection, const freesasa_structure *structure, const char *id) { int count = 0, match, i; assert(id); for (i = 0; i < selection->size; ++i) { match = 0; switch(parent_type) { case E_NAME: match = match_name(structure, id, i); break; case E_SYMBOL: match = match_symbol(structure, id, i); break; case E_RESN: match = match_resn(structure, id, i); break; case E_RESI: match = match_resi(structure, id, i); break; case E_CHAIN: match = match_chain(structure, id, i); break; default: assert(0); break; } if (match) selection->atom[i] = 1; count += match; } if (count == 0) freesasa_warn("Found no matches to %s '%s', typo?", e_str(parent_type),id); }
/** Add atom to residue. Returns index of the new atom on success. FREESASA_FAIL if memory allocation fails. FREESASA_WARN if the atom has already been added. */ static int add_atom(struct classifier_residue *res, const char *name, double radius, int the_class) { int n; char **an = res->atom_name; double *ar = res->atom_radius; int *ac = res->atom_class; if (find_string(res->atom_name, name, res->n_atoms) >= 0) return freesasa_warn("in %s(): Ignoring duplicate entry for atom '%s %s'", __func__, res->name, name); n = res->n_atoms+1; if ((res->atom_name = realloc(res->atom_name,sizeof(char*)*n)) == NULL) { res->atom_name = an; return mem_fail(); } if ((res->atom_radius = realloc(res->atom_radius,sizeof(double)*n)) == NULL) { res->atom_radius = ar; return mem_fail(); } if ((res->atom_class = realloc(res->atom_class,sizeof(int)*n)) == NULL) { res->atom_class = ac; return mem_fail(); } if ((res->atom_name[n-1] = strdup(name)) == NULL) return mem_fail(); ++res->n_atoms; res->atom_radius[n-1] = radius; res->atom_class[n-1] = the_class; return n-1; }
static int select_area_impl(const char *command, char *name, double *area, const freesasa_structure *structure, const freesasa_result *result) { struct selection *selection = NULL; struct expression *expression = NULL; const int maxlen = FREESASA_MAX_SELECTION_NAME; double sasa = 0; int err = 0, warn = 0, n_atoms = 0, j, len; assert(name); assert(area); assert(command); assert(structure); assert(result); assert(freesasa_structure_n(structure) == result->n_atoms); *area = 0; name[0] = '\0'; expression = get_expression(command); selection = selection_new(result->n_atoms); if (selection == NULL) { return fail_msg(""); } if (expression != NULL && selection != NULL) { switch (select_atoms(selection, expression, structure)) { case FREESASA_FAIL: err = 1; break; case FREESASA_WARN: warn = 1; /* proceed with calculation, print warning later */ case FREESASA_SUCCESS: { for (j = 0; j < selection->size; ++j) { ++n_atoms; sasa += selection->atom[j]*result->sasa[j]; } *area = sasa; len = strlen(selection->name); if (len > maxlen) { strncpy(name,selection->name,maxlen); name[maxlen] = '\0'; } else { strncpy(name,selection->name,len); name[len] = '\0'; } break; } default: assert(0); } } else { err = 1; } selection_free(selection); expression_free(expression); if (err) return fail_msg("problems parsing expression '%s'",command); if (warn) return freesasa_warn("in %s(): There were warnings",__func__); return n_atoms; }
static int is_valid_id(int parent_type, const expression *expr) { int type, n, warn, i; const char* val; assert(expr->type == E_NUMBER || expr->type == E_ID); type = expr->type; val = expr->value; switch(parent_type) { case E_NAME: if (strlen(val) > PDB_ATOM_NAME_STRL) return freesasa_warn("select: %s: atom name '%s' invalid (string too long), " "will be ignored", e_str(parent_type), val); break; case E_SYMBOL: if (type != E_ID) return freesasa_warn("select: %s: '%s' invalid (should be 1 or 2 letters, 'C', 'N', 'SE', etc), " "will be ignored", e_str(parent_type), val); if (strlen(val) > 2) return freesasa_warn("select: %s: '%s' invalid (element names have 1 or 2 characters), " "will be ignored", e_str(parent_type), val); break; case E_RESN: if (strlen(val) > PDB_ATOM_RES_NAME_STRL) return freesasa_warn("select: %s: '%s' invalid (string too long), " "will be ignored", e_str(parent_type), val); break; case E_RESI: if (type == E_ID) { /* these should have format 1, 2, 345, etc or 12A, 12B, etc. */ n = strlen(val); if (n > PDB_ATOM_RES_NUMBER_STRL) { return freesasa_warn("select: %s: '%s' invalid (string too long), " "will be ignored", e_str(parent_type), val); } else { warn = 0; if (n == 1) ++warn; if (!warn && (toupper(val[n - 1]) < 'A' || toupper(val[n - 1]) > 'Z')) { ++warn; } for (i = 0; !warn && i < n - 1; ++i) { if (val[i] < '0' || val[i] > '9') { ++warn; } } if (warn) { return freesasa_warn("select: %s: '%s' invalid, should either be " "number (1, 2, 3) or number with insertion code (1A, 1B, ...), " "will be ignored", e_str(parent_type), val); } } } else if (type != E_NUMBER) { return freesasa_warn("select: %s: '%s' invalid, will be ignored", e_str(parent_type), val); } break; case E_CHAIN: if (strlen(val) > 1) return freesasa_warn("select: %s: '%s' invalid (string too long), " "will be ignored", e_str(parent_type), val); break; default: assert(0); break; } return FREESASA_SUCCESS; }