/********************************************************************************************************
 * QRNA - Comparative analysis of biological sequences 
 *         with pair hidden Markov models, pair stochastic context-free
 *        grammars, and probabilistic evolutionary  models.
 *       
 * Version 2.0.3 (MAY 2004)
 *
 * Copyright (C) 2000-2004 Howard Hughes Medical Institute/Washington University School of Medicine
 * All Rights Reserved
 * 
 *     This source code is distributed under the terms of the
 *     GNU General Public License. See the files COPYING and LICENSE
 *     for details.
 ***********************************************************************************************************/

/* evolemisc.c
 * 
 *
 * ER, Sun May 16 11:54:20 CDT 2004 [STL, at home with Coro and my Mother]
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>

#include "funcs.h"
#include "evolfuncs.h"
#include "globals.h"
#include "squid.h"
#include "structs.h"

void
EvolAllocModels(struct emodel_s **ret_emodel)
{
  struct emodel_s *emodel;

  emodel              = (struct emodel_s *)      MallocOrDie (sizeof(struct emodel_s));
  emodel->which_model = (struct which_model_s *) MallocOrDie (sizeof(struct which_model_s));

  emodel->null = AllocNullModel();
  emodel->oth  = AllocOTHModel();
  emodel->cod  = AllocCODModel();
  emodel->rna  = AllocRNAModel();
 
  *ret_emodel = emodel;
}

/* Function: EvolCalculateNaiveTargetError()
 * Date:     ER, Thu Aug 19 12:45:46 CDT 2004  [St. Louis at work, Coro with Maribel]
 *
 * Purpose:  Calculates the actual (time dependent) and max (at t infinity)
 *           error commited by using the naive method to change the background frequencies.
 *
 *           Naive method:  given  P(i,j) = p_i Q(i,j) = p_j Q(j,i)
 *   
 *                          for some target frequencies ~p
 *
 *                          define ~P(i,j) = 0.5 * [ ~p_i Q(i,j) + ~p_j Q(j,i) ] 
 *
 *                                         = ^p_i ^Q(i,j) = ^p_j ^Q(j,i)
 *   
 *                          the new marginals are ^p
 *                         
 *                          the difference between ~p (the target frequencies) and ^p (the obtained freqs) is
 *
 *                                        ^p_i = 0.5 * [ ~p_i + \sum_j ~p_j Q(j,i) ]
 *
 *                          for t = 0      ===> ^p_i = ~p_i (exact, no error)
 *
 *                          for t = \infty ===> ^p_i = 0.5 * [ ~p_i + p_i ] (maximal error)
 *   
 *                          this is a "time-dependent" error, the larger t and the difference between p_i and ~p_i the
 *                          larger the error.
 *
 *
 *                            actual_ave_error =      \sum_i |~p_i - ^p_i| * ~pi 
 *
 *                            max_ave_error    = 1/2 * \sum_i |~p_i - p_i| * ~pi
 *
 *
 * Args:     tfactor
 *           L
 *           targetfreq   
 *           p_old 
 *           p_new 
 *           verbose 
 *
 * Returns:  (void)
 */
void
EvolCalculateNaiveTargetError(double tfactor, int L, double *targetfreq, double *p_old, double *p_new, int verbose)
{
  double max_error;
  double act_error;
  int    x;

  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "OLD probabilities\n");
    PrintVectorProbs(stdout, p_old, L);
    fprintf(stdout, "NEW probabilities at time=%.3f\n", tfactor);
    PrintVectorProbs(stdout, p_new, L);
  }

  if (tfactor < 0.0) Die("EvolCalculateTargetError(): negative time? %f\n", tfactor);

  CheckSingleProb(targetfreq, L); /* paranoia */
  CheckSingleProb(p_old,      L); /* paranoia */
  CheckSingleProb(p_new,      L); /* paranoia */

  /* initialize */
  max_error = 0.0;
  act_error = 0.0;
  
  for (x = 0; x < L; x ++) {
    max_error += 0.5 * fabs(targetfreq[x] - p_old[x]) * targetfreq[x];
    act_error +=       fabs(targetfreq[x] - p_new[x]) * targetfreq[x];
  }

  max_error *= 100.0;
  act_error *= 100.0;

  printf("MAX_average error[L=%d] = %.2f \n", L, max_error);
  printf("ACT_average error[@t %.3f] = %.2f \n\n", tfactor, act_error);
 
}

