From b7c16400424b66761119af9db365eb9fac6c185c Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 13 May 2009 06:51:25 +0000 Subject: [PATCH] New version 0.3 with filtering on short words git-svn-id: https://www.grenoble.prabi.fr/svn/LECASofts/ecoPrimers/trunk@213 60f365c0-8329-0410-b2a4-ec073aeeaa1d --- VERSION | 2 +- src/ecoPrimer | Bin 0 -> 63248 bytes src/ecoprimer.c | 26 ++++- src/libecoPCR/ecoMalloc.c | 4 +- src/libecoprimer/Makefile | 3 +- src/libecoprimer/ecoprimer.h | 20 +++- src/libecoprimer/filtering.c | 183 +++++++++++++++++++++++++++++++ src/libecoprimer/hashencoder.h | 21 ++++ src/libecoprimer/hashsequence.c | 57 ++++++++-- src/libecoprimer/merge.c | 14 ++- src/libecoprimer/strictprimers.c | 31 ++++-- src/libecoprimer/taxstats.c | 3 +- 12 files changed, 330 insertions(+), 34 deletions(-) create mode 100755 src/ecoPrimer create mode 100644 src/libecoprimer/filtering.c create mode 100644 src/libecoprimer/hashencoder.h diff --git a/VERSION b/VERSION index 3b04cfb..be58634 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2 +0.3 diff --git a/src/ecoPrimer b/src/ecoPrimer new file mode 100755 index 0000000000000000000000000000000000000000..336288c7f6e5f4e29a1f26520c8c6a129bfbc556 GIT binary patch literal 63248 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 E0Il+(=>Px# literal 0 HcmV?d00001 diff --git a/src/ecoprimer.c b/src/ecoprimer.c index a10e25a..3483031 100644 --- a/src/ecoprimer.c +++ b/src/ecoprimer.c @@ -14,7 +14,7 @@ #include #include -#define VERSION "0.2" +#define VERSION "0.3" /* TR: by default, statistics are made on species level*/ #define DEFAULTTAXONRANK "species" @@ -98,6 +98,7 @@ static void ExitUsage(int stat) void initoptions(poptions_t options) { options->statistics=FALSE; + options->filtering=TRUE; options->lmin=0; //< Amplifia minimal length options->lmax=1000; //< Amplifia maximal length options->error_max=3; //**< maximum error count in fuzzy search @@ -432,6 +433,7 @@ int main(int argc, char **argv) uint32_t i; pwordcount_t words; +// pwordcount_t words2; pprimercount_t primers; ppairtree_t pairs; @@ -442,7 +444,7 @@ int main(int argc, char **argv) initoptions(&options); - while ((carg = getopt(argc, argv, "hvcUDSd:l:L:e:i:r:q:3:s:x:t:O:")) != -1) { + while ((carg = getopt(argc, argv, "hfvcUDSd:l:L:e:i:r:q:3:s:x:t:O:")) != -1) { switch (carg) { /* ---------------------------- */ @@ -451,6 +453,12 @@ int main(int argc, char **argv) options.statistics=TRUE; break; + /* ---------------------------- */ + case 'f': /* set in single strand mode */ + /* ---------------------------- */ + options.filtering=FALSE; + break; + /* -------------------- */ case 'd': /* database name */ /* -------------------- */ @@ -599,12 +607,20 @@ int main(int argc, char **argv) fprintf(stderr,"\nIndexing words in sequences\n"); - printcurrenttimeinmilli(); words = lookforStrictPrimer(seqdb,seqdbsize,insamples,&options); - printcurrenttimeinmilli(); - fprintf(stderr,"\n Strict primer count : %d\n",words->size); +// options.filtering=FALSE; +// words2= lookforStrictPrimer(seqdb,seqdbsize,insamples,&options); +// fprintf(stderr,"\n Strict primer count : %d\n",words2->size); +// +// fprintf(stderr,"\n\n Primer sample : \n"); +// for (i=0; isize; i++) +// fprintf(stderr," + Primer : %s sequence count : %d\n",ecoUnhashWord(words->words[i],options.primer_length),words->strictcount[i]); +// fprintf(stderr,"\n\n Primer sample : \n"); +// for (i=0; isize; i++) +// fprintf(stderr," + Primer : %s sequence count : %d\n",ecoUnhashWord(words2->words[i],options.primer_length),words2->strictcount[i]); + if (options.no_multi_match) { (void)filterMultiStrictPrimer(words); diff --git a/src/libecoPCR/ecoMalloc.c b/src/libecoPCR/ecoMalloc.c index 0719a8d..d44ce10 100644 --- a/src/libecoPCR/ecoMalloc.c +++ b/src/libecoPCR/ecoMalloc.c @@ -17,7 +17,7 @@ void eco_untrace_memory_allocation() void ecoMallocedMemory() { - return eco_amount_malloc; + //eco_amount_malloc; } void *eco_malloc(int64_t chunksize, @@ -60,7 +60,7 @@ void *eco_realloc(void *chunk, if (!newchunk) { ecoError(ECO_MEM_ERROR,error_message,filename,line); - fprintf('Requested memory : %d\n',newsize); + fprintf(stderr,"Requested memory : %d\n",newsize); } if (!chunk) eco_chunk_malloc++; diff --git a/src/libecoprimer/Makefile b/src/libecoprimer/Makefile index 4fc412c..5b33fb9 100644 --- a/src/libecoprimer/Makefile +++ b/src/libecoprimer/Makefile @@ -13,7 +13,8 @@ SOURCES = goodtaxon.c \ pairtree.c \ pairs.c \ taxstats.c \ - apat_search.c + apat_search.c \ + filtering.c SRCS=$(SOURCES) diff --git a/src/libecoprimer/ecoprimer.h b/src/libecoprimer/ecoprimer.h index f7a9ec4..b984e76 100644 --- a/src/libecoprimer/ecoprimer.h +++ b/src/libecoprimer/ecoprimer.h @@ -47,6 +47,7 @@ typedef uint64_t word_t, *pword_t; #define WORDMASK(s) ((1LLU << ((s) * 2)) -1) #define LSHIFTWORD(x,s) (((x) << 2) & WORDMASK(s)) #define RSHIFTWORD(x,s) (((x) & WORDMASK(s))>> 2) +#define ERRORMASK(s) ((int32_t)((1LLU << (s)) -1)) #define RAPPENDBASE(x,s,c) (LSHIFTWORD((x),(s)) | (word_t)(c)) #define LAPPENDBASE(x,s,c) (RSHIFTWORD((x),(s)) | ((word_t)((~(c)) & 3) << (((s)-1) *2))) @@ -65,6 +66,13 @@ typedef uint64_t word_t, *pword_t; #define MINI(x,y) (((x) < (y)) ? (x):(y)) #define MAXI(x,y) (((x) < (y)) ? (y):(x)) +#define FWORDSIZE (13) +#define FWORDMASK WORDMASK(FWORDSIZE) +#define FILTERWORD(x) ((uint32_t)((x) & FWORDMASK)) +#define CFILTERWORD(x,s) ((uint32_t)(((x) >> (((s)-FWORDSIZE)*2)) & FWORDMASK)) + + + typedef struct { pword_t words; uint32_t *strictcount; @@ -231,6 +239,7 @@ typedef struct { typedef struct { bool_t statistics; + bool_t filtering; uint32_t lmin; //**< Amplifia minimal length uint32_t lmax; //**< Amplifia maximal length uint32_t error_max; //**< maximum error count in fuzzy search @@ -270,7 +279,8 @@ pecodnadb_t readdnadb(const char *name, uint32_t *size); int isGoodTaxon(ecotaxonomy_t *taxonomy,int32_t taxon,poptions_t options); uint32_t ecoWordCount(uint32_t wordsize, uint32_t circular, ecoseq_t *seq); -pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint32_t doublestrand, ecoseq_t *seq,uint32_t *size); +pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint32_t doublestrand, ecoseq_t *seq,uint32_t *size,int32_t *neededWords,uint32_t neededWordCount, + int32_t quorum); uint32_t ecoCompactHashSequence(pword_t dest,uint32_t size); const char* ecoUnhashWord(word_t word,uint32_t size); word_t ecoComplementWord(word_t word,uint32_t size); @@ -278,8 +288,8 @@ uint32_t ecoFindWord(pwordcount_t table,word_t word); void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,uint32_t seqQuorum); -pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,ecoseq_t *seq); -void addSeqToWordCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t exampleCount,uint32_t seqQuorum,ecoseq_t *seq); +pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t seqQuorum,ecoseq_t *seq,int32_t *neededWords,uint32_t neededWordCount); +void addSeqToWordCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t exampleCount,uint32_t seqQuorum,ecoseq_t *seq,int32_t *neededWords,uint32_t neededWordCount); pqueue_t newQueue(pqueue_t queue, uint32_t size); pqueue_t resizeQueue(pqueue_t queue, uint32_t size); @@ -318,4 +328,8 @@ float taxonomycoverage(ppair_t pair, poptions_t options); char ecoComplementChar(char base); void taxonomyspecificity (ppair_t pair); +int32_t *filteringSeq(pecodnadb_t database, uint32_t seqdbsize, + uint32_t exampleCount,poptions_t options,uint32_t *size,int32_t sequenceQuorum); + + #endif /* EPSORT_H_ */ diff --git a/src/libecoprimer/filtering.c b/src/libecoprimer/filtering.c new file mode 100644 index 0000000..79ba685 --- /dev/null +++ b/src/libecoprimer/filtering.c @@ -0,0 +1,183 @@ +/* + * filtering.c + * + * Created on: 12 mai 2009 + * Author: coissac + */ + +#include "ecoprimer.h" +#include +#include + +#include "hashencoder.h" + +static int32_t *ecoFilteringHashSequence(int32_t *dest, + uint32_t circular, + uint32_t doublestrand, + ecoseq_t *seq, + uint32_t *size); + + + + + +static int32_t *ecoFilteringHashSequence(int32_t *dest, + uint32_t circular, + uint32_t doublestrand, + ecoseq_t *seq, + uint32_t *size) +{ + static char *in_last_seq=NULL; + uint32_t i=0; + uint32_t j; + char *base; + int8_t code; + int32_t error=0; + word_t word=0; + word_t antiword=0; + uint32_t goodword; + uint32_t lmax=0; + + // run on the first call; + + + if (dest==(void*)-1) + { + if (in_last_seq) ECOFREE(in_last_seq,"Free in last seq table"); + return NULL; + } + + + *size = pow(4,FWORDSIZE); + + if (!in_last_seq) + in_last_seq = ECOMALLOC(*size*sizeof(char), + "Cannot allocate filtering hash table"); + + memset(in_last_seq,0,*size*sizeof(char)); + + + if (!dest) + { + dest = ECOMALLOC(*size*sizeof(int32_t), + "Cannot allocate filtering hash table"); + memset(dest,0,*size*sizeof(int32_t)); + } + + lmax = seq->SQ_length; + if (!circular) + lmax-= FWORDSIZE-1; + + + +// DEBUG_LOG("Sequence %s @ %d : %18.18s",seq->AC,i,(seq->SQ+i)); + + for (i=0, base = seq->SQ; i < FWORDSIZE && i < lmax; i++,base++) + { + error<<= 1; + error&=ERRORMASK(FWORDSIZE); + + code = encoder[(*base) - 'A']; + if (code <0) + { + code = 0; + error|= 1; + } + + + word=RAPPENDBASE(word,FWORDSIZE,code); + if (doublestrand) + antiword=LAPPENDBASE(antiword,FWORDSIZE,code); + } + + if (!error && i==FWORDSIZE) + { + + goodword=(uint32_t)((doublestrand) ? MINI(word,antiword):word); + + if (!in_last_seq[goodword]) + { + in_last_seq[goodword]=1; + dest[goodword]++; + } + } + + + for (j=1; j < lmax; j++,i++,base++) + { + +// DEBUG_LOG("Sequence %s @ %d : %18.18s",seq->AC,j,(seq->SQ+j)); + + /* roll over the sequence for circular ones */ + if (i==(uint32_t)seq->SQ_length) base=seq->SQ; + + error<<= 1; + error&=ERRORMASK(FWORDSIZE); + + code = encoder[(*base) - 'A']; + if (code <0) + { + code = 0; + error|= 1; + } + + word=RAPPENDBASE(word,FWORDSIZE,code); + if (doublestrand) + antiword=LAPPENDBASE(antiword,FWORDSIZE,code); + + if (!error) + { + goodword=(uint32_t)((doublestrand) ? MINI(word,antiword):word); + if (!in_last_seq[goodword]) + { + in_last_seq[goodword]=1; + dest[goodword]++; + } + } + + } + + return dest; + +} + + +int32_t *filteringSeq(pecodnadb_t database, uint32_t seqdbsize, + uint32_t exampleCount,poptions_t options,uint32_t *size,int32_t sequenceQuorum) +{ + int32_t *wordscount=NULL; + int32_t keep=0; + uint32_t i,j=0; + + for (i=0;iisexample) + { + j++; + wordscount=ecoFilteringHashSequence(wordscount, + options->circular, + options->doublestrand, + database[i], + size); + } + fprintf(stderr," Filtered sequences %5u/%5u \r",j,exampleCount); + + } + + fprintf(stderr,"\n"); + + for (i=0;i<*size;i++) + if (wordscount[i] >= sequenceQuorum) + keep++; + + + (void)ecoFilteringHashSequence((int32_t*)-1, + options->circular, + options->doublestrand, + NULL, + NULL); + + fprintf(stderr,"ok\n Considered word of size %d for filtering : %d\n",FWORDSIZE,keep); + return wordscount; + +} diff --git a/src/libecoprimer/hashencoder.h b/src/libecoprimer/hashencoder.h new file mode 100644 index 0000000..00540d7 --- /dev/null +++ b/src/libecoprimer/hashencoder.h @@ -0,0 +1,21 @@ +/* + * hashencoder.h + * + * Created on: 12 mai 2009 + * Author: coissac + */ + +#ifndef HASHENCODER_H_ +#define HASHENCODER_H_ + +static int8_t encoder[] = {0, // A + -1, // b + 1, // C + -1,-1,-1, // d, e, f + 2, // G + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // h,i,j,k,l,m,n,o,p,q,r,s + 3,3, // T,U + -1,-1,-1,-1,-1}; // v,w,x,y,z + + +#endif /* HASHENCODER_H_ */ diff --git a/src/libecoprimer/hashsequence.c b/src/libecoprimer/hashsequence.c index 207848f..2caea48 100644 --- a/src/libecoprimer/hashsequence.c +++ b/src/libecoprimer/hashsequence.c @@ -10,15 +10,7 @@ static int cmpword(const void *x,const void *y); -static int8_t encoder[] = {0, // A - -1, // b - 1, // C - -1,-1,-1, // d, e, f - 2, // G - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // h,i,j,k,l,m,n,o,p,q,r,s - 3,3, // T,U - -1,-1,-1,-1,-1}; // v,w,x,y,z - +#include "hashencoder.h" uint32_t ecoWordCount(uint32_t wordsize, uint32_t circular, ecoseq_t *seq) { @@ -31,7 +23,15 @@ uint32_t ecoWordCount(uint32_t wordsize, uint32_t circular, ecoseq_t *seq) return wordcount; } -pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint32_t doublestrand, ecoseq_t *seq,uint32_t *size) +pword_t ecoHashSequence(pword_t dest, + uint32_t wordsize, + uint32_t circular, + uint32_t doublestrand, + ecoseq_t *seq, + uint32_t *size, + int32_t *neededWords, + uint32_t neededWordCount, + int32_t quorum) { uint32_t i=0; uint32_t j; @@ -40,6 +40,7 @@ pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint int32_t error=0; word_t word=0; word_t antiword=0; + word_t goodword; uint32_t lmax=0; (*size)=0; @@ -57,7 +58,9 @@ pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint for (i=0, base = seq->SQ; i < wordsize && i < lmax; i++,base++) { + error<<= 1; + error&=ERRORMASK(wordsize); code = encoder[(*base) - 'A']; if (code <0) @@ -68,10 +71,22 @@ pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint word=RAPPENDBASE(word,wordsize,code); + if (doublestrand) antiword=LAPPENDBASE(antiword,wordsize,code); + + if (neededWordCount && i>=(FWORDSIZE-1)) + { + + goodword = (doublestrand) ? MINI(FILTERWORD(word),CFILTERWORD(antiword,wordsize)):FILTERWORD(word); + if (neededWords[(uint32_t)goodword]AC,j,(seq->SQ+j)); /* roll over the sequence for circular ones */ + if (i==(uint32_t)seq->SQ_length) base=seq->SQ; error<<= 1; + error&=ERRORMASK(wordsize); code = encoder[(*base) - 'A']; if (code <0) @@ -100,6 +117,17 @@ pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint if (doublestrand) antiword=LAPPENDBASE(antiword,wordsize,code); + if (neededWordCount) + { + goodword = (doublestrand) ? MINI(FILTERWORD(word),CFILTERWORD(antiword,wordsize)):FILTERWORD(word); + if (neededWords[(uint32_t)goodword]AC,goodword,neededWords[(uint32_t)goodword],quorum,i,error); + + } + + if (!error) { dest[*size]=(doublestrand) ? MINI(word,antiword):word; @@ -107,7 +135,7 @@ pword_t ecoHashSequence(pword_t dest, uint32_t wordsize, uint32_t circular, uint } } - + // DEBUG_LOG("%s goodword = %d",seq->AC,*size); return dest; } @@ -116,12 +144,16 @@ uint32_t ecoCompactHashSequence(pword_t table,uint32_t size) { uint32_t i,j; word_t current; +// bool_t here=FALSE; sortword(table,size); current = 0; current=SETMULTIWORD(current); /* build impossible word for the first loop cycle */ +// if (strcmp(ecoUnhashWord(table[size-1],18),"GTTTGTTCAACGATTAAA")==0) +// here=TRUE; + for (i=0,j=0; j < size;j++) { if (WORD(table[j])!=current) @@ -134,6 +166,9 @@ uint32_t ecoCompactHashSequence(pword_t table,uint32_t size) table[i]=SETMULTIWORD(table[i]); } +// if (strcmp(ecoUnhashWord(WORD(table[i-1]),18),"TACGACCTCGATGTTGGA")==0) +// DEBUG_LOG("winner %d",i) + return i; } diff --git a/src/libecoprimer/merge.c b/src/libecoprimer/merge.c index 28ec24b..a638ca9 100644 --- a/src/libecoprimer/merge.c +++ b/src/libecoprimer/merge.c @@ -41,7 +41,8 @@ void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,ui (void)mergeInit(&merged,data,s1,s2); (void)newQueue(&queue,MINI(s1,s2)); - while (merged.read1 < s1 && merged.read2 < merged.size) + + while (merged.read1 < s1 || merged.read2 < merged.size) { if (! queue.empty) { @@ -56,7 +57,8 @@ void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,ui source=S1; } - if (WORD(currentword) > WORD(merged.words[merged.read2])) + if (merged.read2 < merged.size && + WORD(currentword) > WORD(merged.words[merged.read2])) { currentword = merged.words[merged.read2]; currentcount = merged.count[merged.read2]; @@ -114,6 +116,8 @@ void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,ui if (merged.read2 < merged.size) + { + //DEBUG_LOG("end1 %d %d/%d %d/%d",merged.write,merged.read1,s1,merged.read2,merged.size); for (;merged.read2 < merged.size;merged.read2++) { merged.words[merged.write]=merged.words[merged.read2]; @@ -122,7 +126,10 @@ void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,ui merged.write++; } - else while (! queue.empty) + } + else { + //DEBUG_LOG("end2 %d %d/%d %d/%d",merged.write,merged.read1,s1,merged.read2,merged.size); + while (! queue.empty) { // DEBUG_LOG("write : %s count : %d write : %d size : %d pop : %d push : %d empty : %d",ecoUnhashWord(queue.words[queue.pop],18),queue.count[queue.pop],merged.write,queue.size,queue.pop,queue.push,queue.empty) merged.words[merged.write]=queue.words[queue.pop]; @@ -131,6 +138,7 @@ void ecomerge(pwordcount_t data,uint32_t s1,uint32_t s2,uint32_t remainingSeq,ui if (remainingSeq + merged.count[merged.write] >= seqQuorum) merged.write++; } + } data->size = merged.write; diff --git a/src/libecoprimer/strictprimers.c b/src/libecoprimer/strictprimers.c index d54bde7..2fe6bd6 100644 --- a/src/libecoprimer/strictprimers.c +++ b/src/libecoprimer/strictprimers.c @@ -48,7 +48,7 @@ double timeval_subtract (struct timeval *x, struct timeval *y) return (double)result.tv_sec + (double)result.tv_usec/1e6; } -pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,ecoseq_t *seq) +pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t seqQuorum,ecoseq_t *seq,int32_t *neededWords,uint32_t neededWordCount) { uint32_t i; uint32_t buffsize; @@ -65,7 +65,7 @@ pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circ if (seq) { - table->words = ecoHashSequence(NULL,wordsize,circular,doublestrand,seq,&buffsize); + table->words = ecoHashSequence(NULL,wordsize,circular,doublestrand,seq,&buffsize,neededWords,neededWordCount,seqQuorum); table->size = ecoCompactHashSequence(table->words,buffsize); table->inseqcount=1; @@ -79,7 +79,7 @@ pwordcount_t initCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circ return table; } -void addSeqToWordCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t exampleCount,uint32_t seqQuorum,ecoseq_t *seq) +void addSeqToWordCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circular, uint32_t doublestrand,uint32_t exampleCount,uint32_t seqQuorum,ecoseq_t *seq,int32_t *neededWords,uint32_t neededWordCount) { uint32_t buffersize; pword_t newtable; @@ -96,7 +96,7 @@ void addSeqToWordCountTable(pwordcount_t table, uint32_t wordsize, uint32_t circ // DEBUG_LOG("Words = %x (%u) new = %x", table->words,table->size,newtable); - (void)ecoHashSequence(newtable,wordsize,circular,doublestrand,seq,&newsize); + (void)ecoHashSequence(newtable,wordsize,circular,doublestrand,seq,&newsize,neededWords,neededWordCount,seqQuorum); // DEBUG_LOG("new seq wordCount : %d",newsize); newsize = ecoCompactHashSequence(newtable,newsize); @@ -137,6 +137,18 @@ pwordcount_t lookforStrictPrimer(pecodnadb_t database, uint32_t seqdbsize, pwordcount_t strictprimers=NULL; uint64_t totallength=0; uint32_t sequenceQuorum = (uint32_t)floor((float)exampleCount * options->strict_quorum); + int32_t *neededWords; + uint32_t neededWordCount; + + fprintf(stderr,"Filtering... "); + + if (options->filtering) + neededWords = filteringSeq(database,seqdbsize,exampleCount,options,&neededWordCount,(int32_t)sequenceQuorum); + else + { + neededWordCount=0; + neededWords=NULL; + } if (options->statistics) { @@ -152,7 +164,8 @@ pwordcount_t lookforStrictPrimer(pecodnadb_t database, uint32_t seqdbsize, strictprimers = initCountTable(NULL,options->primer_length, options->circular, options->doublestrand, - NULL); + 0, + NULL,NULL,0); getrusage(RUSAGE_SELF,&start); @@ -167,7 +180,8 @@ pwordcount_t lookforStrictPrimer(pecodnadb_t database, uint32_t seqdbsize, strictprimers = initCountTable(strictprimers,options->primer_length, options->circular, options->doublestrand, - database[i]); + sequenceQuorum, + database[i],neededWords,neededWordCount); first=FALSE; } else @@ -180,7 +194,7 @@ pwordcount_t lookforStrictPrimer(pecodnadb_t database, uint32_t seqdbsize, options->doublestrand, exampleCount, sequenceQuorum, - database[i]); + database[i],neededWords,neededWordCount); }; totallength+=database[i]->SQ_length; getrusage(RUSAGE_SELF,&usage); @@ -215,6 +229,9 @@ pwordcount_t lookforStrictPrimer(pecodnadb_t database, uint32_t seqdbsize, sizeof(word_t)*strictprimers->size, "Cannot reallocate strict primer table"); + if (neededWords) + ECOFREE(neededWords,"Clean needed word table"); + return strictprimers; } diff --git a/src/libecoprimer/taxstats.c b/src/libecoprimer/taxstats.c index 487f84e..a751d7d 100644 --- a/src/libecoprimer/taxstats.c +++ b/src/libecoprimer/taxstats.c @@ -47,7 +47,6 @@ int32_t counttaxon(int32_t taxid) tsearch((void*)((size_t)taxid),&taxontree,cmptaxon); taxoncount++; } - return taxoncount; } @@ -60,6 +59,7 @@ int32_t getrankdbstats(pecodnadb_t seqdb, uint32_t seqdbsize, ecotaxonomy_t *tax ecotx_t *tmptaxon; counttaxon(-1); + options->intaxa = 0; for (i=0;iouttaxa = 0; for (i=0;i