jfaustin's picture
secretion-scores (#4)
a3f3d91 verified
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#include <errno.h>
#include "classifier.h"
#include "freesasa_internal.h"
#define STD_CLASSIFIER_NAME "no-name-given"
/**
In this file the concept class refers to polar/apolar and type to
aliphatic/aromatic/etc. See the example configurations in share/.
*/
static const struct classifier_types empty_types = {0, NULL, NULL, NULL};
static const struct classifier_residue empty_residue = {0, NULL, NULL, NULL, NULL, {NULL, 0, 0, 0, 0, 0}};
static const struct freesasa_classifier empty_config = {0, NULL, NULL, NULL};
struct classifier_types*
freesasa_classifier_types_new()
{
struct classifier_types *t = malloc(sizeof(struct classifier_types));
if (t == NULL) mem_fail();
else *t = empty_types;
return t;
}
void
freesasa_classifier_types_free(struct classifier_types* t)
{
if (t != NULL) {
free(t->type_radius);
free(t->type_class);
if (t->name)
for (int i = 0; i < t->n_types; ++i)
free(t->name[i]);
free(t->name);
free(t);
}
}
struct classifier_residue*
freesasa_classifier_residue_new(const char* name)
{
assert(strlen(name) > 0);
struct classifier_residue *res = malloc(sizeof(struct classifier_residue));
if (res == NULL) mem_fail();
else {
*res = empty_residue;
res->name = strdup(name);
if (res->name == NULL) {
mem_fail();
free(res);
res = NULL;
}
}
return res;
}
void
freesasa_classifier_residue_free(struct classifier_residue* res)
{
if (res != NULL) {
free(res->name);
if (res->atom_name)
for (int i = 0; i < res->n_atoms; ++i)
free(res->atom_name[i]);
free(res->atom_name);
free(res->atom_radius);
free(res->atom_class);
free(res);
}
}
freesasa_classifier *
freesasa_classifier_new()
{
struct freesasa_classifier *cfg = malloc(sizeof(struct freesasa_classifier));
if (cfg == NULL) mem_fail();
else *cfg = empty_config;
return cfg;
}
void
freesasa_classifier_free(freesasa_classifier *c)
{
if (c != NULL) {
if (c->residue)
for (int i = 0; i < c->n_residues; ++i)
freesasa_classifier_residue_free(c->residue[i]);
free(c->residue);
free(c->residue_name);
free(c->name);
free(c);
}
}
//! check if array of strings has a string that matches key, ignores trailing and leading whitespace
static int
find_string(char **array,
const char *key,
int array_size)
{
assert(key);
if (array == NULL || array_size == 0) return -1;
int n = strlen(key);
char key_trimmed[n+1];
// remove trailing and leading whitespace
sscanf(key,"%s",key_trimmed);
for (int i = 0; i < array_size; ++i) {
assert(array[i]);
if (strcmp(array[i],key_trimmed) == 0) return i;
}
return FREESASA_FAIL;
}
/**
Removes comments and strips leading and trailing
whitespace. Returns the length of the stripped line on success,
FREESASA_FAIL if malloc/realloc fails.
*/
static int
strip_line(char **line,
const char *input)
{
int n = strlen(input);
char linebuf[n+1];
char *comment, *first, *last, *tmp;
strncpy(linebuf, input, strlen(input)+1);
comment = strchr(linebuf, '#');
if (comment) *comment = '\0'; // skip comments
first = linebuf;
last = linebuf + strlen(linebuf) - 1;
while (*first == ' ' || *first == '\t') ++first;
if (last > first)
while (*last == ' ' || *last == '\t' || *last == '\n') --last;
tmp = realloc(*line,strlen(first)+1);
if (tmp == NULL) {
free(*line);
*line = NULL;
return mem_fail();
}
*line = tmp;
if (first >= last) {
**line = '\0';
return 0;
}
*(last+1) = '\0';
strcpy(*line, first);
return strlen(*line);
}
/**
Essentially a safer fscanf(input, "%s", str) on the next line in input.
*/
static int
get_next_string(FILE *input, char **str)
{
char *line = NULL;
size_t len;
long pos = ftell(input);
if (getline(&line, &len, input) < 0)
return 0;
*str = malloc(len + 1);
if (*str == NULL) {
free(line);
return mem_fail();
}
*str[0] = '\0';
sscanf(line, "%s", *str);
fseek(input, pos + strlen(*str), SEEK_SET);
return strlen(*str);
}
/**
Stores a line stripped of comments in the provided string. Returns
the length of the line on success, FREESASA_FAIL if malloc/realloc
errors.
*/
static int
next_line(char **line,
FILE *fp)
{
char *linebuf = NULL;
size_t len = 0;
int ret;
ret = getline(&linebuf, &len, fp);
if (ret >= 0) ret = strip_line(line, linebuf);
else ret = FREESASA_FAIL;
free(linebuf);
return ret;
}
/**
Find offset of str in line, returns -1 if not found
Ignores comments
*/
static inline int
locate_string(const char *line,
const char *str)
{
assert(line);
assert(str);
int NOT_FOUND = -1;
size_t len = strlen(line) + 1;
char buf[len], *loc;
if (len == 0) {
return NOT_FOUND;
}
strcpy(buf, line);
// skip comments
loc = strstr(buf, "#");
if (loc == buf) {
return NOT_FOUND;
} else if (loc != NULL) {
*loc = '\0';
}
loc = strstr(buf, str);
if (loc != NULL) {
return loc - buf;
}
return NOT_FOUND;
}
/**
If string exists on line its location is stored in this_range, and
if prev_range is non-null it is set to and at the same location.
*/
static inline int
try_register_stringloc(const char *line,
const char *str,
long last_tell,
struct file_range *this_range,
struct file_range **prev_range)
{
int pos, NOT_FOUND = -1;
if (strlen(line) == 0) return NOT_FOUND;
pos = locate_string(line, str);
if (pos >= 0) {
this_range->begin = last_tell + pos;
if (*prev_range) (*prev_range)->end = last_tell + pos;
(*prev_range) = this_range;
return last_tell + pos;
}
return NOT_FOUND;
}
/**
Checks that input file has the required fields and locates the
'types' and 'atoms' sections. No syntax checking. Return
FREESASA_SUCCESS if file seems ok, FREESASA_FILE if either/both of
the sections are missing.
*/
static int
check_file(FILE *input,
struct file_range *types,
struct file_range *atoms,
struct file_range *name)
{
assert(input); assert(types); assert(atoms);
long last_tell;
size_t len = 0;
char *line = NULL;
struct file_range *last_range = NULL;
last_tell = ftell(input);
types->begin = atoms->begin = name->begin = -1;
while (getline(&line, &len, input) >= 0) {
try_register_stringloc(line, "types:", last_tell, types, &last_range);
try_register_stringloc(line, "atoms:", last_tell, atoms, &last_range);
try_register_stringloc(line, "name:", last_tell, name, &last_range);
last_tell = ftell(input);
}
free(line);
if (last_range != NULL) {
last_range->end = last_tell;
}
rewind(input);
if (name->begin == -1) {
freesasa_warn("input configuration lacks the entry 'name:', "
"will use '" STD_CLASSIFIER_NAME "'");
}
if ((types->begin == -1) ||
(atoms->begin == -1)) {
return fail_msg("input configuration lacks (at least) one of "
"the entries 'types:' or 'atoms:'");
}
return FREESASA_SUCCESS;
}
int
freesasa_classifier_parse_class(const char *name)
{
#if HAVE_STRNCASECMP
if (strncasecmp(name, "apolar", 6) == 0) {
return FREESASA_ATOM_APOLAR;
} else if (strncasecmp(name, "polar", 5) == 0) {
return FREESASA_ATOM_POLAR;
} else {
return fail_msg("only atom classes allowed are 'polar' and 'apolar'"
" (case insensitive)");
}
#else
if (strncmp(name, "apolar", 6) == 0) {
return FREESASA_ATOM_APOLAR;
} else if (strncmp(name, "polar", 5) == 0) {
return FREESASA_ATOM_POLAR;
} else {
return fail_msg("only atom classes allowed are 'polar' and 'apolar'");
}
#endif
}
/**
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).
*/
int
freesasa_classifier_add_type(struct classifier_types *types,
const char *type_name,
const char *class_name,
double r)
{
int the_class;
int n = types->n_types + 1;
char **tn = types->name;
double *tr = types->type_radius;
freesasa_atom_class *tc = types->type_class;
if (find_string(types->name, type_name, types->n_types) >= 0)
return freesasa_warn("ignoring duplicate configuration entry for '%s'", type_name);
the_class = freesasa_classifier_parse_class(class_name);
if (the_class == FREESASA_FAIL) return fail_msg("");
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;
}
/**
Read a line specifying a type, store it in the config. Returns
warning for duplicates, failures for syntax errors or memory
allocation errors.
*/
static int
read_types_line(struct classifier_types *types,
const char* line)
{
size_t blen = strlen(line) + 1;
char buf1[blen], buf2[blen];
int the_type;
double r;
if (sscanf(line,"%s %lf %s",buf1,&r,buf2) == 3) {
the_type = freesasa_classifier_add_type(types, buf1, buf2, r);
if (the_type == FREESASA_FAIL) return fail_msg("");
if (the_type == FREESASA_WARN) return FREESASA_WARN;
} else {
return fail_msg("could not parse line '%s' in configuration, "
"expecting triplet of type 'TYPE [RADIUS] CLASS' for "
"example 'C_ALI 2.00 apolar'", line);
}
return FREESASA_SUCCESS;
}
/**
Reads info about types from the user config. Associates each type
with a class and a radius in the config struct. Returns
FREESASA_SUCCESS on success, FREESASA_FAIL on syntax or memory
allocation errors.
*/
static int
read_types(struct classifier_types *types,
FILE *input,
struct file_range fi)
{
char *line = NULL;
int ret = FREESASA_SUCCESS, nl;
fseek(input, fi.begin, SEEK_SET);
// read command (and discard)
if (next_line(&line, input) > 0) {
size_t blen=strlen(line) + 1;
char buf[blen];
if (sscanf(line, "%s", buf) == 0) return FREESASA_FAIL;
assert(strcmp(buf, "types:") == 0);
} else {
return FREESASA_FAIL;
}
while (ftell(input) < fi.end) {
nl = next_line(&line,input);
if (nl == 0) continue;
if (nl == FREESASA_FAIL) {ret = nl; break; };
ret = read_types_line(types,line);
if (ret == FREESASA_FAIL) break;
}
free(line);
return ret;
}
/**
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.
*/
int
freesasa_classifier_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;
freesasa_atom_class *ac = res->atom_class;
if (find_string(res->atom_name, name, res->n_atoms) >= 0)
return freesasa_warn("ignoring duplicate configuration entry for atom '%s %s'",
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;
}
/**
Add residue to config. If the residue already exists, it returns
the index of that residue, else it returns the index of the new
residue. Returns FREESASA_FAILURE if realloc/strdup fails.
*/
int
freesasa_classifier_add_residue(struct freesasa_classifier *c,
const char* name)
{
char **rn = c->residue_name;
struct classifier_residue **cr = c->residue;
int res = find_string(c->residue_name, name, c->n_residues);
if (res >= 0) return res;
res = c->n_residues + 1;
if ((c->residue_name = realloc(rn, sizeof(char*) * res)) == NULL) {
c->residue_name = rn;
return mem_fail();
}
if ((c->residue = realloc(cr, sizeof(struct classifier_residue *) * res)) == NULL) {
c->residue = cr;
return mem_fail();
}
if ((c->residue[res-1] = freesasa_classifier_residue_new(name)) == NULL) {
return mem_fail();
}
++c->n_residues;
c->residue_name[res-1] = c->residue[res-1]->name;
return res-1;
}
/**
Read a line specifying an atom, store it in the config. Use
supplied types to add assign radius and class. Returns
FREESASA_WARN for duplicates. Returns FREESASA_FAIL for syntax
errors or memory allocation errors. FREESASA_SUCCESS else.
*/
static int
read_atoms_line(struct freesasa_classifier *c,
const struct classifier_types *types,
const char* line)
{
size_t blen = strlen(line) + 1;
char buf1[blen], buf2[blen], buf3[blen];
int res, type, atom;
if (sscanf(line,"%s %s %s",buf1,buf2,buf3) == 3) {
type = find_string(types->name, buf3, types->n_types);
if (type < 0)
return fail_msg("unknown atom type '%s' in configuration, line '%s'",
buf3, line);
res = freesasa_classifier_add_residue(c, buf1);
if (res == FREESASA_FAIL) return fail_msg("");
atom = freesasa_classifier_add_atom(c->residue[res],
buf2,
types->type_radius[type],
types->type_class[type]);
if (atom == FREESASA_FAIL) return fail_msg("");
if (atom == FREESASA_WARN) return FREESASA_WARN;
} else {
return fail_msg("could not parse configuration, line '%s', "
"expecting triplet of type "
"'RESIDUE ATOM CLASS', for example 'ALA CB C_ALI'",
line);
}
return FREESASA_SUCCESS;
}
/**
Reads atom configurations from config-file. Associates each atom
with a radius and class using the types that should already have
been stored in the config struct.
*/
static int
read_atoms(struct freesasa_classifier *c,
struct classifier_types *types,
FILE *input,
struct file_range fi)
{
char *line = NULL;
int ret = FREESASA_SUCCESS, nl;
fseek(input, fi.begin, SEEK_SET);
// read command (and discard)
if (next_line(&line, input) > 0) {
size_t blen = strlen(line) + 1;
char buf[blen];
if (sscanf(line, "%s", buf) == 0) return FREESASA_FAIL;
assert(strcmp(buf, "atoms:") == 0);
} else {
return FREESASA_FAIL;
}
while (ftell(input) < fi.end) {
nl = next_line(&line, input);
if (nl == 0) continue;
if (nl == FREESASA_FAIL) return fail_msg("");
ret = read_atoms_line(c, types, line);
if (ret == FREESASA_FAIL) break;
}
free(line);
return ret;
}
static int
read_name(struct freesasa_classifier *classifier,
FILE *input,
struct file_range fi)
{
char *buf = NULL, *line = NULL;
int ret = FREESASA_FAIL;
if (fi.begin < 0)
return FREESASA_SUCCESS;
fseek(input, fi.begin, SEEK_SET);
if (get_next_string(input, &buf) <= 0)
goto cleanup;
assert(strcmp(buf, "name:") == 0);
if (get_next_string(input, &buf) <= 0) {
fail_msg("empty name for configuration?");
goto cleanup;
}
classifier->name = strdup(buf);
if (classifier->name == NULL) {
mem_fail();
goto cleanup;
}
ret = FREESASA_SUCCESS;
cleanup:
free(buf);
free(line);
return ret;
}
static struct freesasa_classifier*
read_config(FILE *input)
{
assert(input);
struct file_range types_section, atoms_section, name_section;
struct freesasa_classifier *classifier = NULL;
struct classifier_types *types = NULL;
if (!(types = freesasa_classifier_types_new()))
goto cleanup;
if (!(classifier = freesasa_classifier_new()))
goto cleanup;
if (check_file(input, &types_section, &atoms_section, &name_section))
goto cleanup;
if (read_name(classifier, input, name_section))
goto cleanup;
if (read_types(types, input, types_section))
goto cleanup;
if (read_atoms(classifier, types, input, atoms_section))
goto cleanup;
freesasa_classifier_types_free(types);
return classifier;
cleanup:
freesasa_classifier_free(classifier);
freesasa_classifier_types_free(types);
return NULL;
}
/**
See if an atom_name has been defined for the residue ANY (writes
indices to the provided pointers).
*/
static void
find_any(const struct freesasa_classifier *c,
const char *atom_name,
int *res, int *atom)
{
*res = find_string(c->residue_name,"ANY",c->n_residues);
if (*res >= 0) {
*atom = find_string(c->residue[*res]->atom_name,
atom_name,
c->residue[*res]->n_atoms);
}
}
/**
Find the residue and atom index of an atom in the supplied
configuration. Prints error and returns FREESASA_WARN if not
found.
*/
static int
find_atom(const struct freesasa_classifier *c,
const char *res_name,
const char *atom_name,
int* res,
int* atom)
{
*atom = -1;
*res = find_string(c->residue_name, res_name, c->n_residues);
if (*res < 0) {
find_any(c, atom_name, res, atom);
} else {
const struct classifier_residue *residue = c->residue[*res];
*atom = find_string(residue->atom_name, atom_name, residue->n_atoms);
if (*atom < 0) {
find_any(c, atom_name, res, atom);
}
}
if (*atom < 0) {
return FREESASA_WARN;
}
return FREESASA_SUCCESS;
}
double
freesasa_classifier_radius(const freesasa_classifier *classifier,
const char *res_name,
const char *atom_name)
{
assert(classifier); assert(res_name); assert(atom_name);
int res, atom, status;
status = find_atom(classifier, res_name, atom_name, &res,&atom);
if (status == FREESASA_SUCCESS)
return classifier->residue[res]->atom_radius[atom];
return -1.0;
}
freesasa_atom_class
freesasa_classifier_class(const freesasa_classifier *classifier,
const char *res_name,
const char *atom_name)
{
assert(classifier); assert(res_name); assert(atom_name);
int res, atom, status;
status = find_atom(classifier, res_name, atom_name, &res, &atom);
if (status == FREESASA_SUCCESS)
return classifier->residue[res]->atom_class[atom];
return FREESASA_ATOM_UNKNOWN;
}
const char*
freesasa_classifier_class2str(freesasa_atom_class atom_class)
{
switch (atom_class) {
case FREESASA_ATOM_APOLAR:
return "Apolar";
case FREESASA_ATOM_POLAR:
return "Polar";
case FREESASA_ATOM_UNKNOWN:
return "Unknown";
}
fail_msg("invalid atom class");
return NULL;
}
freesasa_nodearea
freesasa_result_classes(const freesasa_structure *structure,
const freesasa_result *result)
{
freesasa_nodearea area = {"whole-structure", 0, 0, 0, 0, 0};
freesasa_range_nodearea(&area, structure, result,
0, freesasa_structure_n(structure) - 1);
return area;
}
freesasa_classifier*
freesasa_classifier_from_file(FILE *file)
{
struct freesasa_classifier *classifier = read_config(file);
if (classifier == NULL) {
fail_msg("");
return NULL;
}
return classifier;
}
const freesasa_nodearea *
freesasa_classifier_residue_reference(const freesasa_classifier *classifier,
const char *res_name)
{
int res = find_string(classifier->residue_name, res_name, classifier->n_residues);
if (res < 0) return NULL;
return &classifier->residue[res]->max_area;
}
const char*
freesasa_classifier_name(const freesasa_classifier *classifier)
{
return classifier->name;
}
struct symbol_radius {
const char symbol[3];
double radius;
};
/* Taken from:
Mantina et al. "Consistent van der Waals Radii for
the Whole Main Group". J. Phys. Chem. A, 2009, 113 (19), pp
5806–5812.
Many of these elements, if they occur in a PDB file, should
probably rather be skipped than used in a SASA calculation, and
ionization will change the effective radius.
*/
static const struct symbol_radius symbol_radius[] = {
// elements that actually occur in the regular amino acids and nucleotides
{" H", 1.10}, {" C", 1.70}, {" N", 1.55}, {" O", 1.52}, {" P", 1.80}, {" S", 1.80}, {"SE", 1.90},
// some others, just because there were readily available values
{" F", 1.47}, {"CL", 1.75}, {"BR", 1.83}, {" I", 1.98},
{"LI", 1.81}, {"BE", 1.53}, {" B", 1.92},
{"NA", 2.27}, {"MG", 1.74}, {"AL", 1.84}, {"SI", 2.10},
{" K", 2.75}, {"CA", 2.31}, {"GA", 1.87}, {"GE", 2.11}, {"AS", 1.85},
{"RB", 3.03}, {"SR", 2.49}, {"IN", 1.93}, {"SN", 2.17}, {"SB", 2.06}, {"TE", 2.06},
};
double
freesasa_guess_radius(const char* symbol)
{
assert(symbol);
int n_symbol = sizeof(symbol_radius)/sizeof(struct symbol_radius);
for (int i = 0; i < n_symbol; ++i) {
if (strcmp(symbol,symbol_radius[i].symbol) == 0)
return symbol_radius[i].radius;
}
return -1.0;
}
//! The residue types that are returned by freesasa_classify_residue()
enum residue {
//Regular amino acids
ALA=0, ARG, ASN, ASP,
CYS, GLN, GLU, GLY,
HIS, ILE, LEU, LYS,
MET, PHE, PRO, SER,
THR, TRP, TYR, VAL,
//some non-standard ones
CSE, SEC, PYL, PYH,
ASX, GLX,
//residue unknown
RES_UNK,
//capping N- and C-terminal groups (usually HETATM)
ACE, NH2,
//DNA
DA, DC, DG, DT,
DU, DI,
//RNA (avoid one-letter enums)
RA, RC, RG, RU, RI, RT,
//generic nucleotide
NN
};
// Residue types, make sure this always matches the corresponding enum.
static const char *residue_names[] = {
//amino acids
"ALA","ARG","ASN","ASP",
"CYS","GLN","GLU","GLY",
"HIS","ILE","LEU","LYS",
"MET","PHE","PRO","SER",
"THR","TRP","TYR","VAL",
// non-standard amino acids
"CSE","SEC","PYL","PYH", // SEC and PYL are standard names, CSE and PYH are found in some early files
"ASX","GLX",
"UNK",
// capping groups
"ACE","NH2",
//DNA
"DA","DC","DG","DT","DU","DI",
//RNA
"A","C","G","U","I","T",
//General nucleotide
"N"
};
int
freesasa_classify_n_residue_types()
{
return NN+1;
}
int
freesasa_classify_residue(const char *res_name)
{
int len = strlen(res_name);
char cpy[len+1];
sscanf(res_name, "%s", cpy);
for (int i = ALA; i < freesasa_classify_n_residue_types(); ++i) {
if (strcmp(cpy,residue_names[i]) == 0) return i;
}
return RES_UNK;
}
const char *
freesasa_classify_residue_name(int residue_type)
{
assert(residue_type >= 0 && residue_type <= NN);
return residue_names[residue_type];
}
int
freesasa_atom_is_backbone(const char *atom_name)
{
int n = strlen(atom_name);
char name[n+1];
name[0] = '\0';
sscanf(atom_name, "%s", name); //trim whitespace
const char *bb[] = {"CA", "N", "O", "C", "OXT",
"P", "OP1", "OP2", "O5'", "C5'", "C4'",
"O4'", "C3'", "O3'", "C2'", "C1'"};
if (strlen(name) == 0) return 0;
for (int i = 0; i < sizeof(bb)/sizeof(const char*); ++i) {
if (strcmp(name, bb[i]) == 0) {
return 1;
}
}
return 0;
}
#if USE_CHECK
#include <check.h>
#include <math.h>
START_TEST (test_classifier)
{
struct classifier_types *types = freesasa_classifier_types_new();
struct classifier_residue *residue_cfg = freesasa_classifier_residue_new("ALA");
struct freesasa_classifier *clf = freesasa_classifier_new();
freesasa_set_verbosity(FREESASA_V_SILENT);
ck_assert_int_eq(freesasa_classifier_parse_class("A"), FREESASA_FAIL);
#if HAVE_STRNCASECMP
ck_assert_int_eq(freesasa_classifier_parse_class("POLAR"), FREESASA_ATOM_POLAR);
ck_assert_int_eq(freesasa_classifier_parse_class("APOLAR"), FREESASA_ATOM_APOLAR);
#endif
ck_assert_int_eq(freesasa_classifier_parse_class("polar"), FREESASA_ATOM_POLAR);
ck_assert_int_eq(freesasa_classifier_parse_class("apolar"), FREESASA_ATOM_APOLAR);
ck_assert_int_eq(types->n_types, 0);
ck_assert_int_eq(freesasa_classifier_add_type(types,"a","A",1.0),FREESASA_FAIL);
ck_assert_int_eq(freesasa_classifier_add_type(types,"a","polar",1.0),0);
ck_assert_int_eq(freesasa_classifier_add_type(types,"b","apolar",2.0),1);
ck_assert_int_eq(freesasa_classifier_add_type(types,"b","polar",1.0),FREESASA_WARN);
ck_assert_int_eq(freesasa_classifier_add_type(types,"c","apolar",3.0),2);
ck_assert_int_eq(types->n_types,3);
ck_assert_str_eq(types->name[0],"a");
ck_assert_str_eq(types->name[1],"b");
ck_assert_str_eq(types->name[2],"c");
ck_assert(fabs(types->type_radius[0]-1.0) < 1e-10);
ck_assert(fabs(types->type_radius[1]-2.0) < 1e-10);
ck_assert(fabs(types->type_radius[2]-3.0) < 1e-10);
freesasa_classifier_types_free(types);
types = freesasa_classifier_types_new();
ck_assert_int_eq(read_types_line(types,""),FREESASA_FAIL);
ck_assert_int_eq(read_types_line(types,"a"),FREESASA_FAIL);
ck_assert_int_eq(read_types_line(types,"a 1.0"),FREESASA_FAIL);
ck_assert_int_eq(read_types_line(types,"a b C"),FREESASA_FAIL);
ck_assert_int_eq(read_types_line(types,"a 1.0 C"),FREESASA_FAIL);
ck_assert_int_eq(read_types_line(types,"a 1.0 apolar"),FREESASA_SUCCESS);
ck_assert_int_eq(read_types_line(types,"b 2.0 polar"),FREESASA_SUCCESS);
ck_assert_int_eq(types->n_types,2);
ck_assert_str_eq(types->name[0],"a");
ck_assert_str_eq(types->name[1],"b");
ck_assert(fabs(types->type_radius[0]-1.0) < 1e-10);
ck_assert(fabs(types->type_radius[1]-2.0) < 1e-10);
ck_assert_int_eq(freesasa_classifier_add_atom(residue_cfg,"C",1.0,0),0);
ck_assert_int_eq(freesasa_classifier_add_atom(residue_cfg,"CB",2.0,0),1);
ck_assert_int_eq(freesasa_classifier_add_atom(residue_cfg,"CB",2.0,0),FREESASA_WARN);
ck_assert_str_eq(residue_cfg->atom_name[0],"C");
ck_assert_str_eq(residue_cfg->atom_name[1],"CB");
ck_assert(fabs(residue_cfg->atom_radius[0]-1.0) < 1e-10);
ck_assert(fabs(residue_cfg->atom_radius[1]-2.0) < 1e-10);
freesasa_classifier_residue_free(residue_cfg);
ck_assert_int_eq(freesasa_classifier_add_residue(clf,"A"),0);
ck_assert_int_eq(freesasa_classifier_add_residue(clf,"B"),1);
ck_assert_int_eq(freesasa_classifier_add_residue(clf,"B"),1);
ck_assert_int_eq(clf->n_residues,2);
ck_assert_str_eq(clf->residue_name[0],"A");
ck_assert_str_eq(clf->residue_name[1],"B");
ck_assert_str_eq(clf->residue[0]->name,"A");
freesasa_classifier_free(clf);
clf = freesasa_classifier_new();
ck_assert_int_eq(read_atoms_line(clf,types,"A A"),FREESASA_FAIL);
ck_assert_int_eq(read_atoms_line(clf,types,"A A bla"),FREESASA_FAIL);
ck_assert_int_eq(read_atoms_line(clf,types,"ALA CA a"),FREESASA_SUCCESS);
ck_assert_int_eq(read_atoms_line(clf,types,"ALA CB b"),FREESASA_SUCCESS);
ck_assert_int_eq(read_atoms_line(clf,types,"ARG CA a"),FREESASA_SUCCESS);
ck_assert_int_eq(read_atoms_line(clf,types,"ARG CB b"),FREESASA_SUCCESS);
ck_assert_int_eq(read_atoms_line(clf,types,"ARG CG b"),FREESASA_SUCCESS);
ck_assert_int_eq(clf->n_residues,2);
ck_assert_str_eq(clf->residue_name[0],"ALA");
ck_assert_str_eq(clf->residue_name[1],"ARG");
ck_assert_int_eq(clf->residue[0]->n_atoms,2);
ck_assert_str_eq(clf->residue[0]->atom_name[0],"CA");
ck_assert_str_eq(clf->residue[0]->atom_name[1],"CB");
ck_assert(fabs(clf->residue[0]->atom_radius[0]-1.0) < 1e-5);
ck_assert(fabs(clf->residue[0]->atom_radius[1]-2.0) < 1e-5);
freesasa_classifier_free(clf);
freesasa_classifier_types_free(types);
freesasa_set_verbosity(FREESASA_V_NORMAL);
}
END_TEST
START_TEST (test_classifier_utils)
{
const char *strarr[] = {"A","B","C"};
const char *line[] = {"# Bla"," # Bla","Bla # Bla"," Bla # Bla","#Bla #Alb"};
char *dummy_str = NULL;
ck_assert_int_eq(find_string((char**)strarr,"A",3),0);
ck_assert_int_eq(find_string((char**)strarr,"B",3),1);
ck_assert_int_eq(find_string((char**)strarr,"C",3),2);
ck_assert_int_eq(find_string((char**)strarr,"D",3),-1);
ck_assert_int_eq(find_string((char**)strarr," C ",3),2);
ck_assert_int_eq(find_string((char**)strarr,"CC",3),-1);
ck_assert_int_eq(strip_line(&dummy_str,line[0]),0);
ck_assert_int_eq(strip_line(&dummy_str,line[1]),0);
ck_assert_int_eq(strip_line(&dummy_str,line[2]),3);
ck_assert_str_eq(dummy_str,"Bla");
ck_assert_int_eq(strip_line(&dummy_str,line[3]),3);
ck_assert_str_eq(dummy_str,"Bla");
ck_assert_int_eq(strip_line(&dummy_str,line[4]),0);
const char *str = "foo bar # baz";
ck_assert_int_eq(locate_string(str, "Foo"), -1);
ck_assert_int_eq(locate_string(str, "foo"), 0);
ck_assert_int_eq(locate_string(str, "bar"), 4);
ck_assert_int_eq(locate_string(str, "baz"), -1);
ck_assert_int_eq(locate_string(str, "ar"), 5);
struct file_range this_range, *last_range = NULL;
ck_assert_int_eq(try_register_stringloc(str, "foo", 0, &this_range, &last_range), 0);
ck_assert_int_eq(this_range.begin, 0);
ck_assert_ptr_eq(last_range, &this_range);
ck_assert_int_eq(try_register_stringloc(str, "bar", 0, &this_range, &last_range), 4);
ck_assert_ptr_eq(last_range, &this_range);
ck_assert_int_eq(last_range->end, 4);
ck_assert_int_eq(try_register_stringloc(str, "baz", 0, &this_range, &last_range), -1);
free(dummy_str);
}
END_TEST
TCase *
test_classifier_static()
{
TCase *tc = tcase_create("classifier.c static");
tcase_add_test(tc, test_classifier);
tcase_add_test(tc, test_classifier_utils);
return tc;
}
#endif // USE_CHECK