示例#1
0
int main(int argc, char **argv)
{
    AjPSeqall seq1;
    AjPSeqset seq2;
    AjPSeq a;
    const AjPSeq b;
    AjPStr m = 0;
    AjPStr n = 0;

    AjPFile errorf;
    AjBool show = ajFalse;

    ajint    lena = 0;
    ajint    lenb = 0;

    const char   *p;
    const char   *q;

    AjPMatrixf matrix;
    AjPSeqCvt cvt = 0;
    float **sub;
    ajint *compass = NULL;
    float *path = NULL;

    float gapopen;
    float gapextend;
    float score;


    ajint begina;
    ajint i;
    ajuint k;
    ajint beginb;
    ajint start1 = 0;
    ajint start2 = 0;
    ajint end1   = 0;
    ajint end2   = 0;
    ajint width  = 0;
    AjPTable seq1MatchTable = 0;
    ajint wordlen = 6;
    ajint oldmax = 0;

    AjPAlign align = NULL;

    embInit("supermatcher", argc, argv);

    matrix    = ajAcdGetMatrixf("datafile");
    seq1      = ajAcdGetSeqall("asequence");
    seq2      = ajAcdGetSeqset("bsequence");
    gapopen   = ajAcdGetFloat("gapopen");
    gapextend = ajAcdGetFloat("gapextend");
    wordlen   = ajAcdGetInt("wordlen");
    align     = ajAcdGetAlign("outfile");
    errorf    = ajAcdGetOutfile("errorfile");
    width     = ajAcdGetInt("width");	/* not the same as awidth */

    gapopen   = ajRoundFloat(gapopen, 8);
    gapextend = ajRoundFloat(gapextend, 8);

    sub = ajMatrixfGetMatrix(matrix);
    cvt = ajMatrixfGetCvt(matrix);

    embWordLength(wordlen);

    ajSeqsetTrim(seq2);

    while(ajSeqallNext(seq1,&a))
    {
        ajSeqTrim(a);
	begina = 1 + ajSeqGetOffset(a);

	m = ajStrNewRes(1+ajSeqGetLen(a));

	lena = ajSeqGetLen(a);

	ajDebug("Read '%S'\n", ajSeqGetNameS(a));

	if(!embWordGetTable(&seq1MatchTable, a)) /* get table of words */
	    ajErr("Could not generate table for %s\n",
		  ajSeqGetNameC(a));

	for(k=0;k<ajSeqsetGetSize(seq2);k++)
	{
	    b      = ajSeqsetGetseqSeq(seq2, k);
	    lenb   = ajSeqGetLen(b);
	    beginb = 1 + ajSeqGetOffset(b);

	    ajDebug("Processing '%S'\n", ajSeqGetNameS(b));
	    p = ajSeqGetSeqC(a);
	    q = ajSeqGetSeqC(b);

	    if(!supermatcher_findstartpoints(seq1MatchTable,b,a,
					     &start1, &start2,
					     &end1, &end2))
	    {
		ajFmtPrintF(errorf,
			    "No wordmatch start points for "
			    "%s vs %s. No alignment\n",
			    ajSeqGetNameC(a),ajSeqGetNameC(b));
		continue;
	    }
	    
        n=ajStrNewRes(1+ajSeqGetLen(b));
        ajStrAssignC(&m,"");
        ajStrAssignC(&n,"");

	    ajDebug("++ %S v %S start:%d %d end:%d %d\n",
		    ajSeqGetNameS(a), ajSeqGetNameS(b),
		    start1, start2, end1, end2);

	    if(end1-start1+1 > oldmax)
	    {
		oldmax = ((end1-start1)+1);
		AJRESIZE(path,oldmax*width*sizeof(float));
		AJRESIZE(compass,oldmax*width*sizeof(ajint));
		ajDebug("++ resize to oldmax: %d\n", oldmax);
	    }

	    for(i=0;i<((end1-start1)+1)*width;i++)
		path[i] = 0.0;

	    ajDebug("Calling embAlignPathCalcFast "
		     "%d..%d [%d/%d] %d..%d [%d/%d]\n",
		     start1, end1, (end1 - start1 + 1), lena,
		     start2, end2, (end2 - start2 + 1), lenb);

	    score = embAlignPathCalcSWFast(&p[start1],&q[start2],
                                           end1-start1+1,end2-start2+1,
                                           0,width,
                                           gapopen,gapextend,
                                           path,sub,cvt,
                                           compass,show);

	    embAlignWalkSWMatrixFast(path,compass,gapopen,gapextend,a,b,
					 &m,&n,end1-start1+1,end2-start2+1,
					 0,width,
                                         &start1,&start2);

		if(!ajAlignFormatShowsSequences(align))
		{
		    ajAlignDefineCC(align, ajStrGetPtr(m),
		            ajStrGetPtr(n), ajSeqGetNameC(a),
		            ajSeqGetNameC(b));
		    ajAlignSetScoreR(align, score);
		}
		else
		{
		    embAlignReportLocal(align, a, b,
		            m,n,start1,start2,
		            gapopen, gapextend,
		            score,matrix, begina, beginb);
		}
		ajAlignWrite(align);
		ajAlignReset(align);
	    ajStrDel(&n);
	}

	embWordFreeTable(&seq1MatchTable); /* free table of words */
	seq1MatchTable=0;

	ajStrDel(&m);

    }

    if(!ajAlignFormatShowsSequences(align))
    {
        ajMatrixfDel(&matrix);        
    }
    
    AJFREE(path);
    AJFREE(compass);

    ajAlignClose(align);
    ajAlignDel(&align);
    ajSeqallDel(&seq1);
    ajSeqDel(&a);
    ajSeqsetDel(&seq2);
    ajFileClose(&errorf);

    embExit();

    return 0;
}
示例#2
0
int main(int argc, char **argv)
{
    AjPSeqall queryseqs;
    AjPSeqset targetseqs;
    AjPSeq queryseq;
    const AjPSeq targetseq;
    AjPStr queryaln = 0;
    AjPStr targetaln = 0;

    AjPFile errorf;
    AjBool show = ajFalse;

    const char   *queryseqc;
    const char   *targetseqc;

    AjPMatrixf matrix;
    AjPSeqCvt cvt = 0;
    float **sub;
    ajint *compass = NULL;
    float *path = NULL;

    float gapopen;
    float gapextend;
    float score;
    float minscore;

    ajuint j, k;
    ajint querystart = 0;
    ajint targetstart = 0;
    ajint queryend   = 0;
    ajint targetend   = 0;
    ajint width  = 0;
    AjPTable kmers = 0;
    ajint wordlen = 6;
    ajint oldmax = 0;
    ajint newmax = 0;

    ajuint ntargetseqs;
    ajuint nkmers;

    AjPAlign align = NULL;
    EmbPWordMatch maxmatch; /* match with maximum score */

    /* Cursors for the current sequence being scanned,
    ** i.e., until which location it was scanned.
    ** Separate cursor/location entries for each sequence in the seqset.
    */
    ajuint* lastlocation;

    EmbPWordRK* wordsw = NULL;
    AjPList* matchlist = NULL;

    embInit("supermatcher", argc, argv);

    matrix    = ajAcdGetMatrixf("datafile");
    queryseqs = ajAcdGetSeqall("asequence");
    targetseqs= ajAcdGetSeqset("bsequence");
    gapopen   = ajAcdGetFloat("gapopen");
    gapextend = ajAcdGetFloat("gapextend");
    wordlen   = ajAcdGetInt("wordlen");
    align     = ajAcdGetAlign("outfile");
    errorf    = ajAcdGetOutfile("errorfile");
    width     = ajAcdGetInt("width");	/* width for banded Smith-Waterman */
    minscore  = ajAcdGetFloat("minscore");

    gapopen   = ajRoundFloat(gapopen, 8);
    gapextend = ajRoundFloat(gapextend, 8);

    sub = ajMatrixfGetMatrix(matrix);
    cvt = ajMatrixfGetCvt(matrix);

    embWordLength(wordlen);

    /* seqset sequence is the reference sequence for SAM format */
    ajAlignSetRefSeqIndx(align, 1);

    ajSeqsetTrim(targetseqs);

    ntargetseqs = ajSeqsetGetSize(targetseqs);

    AJCNEW0(matchlist, ntargetseqs);

    /* get tables of words */
    for(k=0;k<ntargetseqs;k++)
    {
	targetseq = ajSeqsetGetseqSeq(targetseqs, k);
	embWordGetTable(&kmers, targetseq);
	ajDebug("Number of distinct kmers found so far: %d\n",
		ajTableGetLength(kmers));
    }
    AJCNEW0(lastlocation, ntargetseqs);

    if(ajTableGetLength(kmers)<1)
	ajErr("no kmers found");

    nkmers = embWordRabinKarpInit(kmers, &wordsw, wordlen, targetseqs);

    while(ajSeqallNext(queryseqs,&queryseq))
    {
	ajSeqTrim(queryseq);

	queryaln = ajStrNewRes(1+ajSeqGetLen(queryseq));

	ajDebug("Read '%S'\n", ajSeqGetNameS(queryseq));

	for(k=0;k<ntargetseqs;k++)
	{
	    lastlocation[k]=0;
	    matchlist[k] = ajListstrNew();
	}

	embWordRabinKarpSearch(ajSeqGetSeqS(queryseq), targetseqs,
		(const EmbPWordRK*)wordsw, wordlen, nkmers,
		matchlist, lastlocation, ajFalse);


	for(k=0;k<ajSeqsetGetSize(targetseqs);k++)
	{
	    targetseq      = ajSeqsetGetseqSeq(targetseqs, k);

	    ajDebug("Processing '%S'\n", ajSeqGetNameS(targetseq));

	    if(ajListGetLength(matchlist[k])==0)
	    {
		ajFmtPrintF(errorf,
		            "No wordmatch start points for "
		            "%s vs %s. No alignment\n",
		            ajSeqGetNameC(queryseq),ajSeqGetNameC(targetseq));
		embWordMatchListDelete(&matchlist[k]);
		continue;
	    }


	    /* only the maximum match is used as seed
	     * (if there is more than one location with the maximum match
	     * only the first one is used)
	     * TODO: we should add a new option to make above limit optional
	     */
	    maxmatch = embWordMatchFirstMax(matchlist[k]);

	    supermatcher_findendpoints(maxmatch,targetseq, queryseq,
		    &targetstart, &querystart,
		    &targetend, &queryend);

	    targetaln=ajStrNewRes(1+ajSeqGetLen(targetseq));
	    queryseqc = ajSeqGetSeqC(queryseq);
	    targetseqc = ajSeqGetSeqC(targetseq);

	    ajStrAssignC(&queryaln,"");
	    ajStrAssignC(&targetaln,"");

	    ajDebug("++ %S v %S start:%d %d end:%d %d\n",
		    ajSeqGetNameS(targetseq), ajSeqGetNameS(queryseq),
		    targetstart, querystart, targetend, queryend);

	    newmax = (targetend-targetstart+2)*width;

	    if(newmax > oldmax)
	    {
		AJCRESIZE0(path,oldmax,newmax);
		AJCRESIZE0(compass,oldmax,newmax);
		oldmax=newmax;
		ajDebug("++ memory re/allocation for path/compass arrays"
			" to size: %d\n", newmax);
	    }
	    else
	    {
		AJCSET0(path,newmax);
		AJCSET0(compass,newmax);
	    }

	    ajDebug("Calling embAlignPathCalcSWFast "
		    "%d..%d [%d/%d] %d..%d [%d/%d] width:%d\n",
		    querystart, queryend, (queryend - querystart + 1),
		    ajSeqGetLen(queryseq),
		    targetstart, targetend, (targetend - targetstart + 1),
		    ajSeqGetLen(targetseq),
		    width);

	    score = embAlignPathCalcSWFast(&targetseqc[targetstart],
	                                   &queryseqc[querystart],
	                                   targetend-targetstart+1,
	                                   queryend-querystart+1,
	                                   0,width,
	                                   gapopen,gapextend,
	                                   path,sub,cvt,
	                                   compass,show);
	    if(score>minscore)
	    {
		embAlignWalkSWMatrixFast(path,compass,gapopen,gapextend,
		                         targetseq,queryseq,
		                         &targetaln,&queryaln,
		                         targetend-targetstart+1,
		                         queryend-querystart+1,
		                         0,width,
		                         &targetstart,&querystart);

		if(!ajAlignFormatShowsSequences(align))
		{
		    ajAlignDefineCC(align, ajStrGetPtr(targetaln),
		                    ajStrGetPtr(queryaln),
		                    ajSeqGetNameC(targetseq),
		                    ajSeqGetNameC(queryseq));
		    ajAlignSetScoreR(align, score);
		}
		else
		{
		    ajDebug(" queryaln:%S \ntargetaln:%S\n",
		            queryaln,targetaln);
		    embAlignReportLocal(align,
			    queryseq, targetseq,
			    queryaln, targetaln,
			    querystart, targetstart,
			    gapopen, gapextend,
			    score, matrix,
			    1 + ajSeqGetOffset(queryseq),
			    1 + ajSeqGetOffset(targetseq)
		    );
		}
		ajAlignWrite(align);
		ajAlignReset(align);
	    }
	    ajStrDel(&targetaln);

	    embWordMatchListDelete(&matchlist[k]);
	}

	ajStrDel(&queryaln);
    }


    for(k=0;k<nkmers;k++)
    {
	AJFREE(wordsw[k]->seqindxs);
	AJFREE(wordsw[k]->nSeqMatches);

	for(j=0;j<wordsw[k]->nseqs;j++)
	    AJFREE(wordsw[k]->locs[j]);

	AJFREE(wordsw[k]->nnseqlocs);
	AJFREE(wordsw[k]->locs);
	AJFREE(wordsw[k]);
    }

    embWordFreeTable(&kmers);

    if(!ajAlignFormatShowsSequences(align))
	ajMatrixfDel(&matrix);
    
    AJFREE(path);
    AJFREE(compass);
    AJFREE(kmers);
    AJFREE(wordsw);

    AJFREE(matchlist);
    AJFREE(lastlocation);

    ajAlignClose(align);
    ajAlignDel(&align);
    ajSeqallDel(&queryseqs);
    ajSeqDel(&queryseq);
    ajSeqsetDel(&targetseqs);
    ajFileClose(&errorf);

    embExit();

    return 0;
}
int main(int argc, char **argv)
{
    ajint i;
    ajint numseq;
    ajint j = 0;
    ajint numres;
    ajint count;
    ajint k;
    ajint kmax;
    float defheight;
    float currentscale;
    AjPStr shade = NULL;
    AjPFloat pair  = NULL;
    AjPGraph graph = NULL;
    AjPMatrix cmpmatrix = NULL;
    AjPSeqCvt cvt = NULL;
    AjPStr matcodes = NULL;
    AjBool consensus;
    AjBool colourbyconsensus;
    AjBool colourbyresidues;
    AjBool colourbyshade = AJFALSE;
    AjBool boxit;
    AjBool boxcol;
    AjBool portrait;
    AjBool collision;
    ajint identity;
    AjBool listoptions;
    ajint alternative;
    AjPStr altstr = NULL;
    AjPStr sidentity = NULL;
    AjPStr ssimilarity = NULL;
    AjPStr sother = NULL;
    AjPStr sboxcolval = NULL;
    AjPStr options = NULL;
    /*    ajint showscore = 0; */
    ajint iboxcolval = 0;
    ajint cidentity = RED;
    ajint csimilarity = GREEN;
    ajint cother = BLACK;
    float fxp;
    float fyp;
    float yincr;
    float y;
    ajint ixlen;
    ajint iylen;
    ajint ixoff;
    ajint iyoff;
    char res[2] = " ";

    float *score = 0;
    float scoremax = 0;

    float *identical = NULL;
    ajint identicalmaxindex;
    float *matching = NULL;
    ajint matchingmaxindex;

    float *colcheck = NULL;

    ajint **matrix;
    ajint m1 = 0;
    ajint m2 = 0;
    ajint ms = 0;
    ajint highindex = 0;
    ajint myindex;
    ajint *previous = 0;
    AjBool iscons = ajFalse;
    ajint currentstate = 0;
    ajint oldfg = 0;
    float fold = 0.0;
    ajint *colmat = 0;
    ajint *shadecolour = 0;
    /* float identthresh = 1.5; */
    /* float simthresh = 1.0; */
    /* float relthresh = 0.5; */
    float part = 0.0;
    const char *cptr;
    ajint resbreak;
    float fplural;
    float ystart;
    float xmin;
    float xmax;
    float xmid;
    AjPTime ajtime;
    ajint gapcount = 0;
    ajint countforgap = 0;
    ajint boxindex;
    float max;
    ajint matsize;
    ajint seqperpage = 0;
    ajint startseq;
    ajint endseq;
    ajint newILend = 0;
    ajint newILstart;
    void *freeptr;
    ajint itmp;
    
    embInit("prettyplot", argc, argv);

    seqset   = ajAcdGetSeqset("sequences");
    numres   = ajAcdGetInt("residuesperline");
    resbreak = ajAcdGetInt("resbreak");

    ajSeqsetFill(seqset);	/* Pads sequence set with gap characters */
    numseq = ajSeqsetGetSize(seqset);

    graph             = ajAcdGetGraph("graph");
    colourbyconsensus = ajAcdGetBoolean("ccolours");
    colourbyresidues  = ajAcdGetBoolean("docolour");
    shade             = ajAcdGetString("shade");
    pair              = ajAcdGetArray("pair");
    identity          = ajAcdGetInt("identity");
    boxit             = ajAcdGetBoolean("box");

    ajtime = ajTimeNewTodayFmt("daytime");

    ajSeqsetTrim(seqset);
    /* offset = ajSeqsetGetOffset(seqset); Unused */

    ajGraphAppendTitleS(graph, ajSeqsetGetUsa(seqset));

    if(boxit)
    {
	AJCNEW(seqboxptr, numseq);
	for(i=0;i<numseq;i++)
	    AJCNEW(seqboxptr[i], ajSeqsetGetLen(seqset));
    }
    boxcol      = ajAcdGetBoolean("boxcol");
    sboxcolval  = ajAcdGetString("boxuse");

    if(boxcol)
    {
	iboxcolval = ajGraphicsCheckColourS(sboxcolval);
	if(iboxcolval == -1)
	    iboxcolval = GREY;
    }

    consensus = ajAcdGetBoolean("consensus");
    if(consensus)
    {
	AJCNEW(constr, ajSeqsetGetLen(seqset)+1);
	constr[0] = '\0';
    }
    shownames   = ajAcdGetBoolean("name");
    shownumbers = ajAcdGetBoolean("number");
    charlen     = ajAcdGetInt("maxnamelen");
    fplural     = ajAcdGetFloat("plurality");
    portrait    = ajAcdGetBoolean("portrait");
    collision   = ajAcdGetBoolean("collision");
    listoptions = ajAcdGetBoolean("listoptions");
    altstr = ajAcdGetListSingle("alternative");
    cmpmatrix   = ajAcdGetMatrix("matrixfile");

    ajStrToInt(altstr, &alternative);

    matrix = ajMatrixGetMatrix(cmpmatrix);
    cvt = ajMatrixGetCvt(cmpmatrix);
    matsize = ajMatrixGetSize(cmpmatrix);

    AJCNEW(identical,matsize);
    AJCNEW(matching,matsize);
    AJCNEW(colcheck,matsize);

    numgaps = numres/resbreak;
    numgaps--;

    if(portrait)
    {
	ajGraphicsSetPortrait(1);
	ystart = (float) 75.0;
    }
    else
	ystart = (float) 75.0;

    /* pair is an array of three non-negative floats */

    /* identthresh = ajFloatGet(pair,0); Unused */
    /* simthresh = ajFloatGet(pair,1); Unused */
    /* relthresh = ajFloatGet(pair,2); Unused */

    /*
    ** shade is a formatted 4-character string. Characters BLPW only.
    ** controlled by a pattern in ACD.
    */

    if(ajStrGetLen(shade))
    {
	AJCNEW(shadecolour,4);
	cptr = ajStrGetPtr(shade);
	for(i=0;i<4;i++){
	    if(cptr[i]== 'B' || cptr[i]== 'b')
		shadecolour[i] = BLACK;
	    else if(cptr[i]== 'L' || cptr[i]== 'l')
		shadecolour[i] = BROWN;
	    else if(cptr[i]== 'P' || cptr[i]== 'p')
		shadecolour[i] = WHEAT;
	    else if(cptr[i]== 'W' || cptr[i]== 'w')
		shadecolour[i] = WHITE;
	}

	colourbyconsensus = colourbyresidues = ajFalse;
	colourbyshade = ajTrue;
    }

/*
** we can colour by consensus or residue but not both
** if we have to choose, use the consensus
*/

    if(colourbyconsensus && colourbyresidues)
	colourbyconsensus = AJFALSE;

    sidentity = ajAcdGetString("cidentity");
    ssimilarity = ajAcdGetString("csimilarity");
    sother = ajAcdGetString("cother");

    if(colourbyconsensus)
    {
	cidentity = ajGraphicsCheckColourS(sidentity);
	if(cidentity == -1)
	    cidentity = RED;

	csimilarity = ajGraphicsCheckColourS(ssimilarity);
	if(csimilarity == -1)
	    csimilarity = GREEN;


	cother = ajGraphicsCheckColourS(sother);
	if(cother == -1)
	    cother = BLACK;

    }
    else if(colourbyresidues)
    {
	matcodes = ajMatrixGetCodes(cmpmatrix);
	if(ajSeqsetIsProt(seqset))
	    colmat = ajGraphicsBasecolourNewProt(matcodes);
	else
	    colmat = ajGraphicsBasecolourNewNuc(matcodes);
    }


    /* output the options used as the subtitle for the bottom of the graph */
    if(listoptions)
    {
	ajStrAssignC(&options,"");
	ajFmtPrintAppS(&options,"-plurality %.1f",fplural);

	if(collision)
	    ajStrAppendC(&options," -collision");
	else
	    ajStrAppendC(&options," -nocollision");

	if(boxit)
	    ajStrAppendC(&options," -box");
	else
	    ajStrAppendC(&options," -nobox");

	if(boxcol)
	    ajStrAppendC(&options," -boxcol");
	else
	    ajStrAppendC(&options," -noboxcol");

	if(colourbyconsensus)
	    ajStrAppendC(&options," -colbyconsensus");
	else if(colourbyresidues)
	    ajStrAppendC(&options," -colbyresidues");
	else if(colourbyshade)
	    ajStrAppendC(&options," -colbyshade");
	else
	    ajStrAppendC(&options," -nocolour");

	if(alternative==2)
	    ajStrAppendC(&options," -alt 2");
	else if(alternative==1)
	    ajStrAppendC(&options," -alt 1");
	else if(alternative==3)
	    ajStrAppendC(&options," -alt 3");
    }


    AJCNEW(seqcolptr, numseq);
    for(i=0;i<numseq;i++)
	AJCNEW(seqcolptr[i], ajSeqsetGetLen(seqset));

    AJCNEW(seqcharptr, numseq);
    AJCNEW(seqnames, numseq);
    AJCNEW(score, numseq);
    AJCNEW(previous, numseq);
    AJCNEW(seqcount, numseq);

    for(i=0;i<numseq;i++)
    {
	ajSeqsetFmtUpper(seqset);
	seqcharptr[i] =  ajSeqsetGetseqSeqC(seqset, i);
	seqnames[i] = 0;
	ajStrAppendS(&seqnames[i],ajSeqsetGetseqNameS(seqset, i));
	ajStrTruncateLen(&seqnames[i],charlen);
	previous[i] = 0;
	seqcount[i] = 0;
    }

    /*
    ** user will pass the number of residues to fit a page
    ** therefore we now need to calculate the size of the chars
    ** based on this and get the new char width.
    ** 'charlen' maximum characters for the name (truncated above)
    */

    ajGraphicsGetCharsize(&defheight,&currentscale);

    xmin = -charlen - (float)2.0;
    xmax = (float)numres+(float)11.0+(float)(numres/resbreak);
    xmid = (xmax + xmin)/(float)2.0;

    ajGraphOpenWin(graph, xmin, xmax,
		   (float)0.0, ystart+(float)1.0);
 
    ajGraphGetParamsPage(graph, &fxp,&fyp,&ixlen,&iylen,&ixoff,&iyoff);

    if(portrait)
    {
        itmp = ixlen;
        ixlen = iylen;
        iylen = itmp;
    }

    ajGraphicsGetCharsize(&defheight,&currentscale);

    ajGraphicsSetCharscale(((float)ixlen/((float)(numres+charlen+1)*
                                          (currentscale * (float) 1.5)))/
                                           currentscale);

/*    ajGraphicsSetCharscale(((float)ixlen/((float)(numres+charlen)*
                                          (currentscale+(float)1.0)))/
                                          currentscale); */

    ajGraphicsGetCharsize(&defheight,&currentscale);

    yincr = (currentscale + (float)3.0)*(float)0.3;

/*
** If we have titles (now the standard graph title and subtitle and footer)
** leave 7 rows of space for them
*/
    y=ystart-(float)7.0;

    if(ajStrGetLen(options))
    {
	fold = ajGraphicsSetCharscale(1.0);
	ajGraphicsDrawposTextAtmid(xmid,2.0,
                                   ajStrGetPtr(options));
	ajGraphicsSetCharscale(fold);
    }

/* if sequences per page not set then calculate it */

    if(!seqperpage)
    {
	seqperpage = prettyplot_calcseqperpage(yincr,y,consensus);
	if(seqperpage>numseq)
	    seqperpage=numseq;
    }

    count = 0;

/*
** for boxes we need to set a foreground colour for the box lines
** and save the current foreground colour
*/
    if(boxit && boxcol)
	oldfg = ajGraphicsSetFgcolour(iboxcolval);

/*
** step through each residue position
*/

    kmax = ajSeqsetGetLen(seqset) - 1;
    for(k=0; k<= kmax; k++)
    {
	/* reset column score array */
	for(i=0;i<numseq;i++)
	    score[i] = 0.0;

	/* reset matrix character testing arrays */
	for(i=0;i<matsize;i++)
	{
	    identical[i] = 0.0;
	    matching[i] = 0.0;
	    colcheck[i] = 0.0;
	}

	/* generate a score for this residue in each sequence */
	for(i=0;i<numseq;i++)
	{
	    m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
	    for(j=0;j<numseq;j++)
	    {
		m2 = ajSeqcvtGetCodeK(cvt, seqcharptr[j][k]);
		if(m1 && m2)
		    score[i] += (float)matrix[m1][m2]*
			ajSeqsetGetseqWeight(seqset, j);
	    }
	    if(m1)
		identical[m1] += ajSeqsetGetseqWeight(seqset, i);
	}

	/* find the highest score */
	highindex = -1;
	scoremax  = INT_MIN;
	/*ajDebug("Scores at position %d:\n", k);*/

	for(i=0;i<numseq;i++)
	{
	    /*ajDebug("  seq %d: '%c' %f\n",i,seqcharptr[i][k],score[i]);*/

	    if(score[i] > scoremax)
	    {
		scoremax = score[i];
		highindex = i;
	    }
	}
	for(i=0;i<numseq;i++)
	{
	    m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);

	    if(!matching[m1])
	    {
		for(j=0;j<numseq;j++)
		{
		    m2 = ajSeqcvtGetCodeK(cvt, seqcharptr[j][k]);
		    if(m1 && m2 && matrix[m1][m2] > 0)
			matching[m1] += ajSeqsetGetseqWeight(seqset, j);
		}
	    }
	}

	/* find highs for matching and identical */
	matchingmaxindex  = 0;
	identicalmaxindex = 0;
	for(i=0;i<numseq;i++)
	{
	    m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
	    if(identical[m1] > identical[identicalmaxindex])
		identicalmaxindex = m1;
	}
	for(i=0;i<numseq;i++)
	{
	    m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
	    if(matching[m1] > matching[matchingmaxindex])
		matchingmaxindex = m1;
	    else if(matching[m1] ==  matching[matchingmaxindex])
	    {
		if(identical[m1] > identical[matchingmaxindex])
		    matchingmaxindex= m1;
	    }
	}

	iscons = ajFalse;
	boxindex = -1;
	max = -3;

	ajDebug("k:%2d highindex:%2d matching:%4.2f\n",
		k, highindex,
		matching[ajSeqcvtGetCodeK(cvt, seqcharptr[highindex][k])]);
	if(highindex != -1 &&
	   matching[ajSeqcvtGetCodeK(cvt, seqcharptr[highindex][k])] >= fplural)
	{
	    iscons = ajTrue;
	    boxindex = highindex;
	}
	else
	{
	    for(i=0;i<numseq;i++)
	    {
		m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
		if(matching[m1] > max)
		{
		    max = matching[m1];
		    highindex = i;
		}
		else if(matching[m1] == max)
		{
		    if(identical[m1] >
		       identical[ajSeqcvtGetCodeK(cvt,
                                                  seqcharptr[highindex][k])] )
		    {
			max = matching[m1];
			highindex = i;
		    }
		}
	    }

	    if(matching[ajSeqcvtGetCodeK(cvt,
                                         seqcharptr[highindex][k])] >= fplural)
	    {
		iscons = ajTrue;
		boxindex = highindex;
	    }
	}


	if(iscons)
	{
	    if(!collision)
	    {
		/* check for collisions */
		if(alternative == 1)
		{
		    /* check to see if this is unique for collisions */
		    for(i=0;i<numseq;i++)
		    {
			m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
			if(identical[m1] >= identical[identicalmaxindex] &&
			   m1 != identicalmaxindex)
			    iscons = ajFalse;
		    }

		    /*ajDebug("after (alt=1) iscons: %B",iscons);*/
		}

		else if(alternative == 2)
		{
		    for(i=0;i<numseq;i++)
		    {
			m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);

			if((matching[m1] >= matching[matchingmaxindex] &&
			    m1 != matchingmaxindex &&
			    matrix[m1][matchingmaxindex] < 0.1)||
			   (identical[m1] >= identical[matchingmaxindex]
			   && m1 != matchingmaxindex))
			    iscons = ajFalse;
		    }
		}
		else if(alternative == 3)
		{
		    /*
		    ** to do this check one is NOT in consensus to see if
		    ** another score of fplural has been found
		    */
		    ms = ajSeqcvtGetCodeK(cvt, seqcharptr[highindex][k]);

		    for(i=0;i<numseq;i++)
		    {
			m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
			if(ms != m1 && colcheck[m1] == 0.0)
			    /* NOT in the current consensus */
			    for(j=0;j<numseq;j++)
			    {
				m2 = ajSeqcvtGetCodeK(cvt, seqcharptr[j][k]);
				if( matrix[ms][m2] < 0.1)
				{
				    /* NOT in the current consensus */
				    if( matrix[m1][m2] > 0.1)
					colcheck[m1] +=
                                            ajSeqsetGetseqWeight(seqset,
                                                                 j);
				}
			    }
		    }

		    for(i=0;i<numseq;i++)
		    {
			m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
			/* if any other matches then we have a collision */
			if(colcheck[m1] >= fplural)
			    iscons = ajFalse;
		    }

		    /*ajDebug("after alt=2 iscons: %B", iscons);*/
		}
		else
		{
		    for(i=0;i<numseq;i++)
		    {
			m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
			if((matching[m1] >= matching[matchingmaxindex] &&
			    m1 != matchingmaxindex &&
			    matrix[m1][matchingmaxindex] < 0.1))
			    iscons = ajFalse;
			if(identical[m1] >= identical[matchingmaxindex] &&
			   m1 != matchingmaxindex &&
			   matrix[m1][matchingmaxindex] > 0.1)
			    iscons = ajFalse;
		    }

		    if(!iscons)
		    {	/* matches failed try identicals */
			if(identical[identicalmaxindex] >= fplural)
			{
			    iscons = ajTrue;
			    /*
			    ** if nothing has an equal or higher match that
			    ** does not match highest then false
			    */
			    for(i=0;i<numseq;i++)
			    {
				m1 = ajSeqcvtGetCodeK(cvt, seqcharptr[i][k]);
				if(identical[m1] >=
				   identical[identicalmaxindex] &&
				   m1 != identicalmaxindex)
				    iscons = ajFalse;
				else if(matching[m1] >=
					matching[identicalmaxindex] &&
					matrix[m1][matchingmaxindex] <= 0.0)
				    iscons = ajFalse;
				else if(m1 == identicalmaxindex)
				    j = i;
			    }

			    if(iscons)
				highindex = j;
			}
		    }

		}
	    }

	    if(identity)
	    {
		j = 0;
		for(i=0;i<numseq;i++)
		    if(seqcharptr[highindex][k] == seqcharptr[i][k])
			j++;

		if(j<identity)
		    iscons = ajFalse;
	    }
	}

	/*
	** Done a full line of residues
	** Boxes have been defined up to this point
	*/
	if(count >= numres )
	{
	    /* check y position for next set */
	    y=y-(yincr*((float)numseq+(float)2.0+((float)consensus*(float)2)));
	    if(y<yincr*((float)numseq+(float)2.0+((float)consensus*(float)2)))
	    {
		/* full page - print it */
		y=ystart-(float)6.0;

		startseq = 0;
		endseq = seqperpage;
		newILstart = newILend;
		newILend = k;
		while(startseq < numseq)
		{
		    /* AJB */
		    /*if(startseq != 0)
		    	ajGraphNewpage(graph, AJFALSE);*/

		    /*ajDebug("Inner loop: startseq: %d numseq: %d endseq: %d\n",
			    startseq, numseq, endseq);*/
		    if(endseq>numseq)
			endseq=numseq;
		    prettyplot_fillinboxes(numseq,ajSeqsetGetLen(seqset),
					   startseq,endseq,
					   newILstart,newILend,
					   numres,resbreak,
					   boxit,boxcol,consensus,
					   ystart,yincr,cvt);
		    startseq = endseq;
		    endseq += seqperpage;
		    ajGraphNewpage(graph, AJFALSE);
		}
	    }

	    count = 0;
	    gapcount = 0;
	}

	count++;
	countforgap++;

	for(j=0;j<numseq;j++)
	{
	    /* START OF BOXES */

	    if(boxit)
	    {
		seqboxptr[j][k] = 0;
		if(boxindex!=-1)
		{
		    myindex = boxindex;
		    if(matrix[ajSeqcvtGetCodeK(cvt, seqcharptr[j][k])]
		       [ajSeqcvtGetCodeK(cvt, seqcharptr[myindex][k])] > 0)
			part = 1.0;
		    else
		    {
			if(identical[ajSeqcvtGetCodeK(cvt,
                                                      seqcharptr[j][k])] >=
			   fplural)
			    part = 1.0;
			else
			    part = 0.0;
		    }

		    if(previous[j] != part)
			/* draw vertical line */
			seqboxptr[j][k] |= BOXLEF;

		    if(j==0)
		    {
			/* special case for horizontal line */
			if(part)
			{
			    currentstate = 1;
			    /* draw hori line */
			    seqboxptr[j][k] |= BOXTOP;
			}
			else
			    currentstate = 0;
		    }
		    else
		    {
			/* j != 0  Normal case for horizontal line */
			if(part != currentstate)
			{
			    /*draw hori line */
			    seqboxptr[j][k] |= BOXTOP;
			    currentstate = (ajint) part;
			}
		    }

		    if(j== numseq-1 && currentstate)
			/* draw horiline at bottom */
			seqboxptr[j][k] |= BOXBOT;

		    previous[j] = (ajint) part;
		}
		else
		{
		    part = 0;
		    if(previous[j])
		    {
			/* draw vertical line */
			seqboxptr[j][k] |= BOXLEF;
		    }
		    previous[j] = 0;
		}

		if(count == numres || k == kmax || countforgap >= resbreak )
		{			/* last one on the row or a break*/
		    if(previous[j])
		    {
			/* draw vertical line */
			seqboxptr[j][k] |= BOXRIG;
		    }
		    previous[j] = 0;
		}

	    } /* end box */

	    if(boxit && boxcol)
		if(boxindex != -1)
		{
		    myindex = boxindex;
		    if(matrix[ajSeqcvtGetCodeK(cvt, seqcharptr[j][k])]
		       [ajSeqcvtGetCodeK(cvt, seqcharptr[myindex][k])] > 0
		       || identical[ajSeqcvtGetCodeK(cvt, seqcharptr[j][k])] >=
                       fplural )

			seqboxptr[j][k] |= BOXCOLOURED;
		}

	    /* END OF BOXES */




	    if(ajSeqcvtGetCodeK(cvt, seqcharptr[j][k]))
		res[0] = seqcharptr[j][k];
	    else
		res[0] = '-';

	    if(colourbyconsensus)
	    {
		part = (float) matrix[ajSeqcvtGetCodeK(cvt, seqcharptr[j][k])]
		    [ajSeqcvtGetCodeK(cvt, seqcharptr[highindex][k])];
		if(iscons && seqcharptr[highindex][k] == seqcharptr[j][k])
		    seqcolptr[j][k] = cidentity;
		else if(part > 0.0)
		    seqcolptr[j][k] = csimilarity;
		else
		    seqcolptr[j][k] = cother;
	    }
	    else if(colourbyresidues)
		seqcolptr[j][k] = colmat[ajSeqcvtGetCodeK(cvt,
                                                          seqcharptr[j][k])];
	    else if(iscons && colourbyshade)
	    {
		part = (float) matrix[ajSeqcvtGetCodeK(cvt, seqcharptr[j][k])]
		    [ajSeqcvtGetCodeK(cvt, seqcharptr[highindex][k])];
		if(part >= 1.5)
		    seqcolptr[j][k] = shadecolour[0];
		else if(part >= 1.0)
		    seqcolptr[j][k] = shadecolour[1];
		else if(part >= 0.5)
		    seqcolptr[j][k] = shadecolour[2];
		else
		    seqcolptr[j][k] = shadecolour[3];
	    }
	    else if(colourbyshade)
		seqcolptr[j][k] = shadecolour[3];
	    else
		seqcolptr[j][k] = BLACK;
	}

	if(consensus)
	{
	    if(iscons)
		res[0] = seqcharptr[highindex][k];
	    else
		res[0] = '-';
	    strcat(constr,res);
	}

	if(countforgap >= resbreak)
	{
	    gapcount++;
	    countforgap=0;
	}
    }


    startseq = 0;
    endseq=seqperpage;
    newILstart = newILend;
    newILend = k;
    while(startseq < numseq)
    {
	if(startseq)
	    ajGraphNewpage(graph, AJFALSE);

	/*ajDebug("Final loop: startseq: %d numseq: %d endseq: %d\n",
		startseq, numseq, endseq);*/
	if(endseq>numseq)
	    endseq = numseq;
	prettyplot_fillinboxes(numseq,ajSeqsetGetLen(seqset),
			       startseq,endseq,
			       newILstart,newILend,
			       numres,resbreak,
			       boxit,boxcol,consensus,
			       ystart,yincr,cvt);
	startseq = endseq;
	endseq += seqperpage;
    }


    ajGraphicsGetCharsize(&defheight,&currentscale);

    if(boxit && boxcol)
	oldfg = ajGraphicsSetFgcolour(oldfg);

    ajGraphicsCloseWin();
    ajGraphxyDel(&graph);

    ajStrDel(&sidentity);
    ajStrDel(&ssimilarity);
    ajStrDel(&sother);
    ajStrDel(&options);
    ajStrDel(&altstr);

    ajStrDel(&matcodes);

    for(i=0;i<numseq;i++)
    {
	ajStrDel(&seqnames[i]);
	AJFREE(seqcolptr[i]);
	if(seqboxptr)
            AJFREE(seqboxptr[i]);
    }
    AJFREE(seqcolptr);
    AJFREE(seqboxptr);

    AJFREE(seqnames);
    AJFREE(score);
    AJFREE(previous);
    AJFREE(seqcount);

    AJFREE(colmat);
    AJFREE(shadecolour);

    freeptr = (void *) seqcharptr;
    AJFREE(freeptr);

    AJFREE(identical);
    AJFREE(matching);
    AJFREE(colcheck);

    ajSeqsetDel(&seqset);
    ajMatrixDel(&cmpmatrix);
    ajStrDel(&shade);
    ajStrDel(&sboxcolval);
    ajStrDel(&sidentity);
    ajStrDel(&ssimilarity);
    ajStrDel(&sother);
    ajFloatDel(&pair);
    ajTimeDel(&ajtime);
    AJFREE(constr);

    embExit();

    return 0;
}
int main(int argc, char **argv)
{
    AjPSeqset seqset;
    AjPSeqall seqall;
    AjPSeq queryseq;
    const AjPSeq targetseq;
    ajint wordlen;
    AjPTable wordsTable = NULL;
    AjPList* matchlist = NULL;
    AjPFile logfile;
    AjPFeattable* seqsetftables = NULL;
    AjPFeattable seqallseqftable = NULL;
    AjPFeattabOut ftoutforseqsetseq = NULL;
    AjPFeattabOut ftoutforseqallseq = NULL;
    AjPAlign align = NULL;
    AjIList iter = NULL;
    ajint targetstart;
    ajint querystart;
    ajint len;
    ajuint i, j;
    ajulong nAllMatches = 0;
    ajulong sumAllScore = 0;
    AjBool dumpAlign = ajTrue;
    AjBool dumpFeature = ajTrue;
    AjBool checkmode = ajFalse;
    EmbPWordRK* wordsw = NULL;
    ajuint npatterns = 0;
    ajuint seqsetsize;
    ajuint nmatches;
    ajuint* nmatchesseqset;
    ajuint* lastlocation; /* Cursors for Rabin-Karp search. */
                          /* Shows until what point the query sequence was
                           *  scanned for a pattern sequences in the seqset.
                          */
    char* paddedheader = NULL;
    const char* header;
    AjPStr padding;

    header = "Pattern %S  #pat-sequences  #all-matches  avg-match-length\n";
    padding = ajStrNew();

    embInit("wordmatch", argc, argv);

    wordlen = ajAcdGetInt("wordsize");
    seqset  = ajAcdGetSeqset("asequence");
    seqall  = ajAcdGetSeqall("bsequence");
    logfile = ajAcdGetOutfile("logfile");
    dumpAlign = ajAcdGetToggle("dumpalign");
    dumpFeature = ajAcdGetToggle("dumpfeat");

    if(dumpAlign)
    {
        align = ajAcdGetAlign("outfile");
        ajAlignSetExternal(align, ajTrue);
    }

    seqsetsize = ajSeqsetGetSize(seqset);
    ajSeqsetTrim(seqset);
    AJCNEW0(matchlist, seqsetsize);
    AJCNEW0(seqsetftables, seqsetsize);
    AJCNEW0(nmatchesseqset, seqsetsize);

    if (dumpFeature)
    {
        ftoutforseqsetseq =  ajAcdGetFeatout("aoutfeat");
        ftoutforseqallseq =  ajAcdGetFeatout("boutfeat");
    }

    checkmode = !dumpFeature && !dumpAlign;
    embWordLength(wordlen);

    ajFmtPrintF(logfile, "Small sequence/file for constructing"
	    " target patterns: %S\n", ajSeqsetGetUsa(seqset));
    ajFmtPrintF(logfile, "Large sequence/file to be scanned"
	    " for patterns: %S\n", ajSeqallGetUsa(seqall));
    ajFmtPrintF(logfile, "Number of sequences in the patterns file: %u\n",
            seqsetsize);
    ajFmtPrintF(logfile, "Pattern/word length: %u\n", wordlen);

    for(i=0;i<seqsetsize;i++)
    {
        targetseq = ajSeqsetGetseqSeq(seqset, i);
        embWordGetTable(&wordsTable, targetseq);
    }

    AJCNEW0(lastlocation, seqsetsize);

    if(ajTableGetLength(wordsTable)>0)
    {
        npatterns = embWordRabinKarpInit(wordsTable,
                                       &wordsw, wordlen, seqset);
        ajFmtPrintF(logfile, "Number of patterns/words found: %u\n", npatterns);

        while(ajSeqallNext(seqall,&queryseq))
        {
            for(i=0;i<seqsetsize;i++)
            {
                lastlocation[i]=0;

                if (!checkmode)
                    matchlist[i] = ajListstrNew();
            }

            nmatches = embWordRabinKarpSearch(
                    ajSeqGetSeqS(queryseq), seqset,
                    (EmbPWordRK const *)wordsw, wordlen, npatterns,
                    matchlist, lastlocation, checkmode);
            nAllMatches += nmatches;

            if (checkmode)
        	continue;

            for(i=0;i<seqsetsize;i++)
            {
                if(ajListGetLength(matchlist[i])>0)
                {
                    iter = ajListIterNewread(matchlist[i]) ;

                    while(embWordMatchIter(iter, &targetstart, &querystart, &len,
                            &targetseq))
                    {
                        if(dumpAlign)
                        {
                            ajAlignDefineSS(align, targetseq, queryseq);
                            ajAlignSetScoreI(align, len);
                            /* ungapped alignment means same length
                             *  for both sequences
                            */
                            ajAlignSetSubRange(align, targetstart, 1, len,
                                    ajSeqIsReversed(targetseq),
                                    ajSeqGetLen(targetseq),
                                    querystart, 1, len,
                                    ajSeqIsReversed(queryseq),
                                    ajSeqGetLen(queryseq));
                        }
                    }

                    if(dumpAlign)
                    {
                	ajAlignWrite(align);
                	ajAlignReset(align);
                    }

                    if(ajListGetLength(matchlist[i])>0 && dumpFeature)
                    {
                        embWordMatchListConvToFeat(matchlist[i],
                                                   &seqsetftables[i],
                                                   &seqallseqftable,
                                                   targetseq, queryseq);
                        ajFeattableWrite(ftoutforseqallseq, seqallseqftable);
                        ajFeattableDel(&seqallseqftable);
                    }

                    ajListIterDel(&iter);
                }

                embWordMatchListDelete(&matchlist[i]);
            }
        }

        /* search completed, now report statistics */
        for(i=0;i<npatterns;i++)
        {
            sumAllScore += wordsw[i]->lenMatches;

            for(j=0;j<wordsw[i]->nseqs;j++)
        	nmatchesseqset[wordsw[i]->seqindxs[j]] +=
        		wordsw[i]->nSeqMatches[j];
        }

        ajFmtPrintF(logfile, "Number of sequences in the file scanned "
                "for patterns: %u\n", ajSeqallGetCount(seqall));
        ajFmtPrintF(logfile, "Number of all matches: %Lu"
                " (wordmatch finds exact matches only)\n", nAllMatches);

        if(nAllMatches>0)
        {
            ajFmtPrintF(logfile, "Sum of match lengths: %Lu\n", sumAllScore);
            ajFmtPrintF(logfile, "Average match length: %.2f\n",
        	    sumAllScore*1.0/nAllMatches);

            ajFmtPrintF(logfile, "\nDistribution of the matches among pattern"
        	    " sequences:\n");
            ajFmtPrintF(logfile, "-----------------------------------------"
        	    "-----------\n");

            for(i=0;i<ajSeqsetGetSize(seqset);i++)
            {
        	if (nmatchesseqset[i]>0)
        	    ajFmtPrintF(logfile, "%-42s: %8u\n",
        	                ajSeqGetNameC(ajSeqsetGetseqSeq(seqset, i)),
        	                nmatchesseqset[i]);

        	ajFeattableWrite(ftoutforseqsetseq, seqsetftables[i]);
        	ajFeattableDel(&seqsetftables[i]);
            }

            ajFmtPrintF(logfile, "\nPattern statistics:\n");
            ajFmtPrintF(logfile, "-------------------\n");
            if(wordlen>7)
        	ajStrAppendCountK(&padding, ' ', wordlen-7);
            paddedheader = ajFmtString(header,padding);
            ajFmtPrintF(logfile, paddedheader);

            for(i=0;i<npatterns;i++)
        	if (wordsw[i]->nMatches>0)
        	    ajFmtPrintF(logfile, "%-7s: %12u  %12u %17.2f\n",
        	                wordsw[i]->word->fword, wordsw[i]->nseqs,
        	                wordsw[i]->nMatches,
        	                wordsw[i]->lenMatches*1.0/wordsw[i]->nMatches);
        }

    }

    for(i=0;i<npatterns;i++)
    {
        for(j=0;j<wordsw[i]->nseqs;j++)
            AJFREE(wordsw[i]->locs[j]);

        AJFREE(wordsw[i]->locs);
        AJFREE(wordsw[i]->seqindxs);
        AJFREE(wordsw[i]->nnseqlocs);
        AJFREE(wordsw[i]->nSeqMatches);
        AJFREE(wordsw[i]);
    }

    embWordFreeTable(&wordsTable);

    AJFREE(wordsw);
    AJFREE(matchlist);
    AJFREE(lastlocation);
    AJFREE(nmatchesseqset);
    AJFREE(seqsetftables);

    if(dumpAlign)
    {
        ajAlignClose(align);
        ajAlignDel(&align);
    }

    if(dumpFeature)
    {
        ajFeattabOutDel(&ftoutforseqsetseq);
        ajFeattabOutDel(&ftoutforseqallseq);
    }

    ajFileClose(&logfile);

    ajSeqallDel(&seqall);
    ajSeqsetDel(&seqset);
    ajSeqDel(&queryseq);
    ajStrDel(&padding);
    AJFREE(paddedheader);

    embExit();

    return 0;
}