void
EvolCalculateMutProbsTargetError(FILE *ofp, double *targetfreq, struct psubs_s *pmutxy, int verbose)
{
  double *p;
  double  error = 0.0;
  int     L;
  int     LSQ;
  int     x;
  int     i;

  L   = pmutxy->L;
  LSQ = L*L;

  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "Mut probabilities [time=%.3f]\n", pmutxy->time);
    PrintProbs(stdout, pmutxy->P, L);
    fprintf(stdout, "Mut marginals probabilities [time=%.3f]\n", pmutxy->time);
    PrintVectorProbs(stdout, pmutxy->pm, L);
  }

  if (pmutxy->time < 0.0) Die("EvolCalculateMutProbsTargetError(): negative time? %f\n", pmutxy->time);

  CheckSingleProb(targetfreq, L);   /* paranoia */
  
  p = (double *)  MallocOrDie (sizeof(double) * L);
  for (x = 0; x < L; x ++) p[x] = 0.0;
  
  for (i = 0; i < LSQ; i ++) {
    p[i/L] += 0.5 * pmutxy->P[i];
    p[i%L] += 0.5 * pmutxy->P[i];
  }
  if (verbose) {
    fprintf(stdout, "MUT single nt marginal probabilities\n");
    PrintVectorProbs(stdout, p, L);
  }
 CheckSingleProb(p, L); /* paranoia */

  for (x = 0; x < L; x ++) 
    error += fabs(targetfreq[x] - p[x]) * targetfreq[x];

  error *= 100.0;

  printf("\nMUTProbs\n");
  printf("average error[@t %.3f] = %.2f \n\n", pmutxy->time, error);
 
  free(p);
}

void
EvolCalculateMut5ProbsTargetError(FILE *ofp, double *targetfreq, struct psubs_s *pmut5xy, int verbose)
{
  double *p5;
  double  error = 0.0;
  double  sum   = 0.0;
  int     L5;
  int     L5SQ;
  int     L;
  int     LSQ;
  int     x;
  int     i;

  L5   = pmut5xy->L;
  L5SQ = L5*L5;

  L    = L5 - 1;
  LSQ  = L*L;

  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "Mut5 probabilities [time=%.3f]\n", pmut5xy->time);
    PrintProbs(stdout, pmut5xy->P, L5);
    fprintf(stdout, "Mut5 marginals probabilities [time=%.3f]\n", pmut5xy->time);
    PrintVectorProbs(stdout, pmut5xy->pm, L5);
  }

  if (pmut5xy->time < 0.0) Die("EvolCalculateMutProbsTargetError(): negative time? %f\n", pmut5xy->time);

  CheckSingleProb(targetfreq, L);   /* paranoia */
  
  p5 = (double *)  MallocOrDie (sizeof(double) * L5);
  for (x = 0; x < L5; x ++) p5[x] = 0.0;
  
  for (i = 0; i < L5SQ; i ++) {
    p5[i/L5] += 0.5 * pmut5xy->P[i];
    p5[i%L5] += 0.5 * pmut5xy->P[i];
  }
  if (verbose) {
    fprintf(stdout, "MUT5 single nt marginal probabilities\n");
    PrintVectorProbs(stdout, p5, L5);
  }
 CheckSingleProb(p5, L5); /* paranoia */

 for (x = 0; x < L; x ++) sum += p5[x];

  for (x = 0; x < L; x ++) 
    error += fabs(targetfreq[x] - p5[x]/sum) * targetfreq[x];

  error *= 100.0 / L;

  printf("\nMUT5Probs\n");
  printf("average error[@t %.3f] = %.2f \n\n", pmut5xy->time, error);
 
  free(p5);

}

