/*    blpssm.c  Make various pssms from blocks
         blpssm  <config file>

	<config file> must contain:
	BL	blocks database to make PSSMs from (input)
	EX	PSSM database output file
	OU      observed frequencies output file
	FR	frequency file
        GR	substitution matrix for Gribskov ratios
	GQ	qij matrix for Gribskov
	DI	Dirichlet mixtures file for pseudo counts
  	AL	R qij matrix file for Altschul pseudo counts (AL = RC + AQ)
	AQ	qij matrix file for Altschul pseudo counts
	RC	R => tot. # pseudos = R * #residues 
	BC	B = total number of pseudos in a column
	ST	min max qij   Multiple entries for Steve's method
	CL	substitution matrix file for pseudo counts
	GI	make simple background pseudo counts like Gibbs does
        LO	use natural log scores (DI, CL or GI only)
	BR	get counts using Bill Bruno's method instead of seq wts
	HY	hybrid counts; nseq from Bruno, counts from seq wts
	HC	% hybrid counts; nseq from % clumping, counts from seq wts
	NN	YES => set all real counts to zero
	PA	min_score  pattern_output_file
	FP	Output matrix in floating point format

	If DI or CL, must have FR
	If just FR, makes usual PATMAT PSSM
>>> should change struct dirichlet to use struct diri in blimps convert.h <<<
--------------------------------------------------------------------
 6/30/94 J. Henikoff 
 7/ 2/94 Added log option for make_diri()
 7/ 4/94 Changed log calculations to make a positive PSSM by
         subtracting the min. log value for the entire matrix
         from every entry in the matrix, rather than doing each
         position separately.
 7/ 7/94 Changed load_subst() to make matrix non-neg. if nec.
         Added make_clav()  CL option
 7/11/94 Added make_gribs() GR option
 8/10/94 Added make_gibbs()  GI option, simple pseudo counts like Gibbs
         Cleaned up code
         Changed from 0,AASALL to 1,AAS for all but make_gribs()
 8/18/94 Added load_qij()
 8/29/94 Added make_gribq() GQ option - doesn't work, scaling problem
 8/31/94 Added counts_bruno() BR option.
 9/ 4/94 Multiply final matrices to give score range b/w 0 and 99 (final).
 9/ 7/94 Make sure multiplying by a number >= 1.0.
 9/15/94 Added counts_hybrid() HY option.
	 Added counts_clumps() HC option.
 9/26/94 Added Steve's elaboration of Altschul's method
10/31/94 Changed make_matrix() to add seqs= to matrix->ma if not in block
-------------------Added to /howard/local/bin----------------------------
12/ 7/94 Also outputs the observed frequencies, with pseudo counts.
 1/16/95 Changed pseudo-count count from sqrt(n) to 1/n for GI & AL
 1/18/95 Changed pseudo-count count from 1/n to column entropy for GI & AL,
         added compute_entropy()
	 Changed pseudo-count count from entropy to #residues for GI & AL,
         added count_residues()
 1/28/95 Modified Steve's method; use a different substitution matrix
         for every column of a block, not just for every block.
	 Added ratio_counts(), make_steves()
 1/30/95 Fixed problem with too many FILEs in make_steves(). 
	 NOTE: This routine is currently very inefficient, reads qij
         file over for each column!
 2/ 8/95 Changed pseudo_count count from #residues to RTot * # residues for
	 GI, AL, ST
 2/ 8/95 Changed pseudo_alts() to use unweighted counts for pseudo
         counts (not sequence-weighted). Counts are still seq-wted
	 Modified struct working, counts(), pseudo_alts().
 2/15/95 Changed pseudo_alts() back to use weighted counts.
 2/19/95 Made RTot a parameter on the AL option
 2/19/95 Added bruno_rind() & changed counts_bruno() to use Bruno's
         new rind program.
 2/26/95 Initialized col stuff in counts_bruno().
 3/20/95 Changed default RTOT from 1.0 to 5.0; applies to make_gibbs() also.
 3/30/95 Changed make_gibbs() back to use sqrt(N).
         Changed make_gribs() to rescale between 0 and 99; added positive_matrix()
 4/ 6/95 Added free_block() & also freed other data structures.
 4/ 8/95 Changed all counting routines so B->D, Z->E and only the 20
         real aas are counted. Therefore, column counts may not add to
	 the number of sequences if a column contains "-" or "X".
 4/12/95 Changed Gribskov to score B,Z,X,- & * like the other methods.
 5/28/95 Added PA option, PA lines to PSSM
 6/29/95 Write PA lines to a separate file
 7/ 7/95 Fixed problem in add_patterns() when only one pattern.
 7/12/95 Fixed problem in make_col() initialization.
 8/30/95 Added AQ, RC, BC and NN parameters (AL = RC + AQ)
	 Added BTot variable = total # pseudos in a column
 9/11/95 Changed GQ, make_gribq() to use log-odds 
10/ 2/95 Changed strnicmp() to strncasecmp()
 4/24/96 Initialized matrix->patterns in make_matrix() - caused abort with
	 prints.cf input file.
 7/ 4/96 Updated Bruno counts for new version of rind program.
 9/19/96 Added option for floating point output (FP, FloatPt);
	 matrices aren't re-scaled at all in this case.
 11/25/97 Increased MAXWIDTH from 60 to 200 for Bork's groups
  5/26/00 Modified to use BLIMPS libraries; MAXWIDTH to 400
 12/23/00 MAXWIDTH replaced by EXTRA_LARGE_BUFF, MAXNSEQ to 1000
====================================================================*/

#define BLPSSM_C_
#define EXTERN

#include <blocksprogs.h>
#include <math.h>

#define FNAMELEN 80
#define AAS 21
#define AASALL 26
/* 0- 1A 2R 3N 4D 5C 6Q 7E 8G 9H 10I 11L 12K 13M 14F 15P 16S 17T 18W 19Y
   20V 21B 22Z 23X 24* 25J,O,U */
#define MAXCOMP 40			/* Max. # of Dirichlet components */
#define MAXNSEQ 1000			/* Max. # seqs in a block */
#define MAXMAT 10			/* Max. #matrices for Steve's method*/
#define PATCUT 90			/* Default pattern cutoff score */
#define RTOT 5.0			/* Total #pseudos in col  = RTOT * R*/
#define BTOT 25.0			/* Total # pseudos in col */
#define PI 3.141592654
/*   INDEX & INDEXCOL compute the sequential indices for the lower half of an
     nxn symmetric matrix given row & column coordinates.  Lower half has
     n(n-1)/2 entries; col=0,n-2 and row=col+1,n-1; col has n-col-1 rows.
     Index runs from 0 to n(n-1)/2 - 1 down columns with
     (index=0)==(col=0,row=1) and (index=n(n-1)/2-1)==(col=n-2,row=n-1).  */
#define INDEXCOL(n, col)    ( col*n - (col*(col+1))/2 )
#define INDEX(n, col, row)  ( col*n - (col*(col+3))/2 - 1 + row )

struct dirichlet {	/* Dirichlet mixture information */
   int ncomp;		/* number of components */
   double q[MAXCOMP];
   double altot[MAXCOMP];
   double alpha[MAXCOMP][AAS];
};

struct clump_work {
   int cluster[MAXNSEQ], ncluster[MAXNSEQ], nclus[MAXNSEQ];
};

struct working {	/* Working information for one column */
   double cnt[AASALL];		/* Sequence-weighted counts */
   double totcnt;
   double raw[AASALL];		/* unweighted counts */
   double totraw;
   double probn[MAXCOMP];
   double probj[MAXCOMP];
   double reg[AASALL];		/*  pseudo counts */
   double totreg;
};

struct work_pssm {		/* Working PSSM area */
   double value[EXTRA_LARGE_BUFF][AASALL];
   double sum[EXTRA_LARGE_BUFF];
};

struct steve {
   double nmin, nmax;		/* min & max diag/off-diag ratio for col */
   char qijname[FNAMELEN];
};

int read_cf();
void load_subst();
struct dirichlet *load_diric();
double nrgamma();
double addlogs();
struct working *make_col();
struct work_pssm *make_pssm();
Matrix *make_matrix();
Matrix *make_diri();
Matrix *make_grib();
Matrix *make_gribq();
Matrix *make_clav();
Matrix *make_alts();
Matrix *make_patmat();
Matrix *make_gibbs();
Matrix *make_steves();
FILE *steves_qij();
void counts();
void counts_hybrid();
void counts_clumps();
int clump_seqs();
void pseudo_diric();
void pseudo_clav();
void pseudo_alts();
void pseudo_gibbs();
double compute_entropy();
int count_residues();
double ratio_counts();
void fillin();
void final();
void compute_BZX();
void positive_matrix();
void add_patterns();
/*     Bill Bruno's rind program   */
struct work_pssm *bruno_rind();
void counts_bruno();

/*-------------global variables ----------------------------------------*/
FILE *Fbl, *Fex, *Fou, *Ffr, *Fal, *Fdi, *Fcl, *Fgr, *Fgq;  /* files */
FILE *Fpa;
int LogScores;				/* take natural log of scores */
struct steve *Steve[MAXMAT];			/* Steve's parameters */
int BrunoCounts;			/* use Bill Bruno's counts */
int HybridCounts;			/* use hybrid counts */
int ClumpCounts;			/* use hybrid clump counts */
int NoCounts;				/* don't use actual counts */
int FloatPt;				/* floating point output */
int ClumpTot;				/* # of clumps in block */
int PatternCutoff;			/* pattern cutoff score */
double RTot;				/* B_c = RTot * # residues */
double BTot;				/* B_c = BTot = Total pseudos */
/*    Dirichlet stuff */
double LCof = 2.50662827465;	/* sqrt(2*PI)  */
double Cof[6] = {76.18009173, -86.50532033, 24.01409822, -1.231739516,
                  0.120858003e-2, -0.536382e-5};
double Log2;
/*     Bruno stuff */
/*   blimps[aa] == bruno[ Bruno_Order[aa] ]     */
int Bruno_Order[AASALL] = {1, 21, 5, 4, 7, 14, 8, 9, 10, 23, 12, 11, 13,
        3, 23, 15, 6, 2, 16, 17, 23, 20, 18, 23, 19, 22};

/*=====================================================================
 * main
 */

int main(argc, argv)
     int argc;
     char *argv[];
{
   FILE *cfp;
   Block *block;
   int type;
   char cfname[FNAMELEN];
   double freqs[AASALL], subst[AASALL][AASALL];
   struct float_qij *qij;
   struct dirichlet *diric;
   Matrix *matrix, *obs_freqs;

   Log2 = log(2.0);
/* ------------1st arg = configuration file ----------------------------*/
   if (argc > 1)
      strcpy(cfname, argv[1]);
   else
   {
      printf("\nEnter name of configuration file: ");
      gets(cfname);
   }
   if ( (cfp=fopen(cfname, "r")) == NULL)
   {
      printf("\nCannot open file %s\n", cfname);
      exit(-1);
   }
   type = read_cf(cfp);
   if (type <= 0)
   {
      printf("\nConfiguration file errors\n");
      exit(-1);
   }
   else
   {
      switch(type)
      {
         case 1:
            printf("Using PATMAT algorithm...\n");
            break;
        case 2:		/* Gribskov profile */
           printf("Using Gribskov algorithm...\n");
           break;
        case 3:		/* Altschul's pseudo-counts */
           printf("Using Altschul's pseudo-counts...\n");
           break;
        case 4:		/* Claverie's pseudo-counts */
	   printf("Using Claverie pseudo-counts...\n");
           break;
        case 5:		/* Dirichlet pseudo-counts */
           printf("Using Dirichlet pseudo-counts\n");
           break;
        case 6:		/* simple background pseudo-counts */
           printf("Using background pseudo-counts (like Gibbs)\n");
           break;
        case 7:		/* Gribskov profile with qij */
           printf("Using Gribskov algorithm with qij...\n");
           break;
 	case 8:		/* Steve's method */
	   printf("Using Steve's method...\n");
	   printf("WARNING: Parameters are not checked for validity!\n");
           break;
        default:
           break;
      }
   }

/*----------------------------------------------------------------------*/
  if (Ffr != NULL) load_frequencies(Ffr, freqs);
  if (type == 2) load_subst(Fgr, subst);
  if (type == 3) qij = load_qij(Fal);
  if (type == 4) load_subst(Fcl, subst);
  if (type == 5) diric = load_diric(Fdi);
  if (type == 7) qij = load_qij(Fgq);

  while ((block = read_a_block(Fbl)) != NULL)
  {
     normalize(block);
     if (ClumpCounts) ClumpTot = clump_seqs(block);
     if (Fou != NULL) obs_freqs = make_matrix(block);
     switch (type)
     {
        case 1:		/* Patmat odds ratios */
           matrix = make_patmat(block, freqs, obs_freqs);
           break;
        case 2:		/* Gribskov profile */
           matrix = make_grib(block, subst, obs_freqs);
           break;
        case 3:		/* Altschul's pseudo-counts */
           matrix = make_alts(block, freqs, qij, obs_freqs); 
           break;
        case 4:		/* Claverie's pseudo-counts */
           matrix = make_clav(block, freqs, subst, obs_freqs);
           break;
        case 5:		/* Dirichlet pseudo-counts */
           matrix = make_diri(block, freqs, diric, obs_freqs);
           break;
        case 6:		/* simple background pseudo-counts */
           matrix = make_gibbs(block, freqs, obs_freqs);
           break;
        case 7:		/* Gribskov profile with qij */
           matrix = make_gribq(block, qij, obs_freqs);
           break;
	case 8:		/* Steve's method */
	   matrix = make_steves(block, freqs, obs_freqs);
	   break;
        default:
           break;
     }
     if (matrix != NULL)
     {
        if (!FloatPt) output_matrix(matrix, Fex);
        else          output_matrix_s(matrix, Fex, 1); /* FLOAT_OUTPUT == 1 */
        if (PatternCutoff && Fpa != NULL)  add_patterns(matrix, Fpa);
        free_matrix(matrix);
     }
     if (obs_freqs != NULL)
     {
        output_matrix(obs_freqs, Fou);
        free_matrix(obs_freqs);
     }
     free_block(block);
  }
   
  fclose(Fbl); fclose(Fex);
  if (Fpa != NULL) fclose(Fpa);
  if (Fou != NULL) fclose(Fou);
  exit(0);

}  /* end of main */
/*=======================================================================*/
int read_cf(cfp)
FILE *cfp;
{
   int type, gibbs, nsteve;
   char line[MAXLINE], keyword[20], *ptr;
   char blname[FNAMELEN], exname[FNAMELEN], frname[FNAMELEN];
   char alname[FNAMELEN], diname[FNAMELEN], clname[FNAMELEN];
   char grname[FNAMELEN], gqname[FNAMELEN], ouname[FNAMELEN];
   char paname[FNAMELEN];

   type = 0;
   gibbs = FALSE;
   Fbl = Fex = Fpa = Fou = Ffr = Fal = Fdi = Fcl = Fgr = Fgq = NULL;
   for (nsteve = 0; nsteve < MAXMAT; nsteve++) Steve[nsteve] = NULL;
   nsteve = 0;
   BTot = RTot = -1;
   LogScores = BrunoCounts = HybridCounts = ClumpCounts = NoCounts = FALSE;
   FloatPt = FALSE;
   PatternCutoff = 0;
   while (!feof(cfp) && fgets(line, MAXLINE, cfp) != NULL)
   {
      ptr = strtok(line, " \t\r\n");
      if (ptr != NULL && ptr[0] != ';')
      {
         strcpy(keyword,ptr);
         ptr = strtok(NULL, " \t\r\n;");
         if (ptr != NULL)
         {
            if (strncasecmp(keyword, "BL", 2) == 0)
            {
               strcpy(blname, ptr);
               if ( (Fbl = fopen(blname, "r")) == NULL)
                  printf("\nCannot open BL file %s\n", blname);
            }
            else if (strncasecmp(keyword, "EX", 2) == 0)
            {
               strcpy(exname, ptr);
               if ( (Fex = fopen(exname, "w")) == NULL)
                  printf("\nCannot open EX file %s\n", exname);
            }
            else if (strncasecmp(keyword, "OU", 2) == 0)
            {
               strcpy(ouname, ptr);
               if ( (Fou = fopen(ouname, "w")) == NULL)
                  printf("\nCannot open OU file %s\n", ouname);
            }
            else if (strncasecmp(keyword, "FR", 2) == 0)
            {
               strcpy(frname, ptr);
               if ( (Ffr = fopen(frname, "r")) == NULL)
                  printf("\nCannot open FR file %s\n", frname);
            }
            else if (strncasecmp(keyword, "AL", 2) == 0)
            {
               RTot = atof(ptr);
	       if (RTot < 0.0) RTot = RTOT;
	       ptr = strtok(NULL, " \t\r\n");
               strcpy(alname, ptr);
               if ( (Fal = fopen(alname, "r")) == NULL)
                  printf("\nCannot open AL file %s\n", alname);
            }
            else if (strncasecmp(keyword, "RC", 2) == 0)
            {
               RTot = atof(ptr);
	       if (RTot < 0.0) RTot = RTOT;
            }
            else if (strncasecmp(keyword, "BC", 2) == 0)
            {
               BTot = atof(ptr);
	       if (BTot < 0.0) BTot = BTOT;
            }
            else if (strncasecmp(keyword, "AQ", 2) == 0)
            {
               strcpy(alname, ptr);
               if ( (Fal = fopen(alname, "r")) == NULL)
                  printf("\nCannot open AQ file %s\n", alname);
            }
            else if (strncasecmp(keyword, "ST", 2) == 0)
            {
               if (Steve[nsteve] == NULL)
	   Steve[nsteve] = (struct steve *) malloc(sizeof(struct steve));
	       if (Steve[nsteve] == NULL)
               {
                   printf("\nread_cf: OUT OF MEMORY\n");
                   exit(-1);
               }
               Steve[nsteve]->nmin = atof(ptr);
               ptr = strtok(NULL, " \t\r\n");
               Steve[nsteve]->nmax = atof(ptr);
               ptr = strtok(NULL, " \t\r\n");
	       strcpy(Steve[nsteve]->qijname, ptr);
               nsteve++;
            }
            else if (strncasecmp(keyword, "GR", 2) == 0)
            {
               strcpy(grname, ptr);
               if ( (Fgr = fopen(grname, "r")) == NULL)
                  printf("\nCannot open GR file %s\n", grname);
            }
            else if (strncasecmp(keyword, "GQ", 2) == 0)
            {
               strcpy(gqname, ptr);
               if ( (Fgq = fopen(gqname, "r")) == NULL)
                  printf("\nCannot open GQ file %s\n", gqname);
            }
            else if (strncasecmp(keyword, "DI", 2) == 0)
            {
               strcpy(diname, ptr);
               if ( (Fdi = fopen(diname, "r")) == NULL)
                  printf("\nCannot open DI file %s\n", diname);
            }
            else if (strncasecmp(keyword, "CL", 2) == 0)
            {
               strcpy(clname, ptr);
               if ( (Fcl = fopen(clname, "r")) == NULL)
                  printf("\nCannot open CL file %s\n", clname);
            }
            else if (strncasecmp(keyword, "LO", 2) == 0)
            {
                if (ptr[0] == 'y' || ptr[0] == 'Y' ||
                    ptr[0] == 't' || ptr[0] == 'T')
		LogScores = TRUE;
            }
            else if (strncasecmp(keyword, "BR", 2) == 0)
            {
                if (ptr[0] == 'y' || ptr[0] == 'Y' ||
                    ptr[0] == 't' || ptr[0] == 'T')
		BrunoCounts = TRUE;
            }
            else if (strncasecmp(keyword, "HY", 2) == 0)
            {
                if (ptr[0] == 'y' || ptr[0] == 'Y' ||
                    ptr[0] == 't' || ptr[0] == 'T')
		HybridCounts = TRUE;
            }
            else if (strncasecmp(keyword, "NN", 2) == 0)
            {
                if (ptr[0] == 'y' || ptr[0] == 'Y' ||
                    ptr[0] == 't' || ptr[0] == 'T')
		NoCounts = TRUE;
            }
            else if (strncasecmp(keyword, "FP", 2) == 0)
            {
                if (ptr[0] == 'y' || ptr[0] == 'Y' ||
                    ptr[0] == 't' || ptr[0] == 'T')
		FloatPt = TRUE;
            }
            else if (strncasecmp(keyword, "HC", 2) == 0)
            {
		ClumpCounts = atoi(ptr);
		if (ClumpCounts < 0 || ClumpCounts > 100) ClumpCounts = 0;
            }
            else if (strncasecmp(keyword, "GI", 2) == 0)
            {
               gibbs = TRUE;
            }
            else if (strncasecmp(keyword, "PA", 2) == 0)
            {
		PatternCutoff = atoi(ptr);
		if (PatternCutoff < 0 || PatternCutoff > 100)
			 PatternCutoff = PATCUT;
	        ptr = strtok(NULL, " \t\r\n");
                strcpy(paname, ptr);
                if ( (Fpa = fopen(paname, "w")) == NULL)
                  printf("\nCannot open PA file %s\n", paname);
            }
         }   /* end of if ptr */
      }  /* end of if ptr */
   }  /* end of cfp */
   /*   Set PSSM type:  1 is Patmat (FR)
                        2 is Gribskov (GR)
                        3 is Altschul pseudo counts (FR & AL)
                        4 is Claverie pseudo counts (FR & CL)     
                        5 is Dirichlet pseudo counts (FR & DI) 
                        6 is Gibbs pseudo counts (FR) 
			7 is Gribskov with qij (GQ)
			8 is Steve's (ST)
   */
   /*    Can only have one type of total pseudo counts */
   if (RTot > 0 && BTot > 0)  BTot = -1;
   type = 0;
   /* If only have FR; PSSM type = 1 */
   if (Ffr != NULL && Fdi == NULL && Fal == NULL && Fcl == NULL && 
       Fgr == NULL && Fgq == NULL)
       type = 1;
   /*  Steve's method is type 8 */
   if (Ffr != NULL && Steve[0] != NULL && nsteve >= 1)
   {
      type = 8;
      if (Fdi != NULL) fclose(Fdi);
      if (Fcl != NULL) fclose(Fcl);
      if (Fal != NULL) fclose(Fal);
      if (Fgr != NULL) fclose(Fgr);
   }
   /* If have GR, ignore DI and FR and CL; PSSM type = 2 */
   if (Fgr != NULL)
   {
      type = 2;
      if (Fdi != NULL) fclose(Fdi);
      if (Fcl != NULL) fclose(Fcl);
      if (Fal != NULL) fclose(Fal);
      if (Ffr != NULL) fclose(Ffr);
   }
   /* If have GQ,  PSSM type = 7 */
   if (Fgq != NULL)
   {
      type = 7;
      if (Fdi != NULL) fclose(Fdi);
      if (Fcl != NULL) fclose(Fcl);
      if (Fal != NULL) fclose(Fal);
      if (Ffr != NULL) fclose(Ffr);
   }
   /* If have AL, ignore DI and FR and CL; PSSM type = 3 */
   if (Fal != NULL && Ffr != NULL)
   {
      type = 3;
      if (Fdi != NULL) fclose(Fdi);
      if (Fcl != NULL) fclose(Fcl);
      if (Fgr != NULL) fclose(Fgr);
   }
   /* If have CL, ignore the rest */
   if (Fcl != NULL && Ffr != NULL)
   {
      type = 4;
      if (Fal != NULL) fclose(Fal);
      if (Fdi != NULL) fclose(Fdi);
      if (Fgr != NULL) fclose(Fgr);
   }
   /* If have DI, ignore the rest */
   if (Fdi != NULL && Ffr != NULL)
   {
      type = 5;
      if (Fal != NULL) fclose(Fal);
      if (Fcl != NULL) fclose(Fcl);
      if (Fgr != NULL) fclose(Fgr);
   }
   /*  If have FR and GI, type = 6 */
   if (type == 1 && gibbs) type = 6;

   if (type == 0)
      printf("\nNo valid PSSM type specified\n");
   /* Must always have BL and EX */
   if (Fbl == NULL)
   {
      printf("\nMissing BL (input block) file\n");
      type = 0;
   }
   if (Fex == NULL)
   {
      printf("\nMissing EX (output PSSM) file\n");
      type = 0;
   }

   return(type);
}  /* end of read_cf */
/*======================================================================
=======================================================================*/
FILE *steves_qij(col)
struct working *col;
{
   FILE *fst;
   int i;
   char fname[FNAMELEN];
   double ratio;