/* Function: EvolConstructModels_phase1()
 * Date:     ER, Sat May 15 14:23:37 CDT 2004  [St. Louis, at home with Coro]
 *
 * Purpose:  Constructs model_s
 *
 * Args:      pamfile -  
 *            cfgfile -
 *            model_s - structures to fill
 *            verbose - 
 *
 * Returns:  (void)
 *           fills all prob's for models, log2 form 
 *           (allc'ed here, freed by caller)
 */
void
EvolConstructModels_phase1(FILE *ofp, char *codonfile, char *hexapfile, char *pamfile, char *cfgfile, char *ribofile, 
			   double *targetfreq, struct emodel_s **ret_emodel, 
			   double ****ret_cfg_node, double ***ret_hexa, double **ret_codon_joint, 
			   struct psubs_s    **ret_pam_star,  
			   struct psubs_s    **ret_codprob_star, 
			   struct psubs_s    **ret_mutpxy_star, 
			   struct psubs_s    **ret_mut5pxy_star,
			   struct psubs_s    **ret_riboprob_star, 
			   struct psubs_s    **ret_riboprobapprox_star, 
			   struct pnonsubs_s **ret_pair5prob_star,
			   struct psubs_s    **ret_mutpxy_rna_unpaired_star, 
			   struct psubs_s    **ret_mut5pxy_rna_unpaired_star,
			   struct psubs_s    **ret_mut5pxy_rna_loop_star,
			   struct psubs_s    **ret_mutpxy_rna_paired_star, 
			   struct psubs_s    **ret_mut5pxy_rna_paired_star,
			   int add_codon, int add_hexamer, int approx, int areon, int changefreq, 
			   int changefreqoverall, int logodds, int pedantic, int verbose)
{
  struct emodel_s     *emodel;
  FILE                *cfgfp;	              /* open RNA      model file                                */
  FILE                *codonfp;               /* open Codon-Codon model file                             */
  FILE                *hexapfp;               /* open Hexamer  model file                                */
  FILE                *pamfp;                 /* open PAM      model file                                */
  FILE                *ribofp;                /* open RIBOPROB model file                                */
  char                *codonjfile;
  char                *hexamerfile;
  struct psubs_s      *pam_star;
  struct psubs_s      *codprob_star;
  struct psubs_s      *mutpxy_star;
  struct psubs_s      *mut5pxy_star;
  struct psubs_s      *riboprob_star;
  struct psubs_s      *riboprobapprox_star;
  struct pnonsubs_s   *pairprob_star;
  struct pnonsubs_s   *pair5prob_star;
  struct psubs_s      *mutpxy_rna_unpaired_star;
  struct psubs_s      *mut5pxy_rna_unpaired_star;
  struct psubs_s      *mut5pxy_rna_loop_star;
  struct psubs_s      *mutpxy_rna_paired_star;
  struct psubs_s      *mut5pxy_rna_paired_star;
  int                **pam;
  fullmat_t           *ribomat;               /* The RIBOPROB matrix                                         */
  double              *codon_joint;
  double             **hexa;
  double             **cfg;                   /* RNA grammar probs                                           */
  double            ***cfg_node;              /* RNA grammar probs by nodes                                 +*/
  double             **cfg_emit;              /* RNA grammar probs by emission                              +*/
  double              *cfg5prob;
  float                scale;
  int                  change_background;

  if (changefreq || changefreqoverall) change_background = TRUE;
  else                                 change_background = FALSE;

  if (verbose) PrintVectorProbs(stdout, targetfreq, 4);    

  /* Load a PAM substitution matrix
   */
  if ((pamfp = fopen(pamfile, "r")) == NULL &&
      (pamfp = EnvFileOpen(pamfile, "QRNADB")) == NULL)
    Die("Failed to open PAM scoring matrix file %s", pamfile);
  
  if (! ParsePAMFile(pamfp, &pam, &scale))
    Die("Failed to parse PAM file");
  fclose(pamfp);

  /* Load a codon-codon joint frequencies in log2 form 
   */
  if (codonfile) {
     codonjfile = FileConcat("aa", codonfile);
    if ((codonfp = fopen(codonjfile, "r")) == NULL)
      Die("Failed to open Codon-Codon file %s", codonfile);
  }
  else codonfp = NULL;
    
  if (! ParseCodonFile(codonfp, &codon_joint))
    Die("Failed to parse Codon-Codon file");

  if (add_codon) {
    fclose(codonfp);
    free(codonjfile);
  }
  
  /* Load a Hexamer joint frequencies in log2 form 
   */
  if (hexapfile) {
    hexamerfile = FileConcat("/nfs/wol2/people/elena/db/hexamer", hexapfile);
    if ((hexapfp = fopen(hexamerfile, "r")) == NULL)
      Die("Failed to open Hexamer file %s", hexapfile);
  }
  else hexapfp = NULL;
    
  if (! ParseHexamerFile(hexapfp, &hexa))
    Die("Failed to parse Hexamer file");

  if (add_hexamer) {
    fclose(hexapfp);
    free(hexamerfile);
  }

  /* Load a RNA cfg grammar
   */
  if (cfgfile == NULL) /* SCFG is not provided */
    cfgfile = FileConcat("", "mix_tied_linux.cfg");

  if ((cfgfp = fopen(cfgfile, "r")) == NULL&&
      (cfgfp = EnvFileOpen(cfgfile, "QRNADB")) == NULL)
    Die("Failed to open SCFG save file %s", cfgfile);
  if (! ReadSCFG(cfgfp, &cfg))
    Die("Failed to read SCFG from file %s", cfgfile);
  
  fclose(cfgfp);

  Pairs5SCFG(cfg, &cfg5prob);      /* counts for base-pairs */
  DNorm(cfg5prob, 25);

  /* log2 prob         
   */
  Log2ProbSCFG(cfg);

  /* Separate the cfg frequencies into emission and transitions
   */
  TieProbs(cfg, &cfg_node, &cfg_emit);

 /* Load a RIBOPROB matrix
   */
  if (ribofile == NULL) /* RIBOPROB is not provided */
    ribofile = FileConcat("", "RIBOPROB85-60.mat");
 if ((ribofp = fopen(ribofile, "r")) == NULL&&
      (ribofp = EnvFileOpen(ribofile, "QRNADB")) == NULL)
    Die("Failed to open RIBOPROB file %s", ribofile);
 if (! (ribomat = ReadRIBOPROBMatrix(ribofp)))
    Die ("Failed to read RIBOPROB matrix file \n");  

 if (verbose) PrintFullMatrix (stdout, ribomat);

 /* allocate the models 
   */
  EvolAllocModels(&emodel);
  EvolPatternModels(emodel, areon);

  /* 
   * Calculate the Rate matrices for all emission probabilities
   */

  /* calculate the rate for pam_star(20x20) */ 
  EvolCalPAMRate(pam, scale, 20, &pam_star, codon_joint, add_codon, pedantic, verbose);

  /* calculate the codprob_star(64x64) -- we need those to calculate the mutpxy_star->P[4x4] as marginals */ 
  EvolCODProbsStar(pam_star, &codprob_star, codon_joint, add_codon, targetfreq, change_background, pedantic, verbose);

  if (verbose) printf("\nmutpxy_star\n");
  /* calculate the rate for mutpxy_star(4x4). 
   * First infer mutpxy_star->P(4x4) from codprob_star(64x64) */ 
  EvolCalMutRateFromCOD (codprob_star, 4, &mutpxy_star,  targetfreq, change_background, pedantic, verbose);

  /* calculate the rate for mut5pxy_star(5x5).
   * First infer mut5pxy_star->P(4x4)  from codprob_star(64x64) by adding gaps */ 
  EvolCalMut5RateFromCOD(codprob_star, 5, &mut5pxy_star, targetfreq, change_background, pedantic, verbose);
  
  /* calculate the rate for pair5prob_star(5x5). 
   *                      First infer pair5prob_star->P(5x5) from cfg5prob by adding gaps.
   *                        We also use the mutpxy_star to make sure that pair5prob_star and mut5pxy_star have the same marginals */
  EvolCalPair5Rate(cfg5prob, mutpxy_star, 5, &pairprob_star, &pair5prob_star, targetfreq, change_background, pedantic, verbose);

  /* calculate the rate for mutpxy_rna_unpaired_star(4x4). First infer mutpxy_unpaired_star->P(4x4) from RIBOSUM(4x4) unpaired */ 
  EvolCalMutRateFromRIBOUnpaired (ribomat, 4, mutpxy_star,  &mutpxy_rna_unpaired_star,  targetfreq, change_background, pedantic, verbose);

  /* calculate the rate for mut5pxy_rna_paired_star(5x5).
   *  First infer mut5pxy_paired_star->P(4x4)  from RIBOSUM(64x64) marginalized by adding gaps */ 
  EvolCalMut5RateFromRIBOUnpaired(ribomat, 5, mutpxy_star, mut5pxy_star, mutpxy_rna_unpaired_star, &mut5pxy_rna_unpaired_star, 
				  targetfreq, change_background, pedantic, verbose);
  EvolCalMut5RateLoopFromRIBOUnpaired(ribomat, 5, mutpxy_star, mut5pxy_star, mutpxy_rna_unpaired_star, &mut5pxy_rna_loop_star, 
				      targetfreq, change_background, pedantic, verbose);
  
  if (approx) {
    /* calculate the rate for riboprobapprox_star(16x16). 
     * First, infer the riboprobapprox_star->P(16x16) from cfg5prob and mutpxy_star->P */
    /* change_background = FALSE; frequencies have already been changed in pairprob_star */
    EvolCalRIBOApproxRate(mutpxy_star, pairprob_star, &riboprobapprox_star, TRUE, pedantic, verbose);
  }

  /* calculate the rate for riboprob_star(16x16).  riboprob_star->P are given by trained ribomat(RIBOSUM85-60.mat by default) */
  /* change_background = TRUE; we need to use pairprob_star->P  to change the pair marginal frequencies riboprob_star->pm */
  EvolCalRIBORate(ribomat, mutpxy_star, pairprob_star, &riboprob_star, TRUE, pedantic, verbose);

  if (verbose) printf("\nmutpxy_rna_paired_star\n");
  /* calculate the rate for mutpxy_rna_paired_star(4x4). 
   * First infer mutpxy_unpaired_star->P(4x4) from RIBOSUM(64x64) marginalized */ 
  EvolCalMutRateFromRIBOPaired (riboprob_star, 4, mutpxy_star, &mutpxy_rna_paired_star, targetfreq, change_background, pedantic, verbose);

  /* calculate the rate for mut5pxy_rna_unpaired_star(5x5). 
   * First infer mut5pxy_unpaired_star->P(4x4)  from RIBOSUM(4x4) unpaired by adding gaps */ 
  EvolCalMut5RateFromRIBOPaired(riboprob_star, 5, mut5pxy_star, mutpxy_rna_paired_star, &mut5pxy_rna_paired_star, 
				targetfreq, change_background, pedantic, verbose);
  
  *ret_emodel                    = emodel;
  *ret_cfg_node                  = cfg_node;
  *ret_codon_joint               = codon_joint;
  *ret_hexa                      = hexa;
  *ret_pam_star                  = pam_star;
  *ret_codprob_star              = codprob_star;
  *ret_mutpxy_star               = mutpxy_star;
  *ret_mut5pxy_star              = mut5pxy_star;
  *ret_riboprob_star             = riboprob_star;
  if (approx) *ret_riboprobapprox_star = riboprobapprox_star;
  *ret_pair5prob_star            = pair5prob_star;

  *ret_mutpxy_rna_unpaired_star  = mutpxy_rna_unpaired_star;
  *ret_mut5pxy_rna_unpaired_star = mut5pxy_rna_unpaired_star;
  *ret_mut5pxy_rna_loop_star     = mut5pxy_rna_loop_star;
  *ret_mutpxy_rna_paired_star    = mutpxy_rna_paired_star;
  *ret_mut5pxy_rna_paired_star   = mut5pxy_rna_paired_star;

  /* free memory */
  free(cfg5prob);
  Free2DArray(pam, 27);
  FreeNonSubsProbs(pairprob_star);
  FreeFullMatrix(ribomat);
  FreeSCFG(cfg);
  FreeSCFG(cfg_emit);  

}