   ratio = ratio_counts(col);
   fst = NULL;
   fname[0] = '\0';
   i = 0;
   while (!strlen(fname) && Steve[i] != NULL && i < MAXMAT)
   {
      if (ratio >= Steve[i]->nmin &&
          ratio < Steve[i]->nmax)
             strcpy(fname, Steve[i]->qijname);
      i++;
   }
   if ( (fst=fopen(fname, "r")) == NULL)
   {
      printf("\nCannot open file %s\n", fname);
      exit(-1);
   }

   return(fst);
}  /* end of steves_qij */
/*======================================================================
   Dirichlet input file order (0-19) is  ARNDCQEGHILKMFPSTWYV
   Blimps order (0-24) is               -ARNDCQEGHILKMFPSTWYVBZX*
   Store Dirichlet alphas in positions 1-20 to match blimps
=======================================================================*/
struct dirichlet *load_diric(fin)
FILE *fin;
{
   int aa, numc, type;
   char line[MAXLINE], *ptr;
   struct dirichlet *diric;

   diric = (struct dirichlet *) malloc(sizeof(struct dirichlet));
   if (diric == NULL)
   {
      printf("\nOUT OF MEMORY\n");
      exit(-1);
   }
   numc = 0;
   while (numc < MAXCOMP && !feof(fin) && fgets(line, MAXLINE, fin) != NULL)
   {
      type = 0;
      if (strstr(line, "Mixture=") != NULL) type = 1;
      if (strstr(line, "Alpha=") != NULL)  type = 2;
      if (type > 0)
      {
         ptr = strtok(line, "="); ptr = strtok(NULL, "\t\n\r ");
         switch (type)
         {
	    case 1:
               diric->q[numc] = atof(ptr);
               break;
            case 2:
               diric->altot[numc] = atof(ptr);
               aa = 1;
               while (aa < AAS && ptr != NULL)
               {
                  ptr = strtok(NULL, "\t\n\r ");
                  diric->alpha[numc][aa++] = atof(ptr);
               }
               numc++;
               break;
            default:
               break;
         }
      }
   }  /* end of while */
   diric->ncomp = numc;

   fclose(fin);
   return(diric);
}   /* end of load_diric */
/*===================================================================
    Returns log of gamma using Lanczos' approximation.
    Taken from "Numerical Recipes in C".
    NOTE:  Alternative to Sun's lgamma() function

    gamma(x) = integral(0,infinity) y^(x-1) * e^(-y) dy
      gamma(0.5) = sqrt(pi)
      gamma(1) = gamma(2) = 1
      gamma(x) = (x-1) * gamma(x-1), x > 2
      If x is an integer, gamma(x) = (x-1)!
      gamma(1-x) = (pi * x)/{gamma(1+x) * sine(pi * x)}
===================================================================*/
double nrgamma(x)
double x;
{
   double xx, dtemp, dtemp2, lg, g;
   int j;

   if (x <= 0.0) lg = 0.0;
   else if (x < 1.0)   		/*  use the reflection formula */
   {
     dtemp = PI * (1.0 - x);
     dtemp2 = sin(dtemp);
     lg = log(dtemp) - nrgamma(2.0 - x) - log(dtemp2);
   }
   else
   {

      xx = x - 1.0;
      dtemp = xx + 5.5;
      dtemp -= (xx + 0.5) * log(dtemp);
      dtemp2 = 1.0;
      for (j=0; j <= 5; j++)
      {
          xx += 1.0;
          dtemp2 += Cof[j] / xx;
      }
      lg = -dtemp + log(LCof * dtemp2);
      if (lg <= 50) g = exp(lg);		/* overflows quickly */
      else g = 1e50;
   }

   return(lg);
}  /* end of nrgamma */
/*======================================================================*/
Matrix *make_patmat(block, freqs, obs_freqs)
Block *block;
double *freqs;
Matrix *obs_freqs;
{
   double dtemp, sum, temp[AASALL];
   int pos, aa;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *bruno;

   col = make_col();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);

      sum = 0.0;
      for (aa=1; aa < AAS; aa++)
      {
         if (obs_freqs != NULL)
         {
	    dtemp = 100. * col->cnt[aa] / col->totcnt;
	    obs_freqs->weights[aa][pos] = round(dtemp);
         }
          if (freqs[aa] > 0.0)
             temp[aa] = col->cnt[aa] / freqs[aa];
          else temp[aa] = 0.0;
          sum += temp[aa];
      }
      for (aa=1; aa < AAS; aa++)
      {
         dtemp = 99.0 * temp[aa] / sum;
         matrix->weights[aa][pos] = round(dtemp);
      }
      compute_BZX(freqs, matrix, pos);
   }  /*  end of for pos */

   free(col);
   if (bruno != NULL) free(bruno);
   return(matrix);

}  /* end of make_patmat */

/*==========================================================================
NOTE:  This is essentially the same as make_gribs() in convert.c
     Uses Gribskov's method 
     Assumes a non-negative substition matrix (min. value = 0)
     Sets 20 aas plus B and Z from the matrix; X, etc to zero = min. value
     Index for B is 21, for Z is 22
===========================================================================*/
Matrix *make_grib(block, subst, obs_freqs)
Block *block;
double subst[AASALL][AASALL];
Matrix *obs_freqs;
{
   double dtemp, sum, temp[AASALL];
   int pos, aa, aa1;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *bruno;

   col = make_col();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);

      sum = 0.0;
      for (aa=0; aa <= 22; aa++)
      {
         if (obs_freqs != NULL)
         {
	    dtemp = 100. * col->cnt[aa] / col->totcnt;
	    obs_freqs->weights[aa][pos] = round(dtemp);
         }
         temp[aa] = 0.0;
         for (aa1=1; aa1 <= 22 ; aa1++)
         {
            temp[aa] += col->cnt[aa1] * subst[aa][aa1];
         }
         temp[aa] /= col->totcnt;
         sum += temp[aa];
      }
      for (aa=1; aa <= 22; aa++)
      {
         dtemp = temp[aa];
         matrix->weights[aa][pos] = round(dtemp);
      }
      /*  Set X, * and - to zero */
      matrix->weights[0][pos] = matrix->weights[23][pos] = 0;
      matrix->weights[24][pos] = matrix->weights[25][pos] = 0;
   }  /*  end of for pos */

   free(col);
   if (bruno != NULL) free(bruno);
   /*  scale final matrix to lie between 0 and 99 */
   positive_matrix(block, matrix);
   return(matrix);
}   /*  end of make_grib */
/*==========================================================================
     Uses Gribskov's method with log(qij/pipj) instead of sij
     NOTE: no BZX values
===========================================================================*/
Matrix *make_gribq(block, qij, obs_freqs)
Block *block;
struct float_qij *qij;
Matrix *obs_freqs;
{
   double dtemp, sum, temp[AASALL];
   int pos, aa, aa1, minval;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *bruno;

   col = make_col();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   minval = 99999;			/* min. val in matrix  */
   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);

      sum = 0.0;
      for (aa=1; aa <= 20; aa++)
      {
         if (obs_freqs != NULL)
         {
	    dtemp = 100. * col->cnt[aa] / col->totcnt;
	    obs_freqs->weights[aa][pos] = round(dtemp);
         }
         temp[aa] = 0.0;
         for (aa1=1; aa1 <= 20 ; aa1++)
         {
            dtemp = qij->value[aa][aa1] / (qij->marg[aa] * qij->marg[aa1]);
            dtemp = log(dtemp) / log(2.0);	/* sij scaled in bits */
            temp[aa] += col->cnt[aa1] * dtemp;
         }
         temp[aa] /= col->totcnt;
         sum += temp[aa];
      }
      for (aa=1; aa <= 20; aa++)
      {
         dtemp = 100.0 * temp[aa];	/* beef up weights for scaling */
         matrix->weights[aa][pos] = round(dtemp);  /* weights are ints */
	 if (matrix->weights[aa][pos] < minval)
		minval = matrix->weights[aa][pos];
      }
   }  /*  end of for pos */

   /*  Set B, Z, X, * and - to min. value */
   for (pos = 0; pos < block->width; pos++)
   {
      matrix->weights[0][pos] = matrix->weights[23][pos] = minval;
      matrix->weights[24][pos] = matrix->weights[25][pos] = minval;
      matrix->weights[21][pos] = matrix->weights[22][pos] = minval;
   }

   free(col);
   if (bruno != NULL) free(bruno);
   /*  scale final matrix to lie between 0 and 99 */
   positive_matrix(block, matrix);
   return(matrix);
}   /*  end of make_gribq */
/*==========================================================================
     Uses Altschul's method of getting pseudo-counts with a qij matrix,
===========================================================================*/
Matrix *make_alts(block, freqs, qij, obs_freqs)
Block *block;
double *freqs;
struct float_qij *qij;
Matrix *obs_freqs;
{
   double epsilon;
   int pos;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *pssm, *bruno;

   col = make_col();
   pssm = make_pssm();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   /*--------------  Do one position at a time -------------------*/
   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);