/* Function: EvolConstructModels_phase2()
 * Date:     ER, Mon May 17 09:59:53 CDT 2004  [St. Louis, at work with Coro]
 *
 * Purpose:  Constructs model_s
 *
 * Args:      pamfile -  
 *            cfgfile -
 *            model_s - structures to fill
 *            verbose - 
 *
 * Returns:  (void)
 *           fills all prob's for models, log2 form 
 *           (allc'ed here, freed by caller)
 */
void
EvolConstructModels_phase2(FILE *ofp, int win, double ***cfg_node, double **hexa, double *codon_joint, 
			   double *freqX, double *freqY, struct emodel_s *emodel, struct three_times_s time, 
			   struct psubs_s    *pam_star, 
			   struct psubs_s    *codprob_star, 
			   struct psubs_s    *mutpxy_star, 
			   struct psubs_s    *mut5pxy_star,
			   struct psubs_s    *riboprob_star, 
			   struct pnonsubs_s *pair5prob_star, 
			   struct psubs_s    *mutpxy_rna_unpaired_star, 
			   struct psubs_s    *mut5pxy_rna_unpaired_star,
			   struct psubs_s    *mut5pxy_rna_loop_star,
			   struct psubs_s    *mutpxy_rna_paired_star, 
			   struct psubs_s    *mut5pxy_rna_paired_star,
			   int add_codon, int add_hexamer, int changefreq, int changefreqoverall, 
			   int logodds, int use_ribo_oldrna, int pedantic, int verbose)
{
  double            *targetfreq;	    /* 4x4   target frequncies, otherwise they are given my mutpxy */
  double             tfactor;
  int                i;
  int                change_background;

  if (changefreq || changefreqoverall) change_background = TRUE;
  else                                 change_background = FALSE;

  /* Calculate the PAM model:  P(x1 x2 x3,y1 y2 y3)
   * and mutation probabilities:
   * P(x,y) = 1/3 \sum_{x1,x2,y1,y2} [ P(x  x1 x2, y  y1 y2) + 
   *                                   P(x1 x  x2, y1 y  y2) + 
   *                                   P(x1 x2 x , y1 y2 y )   ]
   */
  if (time.oth < 0.0 || time.cod < 0.0 || time.rna < 0.0) Die("positive times required, or you won't be here!");

  targetfreq = (double *) MallocOrDie (sizeof(double) * 4);
  
  for (i = 0; i < 4; i ++)  
    targetfreq[i] = 0.5*(freqX[i]+freqY[i]);
  
  if (verbose) {
    printf("Target freqs in EvolConstructModels_phase2() changefreq=%d changefreqoverall=%d\n", 
	   changefreq, changefreqoverall);
    PrintVectorProbs(stdout, targetfreq, 4);    
  }
  
  /* for the Null model we take an average of the three times
   */  
  tfactor = (time.oth + time.cod + time.rna)/3.0;
  
  if (verbose) printf("\nConstruct COD Model at time = %.4f\n", time.cod);
  if (emodel->which_model->cod || NullProbs(targetfreq, 4)) 
    EvolConstructCODModel(pam_star, codprob_star, mutpxy_star, codon_joint, add_codon, hexa, 
			  win, time.cod, targetfreq, change_background, emodel->cod, add_hexamer, pedantic, verbose);
  
  if (verbose) printf("\nConstruct Null Model at time = %.4f\n", tfactor);
  EvolConstructNullModel(mutpxy_star, emodel->null, Nullparam, Nullparam, Nullparam, tfactor, targetfreq, change_background, verbose);
  
  if (verbose) printf("\nConstruct OTH Model at time = %.4f\n", time.oth);
  if (emodel->which_model->oth) 
    EvolConstructOTHModel(mutpxy_star, OTHparam, OTHparam_zero, OTHparam_infty, 
			  win, win, win, time.oth, targetfreq, change_background, emodel->oth, pedantic, verbose);
  
  if (verbose) printf("\nConstruct RNA Model at time = %.4f\n", time.rna);
  if (emodel->which_model->rna) 
    EvolConstructRNAModel(mutpxy_star, mut5pxy_star, 
			  mutpxy_rna_unpaired_star, mut5pxy_rna_unpaired_star, mut5pxy_rna_loop_star, 
			  mutpxy_rna_paired_star, mut5pxy_rna_paired_star, 
			  pair5prob_star, riboprob_star, cfg_node, 
			  win, time.rna, emodel->rna, emodel->null, targetfreq, change_background, use_ribo_oldrna, pedantic, verbose); 
  
  if (verbose) {
    PrintNullModel(emodel->null);
    PrintCODModel (emodel->cod);
    PrintOTHModel (emodel->oth);
    PrintRNAModel (emodel->rna);

    EvolPrintTrProbs (emodel); 
  }
   
 /* Logodds form of the models 
   */
  if (logodds) EvolModelLog2ToOdds(emodel);

  /* free memory */
  free(targetfreq);

}