/*      epsilon = sqrt(col->totcnt); 
      epsilon = 1.0 / col->totcnt;
      epsilon += compute_entropy(col); 
*/
      /*    epsilon = total number of pseudo counts in the column   */
      if (RTot >= 0.0) epsilon = (double) RTot * count_residues(col);
      else if (BTot >= 0.0) epsilon = BTot;
      else epsilon = sqrt(col->totcnt);

      /*---------- get the pseudo counts -------------------------------*/
      pseudo_alts(col, qij, epsilon);

      /*---------   Fill in the matrix entries --------------------*/
      fillin(pos, freqs, col, pssm, obs_freqs);

   }  /*  end of for pos */
   /*------ Now make the final scores; make log scores non-neg    */
   /*       by subtracting the min. value for all positions ----- */
   final(block, freqs, pssm, matrix);

   free(col);
   free(pssm);
   if (bruno != NULL) free(bruno);
   return(matrix);
}  /* end of make_alts */
/*==========================================================================
     Uses Steve's modification of
         Altschul's method of getting pseudo-counts with a qij matrix,
         different matrix for each column.
===========================================================================*/
Matrix *make_steves(block, freqs, obs_freqs)
Block *block;
double *freqs;
Matrix *obs_freqs;
{
   double epsilon;
   int pos;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *pssm, *bruno;
   struct float_qij *qij;
   FILE *fin;

   col = make_col();
   pssm = make_pssm();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;
   qij = NULL;
   fin = NULL;

   /*--------------  Do one position at a time -------------------*/
   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);
      if (RTot >= 0.0) epsilon = (double) RTot * count_residues(col);
      else if (BTot >= 0.0) epsilon = BTot;
      else epsilon = sqrt(col->totcnt);
      if (qij != NULL) free(qij);
      fin = steves_qij(col);
      qij = load_qij(fin);
      fclose(fin);

      /*---------- get the pseudo counts -------------------------------*/
      pseudo_alts(col, qij, epsilon);

      /*---------   Fill in the matrix entries --------------------*/
      fillin(pos, freqs, col, pssm, obs_freqs);

   }  /*  end of for pos */
   /*------ Now make the final scores; make log scores non-neg    */
   /*       by subtracting the min. value for all positions ----- */
   final(block, freqs, pssm, matrix);

   free(col);
   free(pssm);
   if (bruno != NULL) free(bruno);
   return(matrix);
}  /* end of make_steves */
/*==========================================================================
     Uses Claverie's method of getting pseudo-counts with a subst. matrix,
     not Gribskov's method
===========================================================================*/
Matrix *make_clav(block, freqs, subst, obs_freqs)
Block *block;
double *freqs;
double subst[AASALL][AASALL];
Matrix *obs_freqs;
{
   double epsilon, maxsubst, minfreq;
   int pos, aa, row;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *pssm, *bruno;

   col = make_col();
   pssm = make_pssm();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   /*-----------------  Get the scaling value ------------------*/
   maxsubst = -999.9; minfreq = 999.9;
   for (row = 1; row < AAS; row++)
   {
      if (freqs[row] < minfreq && freqs[row] > 0.0)
           minfreq = freqs[row];
      for (aa = row; aa < AAS; aa++)
         if (subst[row][aa] > maxsubst) maxsubst = subst[row][aa];
   }

   /*--------------  Do one position at a time -------------------*/
   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);
      epsilon = (minfreq * sqrt(col->totcnt)) / maxsubst;

      /*---------- get the pseudo counts -------------------------------*/
      pseudo_clav(col, subst, epsilon);

      /*---------   Fill in the matrix entries --------------------*/
      fillin(pos, freqs, col, pssm, obs_freqs);

   }  /*  end of for pos */
   /*------ Now make the final scores; make log scores non-neg    */
   /*       by subtracting the min. value for all positions ----- */
   final(block, freqs, pssm, matrix);

   free(col);
   free(pssm);
   if (bruno != NULL) free(bruno);
   return(matrix);
} /* end of make_clav */
/*==========================================================================
     Uses simple background frequencies to make pseudo counts,
     b[aa] = sqrt(#seqs) * freq[aa]
     After Chip Lawrence's Gibbs sampling paper
===========================================================================*/
Matrix *make_gibbs(block, freqs, obs_freqs)
Block *block;
double *freqs;
Matrix *obs_freqs;
{
   double epsilon;
   int pos;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *pssm, *bruno;

   col = make_col();
   pssm = make_pssm();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   /*--------------  Do one position at a time -------------------*/
   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);
/*
      epsilon = 1.0 / (double) block->num_sequences;
      epsilon += compute_entropy(col);
      epsilon = (double) RTot * count_residues(col);
*/
      if (RTot >= 0.0) epsilon = (double) RTot * count_residues(col);
      else if (BTot >= 0.0) epsilon = BTot;
      else epsilon = sqrt( (double) block->num_sequences); 

      /*---------- get the pseudo counts -------------------------------*/
      pseudo_gibbs(col, freqs, epsilon);

      /*---------   Fill in the matrix entries --------------------*/
      fillin(pos, freqs, col, pssm, obs_freqs);

   }  /*  end of for pos */
   /*------ Now make the final scores; make log scores non-neg    */
   /*       by subtracting the min. value for all positions ----- */
   final(block, freqs, pssm, matrix);

   free(col);
   free(pssm);
   if (bruno != NULL) free(bruno);
   return(matrix);
} /* end of make_gibbs */
/*======================================================================*/
Matrix *make_diri(block, freqs, diric, obs_freqs)
Block *block;
double *freqs;
struct dirichlet *diric;
Matrix *obs_freqs;
{
   int pos;
   Matrix *matrix;
   struct working *col;
   struct work_pssm *pssm, *bruno;

   col = make_col();
   pssm = make_pssm();
   matrix = make_matrix(block);
   if (BrunoCounts || HybridCounts) bruno = bruno_rind(block);
   else bruno = NULL;

   for (pos = 0; pos < block->width; pos++)
   {
      /*-------- count the number of each aa in this position ------------*/
      if (BrunoCounts) counts_bruno(bruno, col, pos);
      else if (HybridCounts) counts_hybrid(bruno, block, col, pos);
           else if (ClumpCounts) counts_clumps(block, col, pos);
                else counts(block, col, pos);

      /*--------  get the Dirichlet mixture pseudo-counts ---------------*/
      pseudo_diric(col, diric);

/*    printf("\npos=%d\n", pos);
      for (aa = 1; aa < AAS; aa++)
         printf("%c: actual=%f diric=%f diric/Z=%f\n",
              aa_btoa[aa], col->cnt[aa], col->cnt[aa] + col->reg[aa],
              (col->cnt[aa] + col->reg[aa])/(col->totcnt + col->totreg) );
*/
  
      /*---------   Fill in the matrix entries --------------------*/
      fillin(pos, freqs, col, pssm, obs_freqs);
       
   }  /*  end of for pos */
   /*------ Now make the final scores; make log scores non-neg    */
   /*       by subtracting the min. value for all positions ----- */
   final(block, freqs, pssm, matrix);

   free(col);
   free(pssm);
   if (bruno != NULL) free(bruno);
   return(matrix);

}  /* end of make_diri */
/*===============================================================
      Returns log(e^x + e^y)
================================================================*/
double addlogs(lx, ly)
double lx, ly;
{
   if (lx > ly)  return(lx + log(1.0 + exp(ly - lx)));
   else          return(ly + log(1.0 + exp(lx - ly)));
}  /*  end of addlogs */

/*=======================================================================
      Loads scoring matrix.  Assumes alphabet for file is
      listed on first non-blank line following any comment lines starting
      with # or ;.
      Adds min. value to each entry to make matrix non-negative.
=========================================================================*/
void load_subst(fin, subst)
FILE *fin;
double subst[AASALL][AASALL];
{
   char line[MAXLINE], *ptr;
   int alpha[AASALL+10], nrows, ncols, row, col, i;
   double minval;

/*----------Read file until first non-blank, non-comment line -----------*/
      line[0] = '\0';
      while (fgets(line, sizeof(line), fin) != NULL &&
             (!strlen(line) || line[0] == '#' || line[0] == ';'))
	    ;
/*------See if the first line has characters on it ------------*/
      for (col=0; col < 30; col++) alpha[col] = -1;
      if (strstr(line, "A") != NULL)	/* This line has characters */
      {
	 row = 0;	/* # of alphabetic characters on the line */
	 for (i=0; i < (int) strlen(line); i++)
	 {
	    col = aa_atob[line[i]];
	    if (col >= 0 && col < AASALL)
	    {
	       alpha[row] = col;
	       row++;
	    }
	    else if (isalpha(line[i])) row++; /* skip over other alpha */
	 }
      }
/*-------Get the data values now ------------*/
      for (row=0; row<AASALL; row++)
	for (col=0; col<AASALL; col++)
	   subst[row][col] = -99.0;		/* Null value */
      nrows = 0;
      line[0] = '\0';
      while (fgets(line, sizeof(line), fin) != NULL)
      {
	 if ((int) strlen(line) > 1)
	 {
	    if (alpha[nrows] >= 0 && alpha[nrows] < AASALL)
	    {
	       row = alpha[nrows]; ncols = 0;
	       ptr = strtok(line, " ,\t\n");
	       while (ptr != NULL)
	       {
		  if (strspn(ptr, "+-0123456789") == strlen(ptr))
		  {
		     col = alpha[ncols];
		     if (col >= 0 && col < AASALL)
			subst[row][col] = (double) atoi(ptr);
		     ncols++;
		  }
		  ptr = strtok(NULL, " ,\t\n");
	       }
	    }
	    nrows++;
	 }
      }

/*-------If some entries are still missing, assume symmetry ---------*/
      for (row=0; row<AASALL; row++)
      {
	for (col=0; col<AASALL; col++)
	{
	   if (subst[row][col] == -99.0)
		  subst[row][col] = subst[col][row];
	   if (subst[row][col] == -99.0)
		  subst[row][col] = 0.0;
	}
      }

      /*------- Make sure matrix is non-negative -----------------*/
      minval = 9999.9;
      for (row=0; row<AASALL; row++)
	for (col=row; col<AASALL; col++)
           if (subst[row][col] < minval) minval = subst[row][col];
      if (minval <= 0.0)
      {
         minval -= 1.0;
         for (row=0; row < AASALL; row++)
           for (col=0; col < AASALL; col++)
              subst[row][col] -= minval;
      }
      fclose(fin);
} /* end of load_subst */

/*===================================================================*/
Matrix *make_matrix(block)
Block *block;
{
   Matrix *matrix;
   char ctemp[MAXLINE], *ptr;

   /*---------  Create the matrix --------------------------*/
   matrix = new_matrix(block->width);
   matrix->block = block;
   strcpy(ctemp, block->id);
   strncpy(strstr(ctemp, "BLOCK"), "MATRIX\0", 7);
   strcpy(matrix->id, ctemp);
   strcpy(matrix->ac, block->ac);
   strcpy(matrix->de, block->de);
   strcpy(matrix->ma, block->bl);
   strcpy(matrix->number, block->number);
   strcpy(matrix->motif, block->motif);
   matrix->width = matrix->max_length = block->width;
   matrix->num_sequences = block->num_sequences;
   matrix->percentile = block->percentile;
   matrix->strength = block->strength;
   matrix->patterns = NULL;
   matrix->undefined_ptr = NULL;
   /*  Add seqs= to MA line if not there */
   if (strstr(matrix->ma, "seqs=") == NULL)
   {
	strcpy(ctemp, matrix->ma);
	ptr = strtok(ctemp, "\n\r");
	sprintf(matrix->ma, "%s seqs=%d",
		ptr, matrix->num_sequences);
   }

   return(matrix);
}  /* end of make_matrix */
/*======================================================================*/
void counts(block, col, pos)
Block *block;
struct working *col;
int pos;
{
   int seq, aa;

      col->totcnt = col->totraw = col->totreg = 0.0;
      for (aa = 0; aa < AASALL; aa++) 
      { col->cnt[aa] = col->raw[aa] = col->reg[aa] = 0.0; }

      /*  Only count the real 20 aas, combine B(21) with D & Z(22) with E  */
      for (seq = 0; seq < block->num_sequences; seq++)
      {
         aa = block->residues[seq][pos];
         if (aa == 21) aa = 4;			/* combine B with D */
	 if (aa == 22) aa = 7;			/* combine Z with E */
         if (aa >= 1 && aa < AAS)
         {
            col->cnt[aa] += block->sequences[seq].weight;
            col->totcnt += block->sequences[seq].weight;
	    col->raw[aa] += 1.0;
            col->totraw += 1.0;
         }
         else printf("Uncounted character for %s: %d\n",
              block->number, block->residues[seq][pos]);
      }
}  /* end of counts */
/*======================================================================
    Get col->totcnt from Bruno but col->cnt[aa] from sequence weights
    Each column has a different col->totcnt
======================================================================*/
void counts_hybrid(bruno, block, col, pos)
struct work_pssm *bruno;
Block *block;
struct working *col;
int pos;
{
   int aa;
   double totbruno, factor;

   counts_bruno(bruno, col, pos);
   totbruno = col->totcnt;
   counts(block, col, pos);
   /*   Re-normalize sequence-weighted counts to add to Bruno total */
   factor = totbruno / col->totcnt;
   for (aa = 0; aa < AASALL; aa++) col->cnt[aa] *= factor;
   col->totcnt = totbruno;
}  /* end of counts_hybrid */
/*======================================================================
    Get col->totcnt from # clumps but col->cnt[aa] from sequence weights
    Each column has the same col->totcnt = ClumpsTot
======================================================================*/
void counts_clumps(block, col, pos)
Block *block;
struct working *col;
int pos;
{
   int aa;
   double factor;

   counts(block, col, pos);
   /*   Re-normalize sequence-weighted counts to add to clumps total */
   factor = ClumpTot / col->totcnt;
   for (aa = 0; aa < AASALL; aa++) col->cnt[aa] *= factor;
   col->totcnt = ClumpTot;
}  /* end of counts_clumps */
/*=====================================================================*/
double compute_entropy(col)
struct working *col;
{
   int aa;
   double entropy, dtemp;

   entropy = 0.0;
   for (aa=1; aa < AAS ; aa++)
   {
      dtemp = col->cnt[aa] / col->totcnt;
      if (dtemp > 0.0000) entropy -= dtemp * log(dtemp);
   }
   entropy /= Log2;		/* convert it to bits */
   return(entropy);
}   /* end of compute_entropy */
/*=====================================================================*/
int count_residues(col)
struct working *col;
{
   int aa, nr;

   nr = 0;
   for (aa = 1; aa < AAS; aa++)
      if (col->cnt[aa] > 0.0) nr++;

   return(nr);
}  /*  end of count_residues */
/*=======================================================================
    Count all pairs of amino acids in a column. Return the ratio of
    diagonal counts (identities) to off-diagonal counts.
    Working from the sequence-weighted aa counts in the column,
    not the actual block column.
    The total number of pairwise counts is tot*(tot-1)/2
========================================================================*/
double ratio_counts(col)
struct working *col;
{
   int aa;
   double ndiag, total, ratio;

   total = col->totcnt * (col->totcnt - 1.0) / 2.0;
   ndiag = 0.0;
   for (aa = 1; aa < AAS; aa++)
      if (col->cnt[aa] > 1.0)
         ndiag += col->cnt[aa] * (col->cnt[aa] - 1.0) / 2.0;

   if (ndiag < total) ratio = ndiag/(total - ndiag);
   else               ratio = 10.0;			/* infinity */
   return(ratio);
}  /*  end of ratio_counts */
/*=====================================================================*/
void pseudo_diric(col, diric)
struct working *col;
struct dirichlet *diric;
{
   int j, aa;
   double denom, dtemp;

      /*-----------   compute equation (3), Prob(n|j) ------------  */
      for (j = 0; j < diric->ncomp; j++)
      {
         col->probn[j] = lgamma(col->totcnt + 1.0) + lgamma(diric->altot[j]);
         col->probn[j] -= lgamma(col->totcnt + diric->altot[j]);
         /*   Note range on aa varies; Diric values only for 1-20 */
         for (aa = 1; aa < AAS; aa++)
         {
         /*  ni = cnt[i] */
            if (col->cnt[aa] >= 0.0)
            {
               dtemp = lgamma(col->cnt[aa] + diric->alpha[j][aa]);
               dtemp -= lgamma(col->cnt[aa] + 1.0);
               dtemp -= lgamma(diric->alpha[j][aa]);
               col->probn[j] += dtemp;
            }
         }
      }

      /*------ compute sum qk * p(n|k) using logs & exponents ----------*/
      denom = log(diric->q[0]) + col->probn[0];
      for (j = 1; j < diric->ncomp; j++)
      {
         dtemp = log(diric->q[j]) + col->probn[j];
         denom = addlogs(denom, dtemp);
      }

      /*   compute equation (3), Prob(j|n)  */
      for (j = 0; j < diric->ncomp; j++)
      {
         col->probj[j] = log(diric->q[j]) + col->probn[j] - denom;
/*       printf("j=%d probn[j]=%f probj[j]=%f\n",
             j, exp(col->probn[j]), exp(col->probj[j]));
*/
      }