void
EvolFreeModels(struct emodel_s *emodel)
{
  FreeNullModel(emodel->null);
  FreeCODModel (emodel->cod);
  FreeOTHModel (emodel->oth);
  FreeRNAModel (emodel->rna);

  free(emodel->which_model);
  free(emodel);
}

/* Function: EvolModelLog2ToOdds()
 * Date:     ER,  Mon Aug 16 12:18:57 CDT 2004 [St. Louis at work, Coro with Maribel]
 *
 * Purpose:  Converts transition and emission prob's of a model_ structure
 *           from log2 to log2odds form (except for model->null). 
 *
 * Args:     model - the structure for a model_s 
 *
 * Returns:  void. 
 */
void
EvolModelLog2ToOdds(struct emodel_s *emodel)
{
  CODLog2ToOdds(emodel->cod, emodel->null); 
  OTHLog2ToOdds(emodel->oth, emodel->null);  
  RNALog2ToOdds(emodel->rna, emodel->null); 
}

void
EvolPatternModels(struct emodel_s *emodel, int areon)
{
  PatternNullModel(emodel->null);
  PatternOTHModel (emodel->oth);
  PatternCODModel (emodel->cod);
  PatternRNAModel (emodel->rna);

  emodel->which_model->null = areon;
  emodel->which_model->oth  = areon;
  emodel->which_model->cod  = areon;
  emodel->which_model->rna  = areon;
}