      /* ----- compute equation (4), ni + bi, bi = Prob(j|n) * alpha[j][i]  */
      for (aa = 1; aa < AAS; aa++)
      {
         for (j = 0; j < diric->ncomp; j++)
            col->reg[aa] += (exp(col->probj[j]) * diric->alpha[j][aa]);
         col->totreg += col->reg[aa];
      }

}  /* end of pseudo_diric */
/*=====================================================================*/
void pseudo_alts(col, qij, epsilon)
struct working *col;
struct float_qij *qij;
double epsilon;
{
   int aa, row;

   /*---------- get the pseudo counts -------------------------------*/
   for (aa=1; aa < AAS; aa++)
   {
      col->reg[aa] = 0.0;
      for (row = 1; row < AAS; row++)
      {
        col->reg[aa] += (col->cnt[row] * qij->value[aa][row] / qij->marg[row]);
/*
        col->reg[aa] += (col->raw[row] * qij->value[aa][row] / qij->marg[row]);
*/
      }
      col->reg[aa] *= epsilon;
/*    col->reg[aa] /= col->totraw;
*/
      col->reg[aa] /= col->totcnt;
      col->totreg += col->reg[aa];
   }
}  /* end of pseudo_alts */
/*=====================================================================*/
void pseudo_clav(col, subst, epsilon)
struct working *col;
double subst[AASALL][AASALL];
double epsilon;
{
   int aa, row;

      /*---------- get the pseudo counts -------------------------------*/
      for (aa=1; aa < AAS; aa++)
      {
         col->reg[aa] = 0.0;
         for (row = 1; row < AAS; row++)
         {
            col->reg[aa] += col->cnt[row] * subst[aa][row];
         }
         col->reg[aa] *= epsilon;
         col->reg[aa] /= col->totcnt;
         col->totreg += col->reg[aa];
      }
}  /* end of pseudo_clav */
/*=====================================================================*/
void pseudo_gibbs(col, freqs, epsilon)
struct working *col;
double *freqs;
double epsilon;
{
   int aa;

   /*---------- get the pseudo counts -------------------------------*/
   col->totreg = 0.0;
   for (aa=1; aa < AAS; aa++)
   {
      col->reg[aa] = epsilon * freqs[aa];
      col->totreg += col->reg[aa];
   }
}  /* end of pseudo_gibbs */
/*=====================================================================*/
void fillin(pos, freqs, col, pssm, obs_freqs)
int pos;
double *freqs;
struct working *col;
struct work_pssm *pssm;
Matrix *obs_freqs;
{
      int aa;
      double dtemp;

      pssm->sum[pos] = 0.0; 
      for (aa=1; aa < AAS; aa++)
      {
         if (NoCounts)
         {
            pssm->value[pos][aa] = col->reg[aa];
            pssm->value[pos][aa] /= col->totreg;
         }
         else
         {
            pssm->value[pos][aa] = col->cnt[aa] + col->reg[aa];
            pssm->value[pos][aa] /= (col->totcnt + col->totreg);
         }
	 if (obs_freqs != NULL)
         {
             dtemp = 100. * pssm->value[pos][aa];
	     obs_freqs->weights[aa][pos] = round(dtemp);
         }
         if (freqs[aa] > 0.0)
             pssm->value[pos][aa] /= freqs[aa];

         if (LogScores && pssm->value[pos][aa] > 0.0)
             pssm->value[pos][aa] = log(pssm->value[pos][aa]);

         pssm->sum[pos] += pssm->value[pos][aa];
      }
}  /* end of fillin */
/*=========================================================================
      Adds negative minval to give all positive matrix,
      then multiplies by 99/maxval to give scores ranging from 0 to99 
===========================================================================*/
void final(block, freqs, pssm, matrix)
Block *block;
double *freqs;
struct work_pssm *pssm;
Matrix *matrix;
{
   int pos, aa;
   double factor, maxval, minval, dtemp;

   minval = 9999.9;
   maxval = -9999.9;
   for (pos = 0; pos < block->width; pos++)
      for (aa=1; aa < AAS; aa++)
      {
         if (pssm->value[pos][aa] < minval) minval = pssm->value[pos][aa];
         if (pssm->value[pos][aa] > maxval) maxval = pssm->value[pos][aa];
      }

   if (minval < 0.0) factor = 99.0 / (maxval - minval);
   else              factor = 99.0 / maxval;
   if (factor < 1.0) factor = 1.0;
   for (pos = 0; pos < block->width; pos++)
   {
      for (aa=1; aa < AAS; aa++)
      {
         if (FloatPt)		/* Just copy pssm to matrix */
         {
            matrix->weights[aa][pos] = pssm->value[pos][aa];
         }
         else			/* Rescale it */
         {
            if (LogScores) 
            {
               if (minval < 0.0)
                  dtemp = factor * (pssm->value[pos][aa] - minval);
               else dtemp = factor * pssm->value[pos][aa];
            }
            else 
            { 
              dtemp = 99.0 * pssm->value[pos][aa] / pssm->sum[pos];
            }
            matrix->weights[aa][pos] = round(dtemp);
         }	/* end of if not floating point */
      }   /* end of aa */
      compute_BZX(freqs, matrix, pos);
   }  /*  end of for pos */
}  /* end of final */
/*=====================================================================*/
void compute_BZX(frequency, matrix, col)
double *frequency;
Matrix *matrix;
int col;
{
  double part_D;		/* the partition of D for B. */
				/* = freq[D] / ( freq[D] + freq[N] ) */
  double part_N;		/* the partition of N for B. */
				/* = freq[N] / ( freq[D] + freq[N] ) */
  double part_E;		/* the partition of E for Z. */
				/* = freq[E] / ( freq[E] + freq[Q] ) */
  double part_Q;		/* the partition of Q for Z. */
				/* = freq[Q] / ( freq[E] + freq[Q] ) */
  /*
   * find the partitions of D, N, E, and Q for B and Z
   */
  part_D = frequency[aa_atob['D']] / 
    ( frequency[aa_atob['D']] + frequency[aa_atob['N']] );
  part_N = frequency[aa_atob['N']] / 
    ( frequency[aa_atob['D']] + frequency[aa_atob['N']] );
  part_E = frequency[aa_atob['E']] / 
    ( frequency[aa_atob['E']] + frequency[aa_atob['Q']] );
  part_Q = frequency[aa_atob['Q']] / 
    ( frequency[aa_atob['E']] + frequency[aa_atob['Q']] );

    /* fill in the matrix for B, Z, X, gap, stop and non */
    matrix->weights[aa_atob['B']][col] = 
      (int) ((part_D * matrix->weights[aa_atob['D']][col] +
	      part_N * matrix->weights[aa_atob['N']][col]) + 0.5);
				/* rounding to ints by adding 0.5 */
    matrix->weights[aa_atob['Z']][col] =
      (int) ((part_E * matrix->weights[aa_atob['E']][col] +
	      part_Q * matrix->weights[aa_atob['Q']][col]) + 0.5);
				/* rounding to ints by adding 0.5 */
    matrix->weights[aa_atob['X']][col] = 
      (int) (frequency[aa_atob['X']] + 0.5);
				/* rounding to ints by adding 0.5 */
    matrix->weights[aa_atob['-']][col] = 
      (int) (frequency[aa_atob['-']] + 0.5);
				/* rounding to ints by adding 0.5 */
    matrix->weights[aa_atob['*']][col] = 
      (int) (frequency[aa_atob['*']] + 0.5);
				/* rounding to ints by adding 0.5 */
}  /* end of compute_BZX */

/*=====================================================================*/
struct work_pssm *make_pssm()
{
   struct work_pssm *pssm;
   int pos, aa;

   pssm = (struct work_pssm *) malloc(sizeof(struct work_pssm));
   if (pssm == NULL)
   {
      printf("make_pssm: OUT OF MEMORY\n");
      exit(-1);
   }
   for (pos = 0; pos < EXTRA_LARGE_BUFF; pos++)
   {
      pssm->sum[pos] = 0.0;
      for (aa=0; aa < AASALL; aa++)
         pssm->value[pos][aa] = 0.0;
   }
   return(pssm);

}  /* end of make_pssm */
/*==================================================================*/
struct working *make_col()
{
   struct working *col;
   int aa;

   col = (struct working *) malloc(sizeof(struct working));
   if (col == NULL)
   {
      printf("make_col:  OUT OF MEMORY\n");
      exit(-1);
   }

   col->totcnt = col->totreg = 0.0;
   for (aa=0; aa < AASALL; aa++)
   {
      col->cnt[aa] = col->reg[aa] = 0.0;
   }

   return(col);
}  /* end of make_col */

/*=======================================================================
    Bill Bruno's character counts:
	creates file "data" with sequences
	executes program "rind" & waits for it to finish
	reads output file "counts" to get counts
     Computes counts for all positions at once
========================================================================*/
struct work_pssm *bruno_rind(block)
Block *block;
{
   struct work_pssm *bruno;
   FILE *fp;
   int seq, pos, baa;
   char line[1000], *ptr;
   double dtemp;

   bruno = make_pssm();
   /*------Turn the block into file "data" for rind --------------*/
   if ( (fp = fopen("data", "w")) == NULL)
   {
       printf("\nbruno_rind(): Cannot open file data\n");
       return(bruno);
   }
   for (seq=0; seq < block->num_sequences; seq++)
   {
      fprintf(fp, "%10s ", block->sequences[seq].name);
      for (pos=0; pos < block->width; pos++)
         fprintf(fp, "%c", aa_btoa[ block->residues[seq][pos] ]);
      fprintf(fp, "\n");
   }
   fclose(fp);
   /*------Execute rind ------------------------------------------*/
   printf("\nExecuting rind ....\n");
   sprintf(line, "rind");
   if (system(line) != 0)
   {
       printf("\nbruno_rind(): Execution of rind failed\n");
       exit(-1);
/*       return(bruno);  */
   }
   /*------Get the counts from "counts"-------------------------*/
   if ( (fp = fopen("counts", "r")) == NULL)
   {
       printf("\nbruno_rind(): Cannot open file counts\n");
       return(bruno);
   }
   pos = baa = -1;
   while (pos < block->width && 
          !feof(fp) && fgets(line, 1000, fp) != NULL)
   {
      if (strstr(line, "position") != NULL)
      {
         pos++; baa = 0;
         bruno->sum[pos] = 0.0;
      }
      else if (pos >= 0 && baa == 0)
      {
         ptr = strtok(line, " \t");
         while (baa < 25 && ptr != NULL)
         {
            dtemp = atof(ptr);
            bruno->value[pos][ Bruno_Order[baa] ] = dtemp;
            bruno->sum[pos] += dtemp;
            baa++;
            ptr = strtok(NULL, "-");
	    ptr = strtok(NULL, " \t");
	    ptr = strtok(NULL, " \t");
         }
      }
   }
   fclose(fp);
   /*--------------------------------------------------------------*/
   return(bruno);
}  /* end of bruno_rind()  */
/*=======================================================================
        Looks up Bruno counts
========================================================================*/
void counts_bruno (bruno, col, pos)
struct work_pssm *bruno;
struct working *col;
int pos;
{ 
   int aa;

   for (aa = 0; aa < AASALL; aa++) 
   { col->cnt[aa] = col->raw[aa] = col->reg[aa] = 0.0; }
   for (aa=1; aa < AAS; aa++)
      col->cnt[aa] = bruno->value[pos][aa];
   col->totcnt = bruno->sum[pos];

} /* end of counts_bruno */