/* Function: EvolPrintTrProbs()
 * Date:     ER,  Mon Aug 16 12:16:53 CDT 2004 [St. Louis at work, coro with maribel]
 *
 * Purpose:  Print trnasition probabilities of all the models
 *
 * Args:     othmodel -- the othmodel prob's, in log2 form
 *
 * Returns:  void. prints transition and emission probs for oth model, in [0,1] form.
 */
void
EvolPrintTrProbs(struct emodel_s *emodel)
{

  printf("\nNull MODEL -- Transition probabilities\n");
  printf("eta   = %f\n", EXP2(emodel->null->eta)); 
  printf("1-eta = %f\n", EXP2(emodel->null->meta)); 
  
  printf("\nOTH MODEL \n");
  PrintOTHTrProbs(emodel->oth);

  printf("\nCOD MODEL \n");
  PrintCODTrProbs(emodel->cod);

  printf("\nRNA MODEL \n");
  PrintRNATrProbs(emodel->rna);

  printf("\n");
}

int
NullProbs (double *p, int L)
{
  int isnull = TRUE;
  int x;

  for (x = 0; x < L; x ++) { if (p[x] > 0.0+MARGIN) isnull = FALSE; break; }

  if (FALSE) {
    printf("is null = %d\n", isnull);
    PrintVectorProbs(stdout, p, L);
  }
  return isnull;
}