/*======================================================================*/
/*    Cluster sequences in a block based on the number of               */
/*    identities within the block. Sets Block.cluster & Block.ncluster  */
/*      1. Compute number of identities for each possible pair of seqs. */
/*         Results stored in lower half of matrix (pairs).              */
/*      2. Use clustering threshold % of # of AAs in trimmed block.     */
/*      3. Cluster recursively by traversing cols, rows of matrix.      */
/*UNIX NOTE:  Program aborts when running under UNIX at free(pairs),
   so use the fixed size declaration pairs & remove the malloc() &
   free() calls when compiling for UNIX                                 */
/*======================================================================*/
int clump_seqs(block)
Block *block;
{
   int clus, npair, threshold, s1, s2, l1, l2, px, i, i1, i2;
   int minclus, oldclus;
   struct pair *pairs;
   struct clump_work *clumps;
/*UNIX   struct pair pairs[MAXNSEQ*(MAXNSEQ-1)/2];  */

   npair = block->num_sequences * (block->num_sequences - 1) / 2;
   pairs = (struct pair *) malloc (npair * sizeof(struct pair));
   clumps = (struct clump_work *) malloc (sizeof(struct clump_work));
   if (pairs == NULL || clumps == NULL)
   {
      printf("\nclump_seqs: Unable to allocate pair structure!\n");
      exit(-1);
   }
   threshold = (int) (ClumpCounts * (block->width))/100;

/*    Compute scores for all possible pairs of sequences            */
   for (s1=0; s1<block->num_sequences - 1; s1++) /* col = 0, n-2     */
   {
      l1 = 0;
      for (s2=s1+1; s2<block->num_sequences; s2++)	/* row = col+1, n-1 */
      {
	 l2 = 0;
	 px = INDEX(block->num_sequences, s1, s2);
	 pairs[px].score = 0;
	 pairs[px].cluster = -1;
	 for (i=0; i<=block->width; i++)
	 {
	    i1 = l1+i;  i2 = l2+i;
	    if (i1 >= 0 && i1 < block->width &&
		i2 >= 0 && i2 < block->width &&
                block->residues[s1][i1] == block->residues[s2][i2])
		   pairs[px].score += 1;
	 }
      }  /* end of s2 */
   }  /* end of s1 */

/*-------Cluster if score exceeds threshold by scanning cols (s1) */
   for (s1=0; s1<block->num_sequences; s1++)
   {
      clumps->cluster[s1] = -1;	/* clear out old values */
      clumps->ncluster[s1] = 1;
      clumps->nclus[s1] = 0;
   }
   clus = 0;        				/* cluster number */
   for (s1=0; s1<block->num_sequences - 1; s1++) 	/* col = 0, n-2     */
      for (s2=s1+1; s2<block->num_sequences; s2++)	/* row = col+1, n-1 */
      {
	 px = INDEX(block->num_sequences, s1, s2);
	 if (pairs[px].score >= threshold)	/*  cluster this pair */
	 {
	    if (clumps->cluster[s1] < 0)          /* s1 not yet clustered */
	    {
	       if (clumps->cluster[s2] < 0)       /* new cluster */
	       {
		  clumps->cluster[s1] = clus++;
		  clumps->cluster[s2] = clumps->cluster[s1];
	       }
	       else  				/* use s2's cluster  */
		  clumps->cluster[s1] =  clumps->cluster[s2];
	    }
	    /*  use s1's cluster if it has one and s2 doesn't */
	    else if (clumps->cluster[s1] >= 0 && clumps->cluster[s2] < 0)
	       clumps->cluster[s2] = clumps->cluster[s1];
	    /* merge the two clusters into the lower number */
	    else if (clumps->cluster[s1] >= 0 && clumps->cluster[s2] >= 0)
	    {
	       minclus = clumps->cluster[s1]; oldclus = clumps->cluster[s2];
	       if (clumps->cluster[s2] < clumps->cluster[s1])
	       {
		  minclus = clumps->cluster[s2]; oldclus = clumps->cluster[s1];
	       }
	       for (i1=0; i1<block->num_sequences; i1++)
		 if (clumps->cluster[i1] == oldclus)
		     clumps->cluster[i1] = minclus;
	    }
	 }  /* end of if pairs */
      }  /* end of s2 */

   /*---  Set ncluster, get rid of negative cluster numbers --*/
   for (s1=0; s1<block->num_sequences; s1++)
      if (clumps->ncluster[s1] >= 0)  clumps->nclus[clumps->cluster[s1]]++;
   for (s1=0; s1<block->num_sequences; s1++)
   {
      if (clumps->cluster[s1] < 0)
      {
	  clumps->cluster[s1] = clus++;
	  clumps->ncluster[s1] = 1;
      }
      else
	  clumps->ncluster[s1] = clumps->nclus[clumps->cluster[s1]];
   }
   free(pairs);
   return(clus);
}  /*  end of clump_seqs */
/*=========================================================================
    Scales positive matrix to lie between 0 and 99
===========================================================================*/
void positive_matrix(block, matrix)
Block *block;
Matrix *matrix;
{
   int pos, aa;
   double factor, maxval, minval, dtemp;

   minval = 9999.9;
   maxval = -9999.9;
   for (pos = 0; pos < block->width; pos++)
      for (aa=0; aa < AASALL; aa++)
      {
         if (matrix->weights[aa][pos] < minval)
             minval = matrix->weights[aa][pos];
         if (matrix->weights[aa][pos] > maxval)
             maxval = matrix->weights[aa][pos];
      }

   if (minval < 0.0) factor = 99.0 / (maxval - minval);
   else              factor = 99.0 / maxval;
/*   if (factor < 1.0) factor = 1.0;     ????why????? */
   for (pos = 0; pos < block->width; pos++)
   {
      for (aa=0; aa < AASALL; aa++)
      {
            if (minval < 0.0)
               dtemp = factor * (matrix->weights[aa][pos] - minval);
            else dtemp = factor * matrix->weights[aa][pos];
            matrix->weights[aa][pos] = round(dtemp);
      }
   }  /*  end of for pos */
}  /* end of positive_matrix */
/*=====================================================================*/
/*    Find patterns & add them to output file containing the matrix    */
/*    There is at most one pattern per matrix position, and it will    */
/*    have only one non-x position in it. Patterns may be made more    */
/*    general later on                                                 */

void add_patterns(matrix, Fpa)
Matrix *matrix;
FILE *Fpa;
{
   int pos, aa, npos, naa, i;
   int aas[AASALL];
   char pattern[MAXLINE], ctemp[5], *ptr;

   /*    Change MATRIX to PATMAT on id line    */
   strcpy(pattern, matrix->id);
   ptr = strtok(pattern, ";");
   if (ptr != NULL) strcat(pattern, "; PATMAT");
   fprintf(Fpa, "ID   %s\n", pattern);
   fprintf(Fpa, "AC   %s\n", matrix->ac);
   fprintf(Fpa, "DE   %s\n", matrix->de);
   fprintf(Fpa, "PA   %s\n", matrix->ma);
   for (pos = 0; pos < matrix->width; pos++)
   {
      npos = naa = 0;
      pattern[0] = '\0';
      for (aa=1; aa <= 20; aa++)
      {
         if (matrix->weights[aa][pos] >= PatternCutoff)
         {
            aas[naa] = aa;
            naa++;
         }
      }
      if (naa == 1)
      {
         for (i=0; i < pos; i++) strcat(pattern, "x");
         ctemp[0] = aa_btoa[ aas[0] ]; ctemp[1] = '\0';
         strcat(pattern, ctemp);   /* this is i = pos */
         for (i=pos+1; i < matrix->width; i++) strcat(pattern, "x");
         npos++;
      }
      else if (naa > 1)
           {
              for (i=0; i < pos; i++) strcat(pattern, "x");
              strcat(pattern, "[");
              ctemp[1] = '\0';
              for (i=0; i < naa; i++)
              {
                 ctemp[0] = aa_btoa[ aas[i] ];
                 strcat(pattern, ctemp);
              }
              strcat(pattern, "]");
              for (i=pos; i < matrix->width; i++) strcat(pattern, "x");
              npos++;
           }
      if (npos > 0) fprintf(Fpa, "%s\n", pattern);
   }
   fprintf(Fpa, "//\n");
}  /* end of add_patterns */
