/* This file contains common output routines for use with the parallel
   versions of the FASTLINK programs ILINK, LINKMAP, and MLINK.
   Sequential FASTLINK is an improved version of LINKAGE.  Improvements
   are described in described in: R. W. Cottingham, Jr., R. M. Idury, and
   A. A. Schaffer Faster Sequential Genetic Linkage Computations American
   Journal of Human Genetics, 53(1993), pp. 252--263 and A. A. Schaffer,
   S. K. Gupta, K. Shriram, and R. W. Cottingham, Jr., Avoiding
   Recomputation in Linkage Analysis Human Heredity 44(1994),
   pp. 225-237.  The parallel implementations of ILINK are described in:
   S. Dwarkadas, A. A. Schaffer, R. W. Cottingham Jr., A. L. Cox,
   P. Keleher, and W. Zwaenepoel, Parallelization of General Linkage
   Analysis Problems, Human Heredity 44(1994), pp. 127-141 and
   S. K. Gupta, A. A. Schaffer, A. L. Cox, S. Dwarkadas, and
   W. Zwaenepoel, Integerating Parallelization Strategies for Linkage
   Analysis, Computers and Biomedical Research, to appear.
   The code in this file was written by Chris Hyams. */
   
#include "commondefs.h"
#include "gemdefs.h"
#if !defined(LESSMEMORY)
#include "moddefs.h"
#endif  /* if !defined(LESSMEMORY) */
#if defined(MLINK)
#include "mldefs.h"
#endif  /* if defined(MLINK) */
#if defined(LINKMAP)
#include "lidefs.h"
#endif  /* if defined(LINKMAP) */


#if PARALLEL  /* cgh */

void preLikeBufferOutput()
{
  int i;
  /* temporary output buffer */
  char tempBuff[TEMPBUFF_SIZE]; 

  /* pointers to specific entries in each iped array for this
     iteration */
  strBuff* stdBuff = stdoutBuff->ipeds[absoluteThetanum];
  strBuff* outfBuff = outfileBuff->ipeds[absoluteThetanum];
#if defined(MLINK)
  strBuff* strmBuff = streamBuff->ipeds[absoluteThetanum];
#endif  /* defined(MLINK) */

  sprintf(tempBuff, "%s\n%s\n", LINE, LINE);
  append(stdBuff, tempBuff);
  append(outfBuff, tempBuff);
  
  if (sexdif) {
    append(stdBuff, "MALE THETAS   ");
    append(outfBuff, "MALE THETAS   ");
  } else { 
    append(stdBuff, "THETAS ");
    append(outfBuff, "THETAS ");
  }
  
  for (i = 0; i <= mlocus - 2; i++) {
    sprintf(tempBuff, "%6.3f", maletheta->theta[i]);
    append(stdBuff, tempBuff);
    append(outfBuff, tempBuff);
  }

#if defined(MLINK)
  if (interfer) {
    sprintf(tempBuff, "%6.3f", maletheta->theta[mlocus - 1]);
    append(stdBuff, tempBuff);
    append(outfBuff, tempBuff);
 }
#endif  /* if defined(MLINK) */

  append(stdBuff, "\n");
  append(outfBuff, "\n");

#if defined(MLINK)
  if (dostream) {
    for (i = 0; i <= mlocus - 2; i++) {
      sprintf(tempBuff, "%6.3f\n", maletheta->theta[i]);
      append(strmBuff, tempBuff);
    }
    if (interfer) {
      sprintf(tempBuff, "%6.3f\n", maletheta->theta[mlocus - 1]);
      append(strmBuff, tempBuff);
    }
  }
#endif  /* if defined(MLINK) */

  if (sexdif) {
    append(stdBuff, "FEMALE THETAS ");
    append(outfBuff, "FEMALE THETAS ");
    for (i = 0; i <= mlocus - 2; i++) {
      sprintf(tempBuff, "%6.3f", femaletheta->theta[i]);
      append(stdBuff, tempBuff);
      append(outfBuff, tempBuff);
    }
    if (interfer) {
      sprintf(tempBuff, "%6.3f", femaletheta->theta[mlocus - 1]);
      append(stdBuff, tempBuff);
#if defined(MLINK)
      append(outfBuff, tempBuff);
#endif  /* if defined(MLINK) */
    }

    append(outfBuff, "\n");
#if defined(MLINK)      
    append(stdBuff, "\n");
    if (dostream) {
      for (i = 0; i <= mlocus - 2; i++) {
	sprintf(tempBuff, "%6.3f\n", femaletheta->theta[i]);
	append(strmBuff, tempBuff);
      }
      if (interfer) {
	sprintf(tempBuff, "%6.3f\n", femaletheta->theta[mlocus - 1]); 
	append(strmBuff, tempBuff);
      }
    }
#endif  /* if defined(MLINK) */
  }

  sprintf(tempBuff, "%s\nPEDIGREE |  LN LIKE  | LOG 10 LIKE\n%s\n",
	  LINE, LINE);
  append(stdBuff, tempBuff);
  append(outfBuff, tempBuff);
}


void bufferPedOutput(currThisped, currLike)
int currThisped;
double currLike;
{
  /* temporary output buffer */
  char tempBuff[TEMPBUFF_SIZE]; 

  if (dostream) {
#if defined(MLINK)
    sprintf(tempBuff, "%12d % .5e", proband[currThisped]->ped, currLike);
#elif defined(LINKMAP)
    sprintf(tempBuff, "%12d % .5e ", proband[currThisped]->ped, currLike);
#endif
    append(streamBuff->ipeds[absoluteThetanum], tempBuff);
  }	
  sprintf(tempBuff, "%9d %12.6f ", proband[currThisped]->ped, currLike);
  append(stdoutBuff->ipeds[absoluteThetanum], tempBuff);
  if (byfamily)
    append(outfileBuff->ipeds[absoluteThetanum], tempBuff);
}


#if defined(MLINK)
void bufferLikeOutput(currLike, eachlodII)
double currLike, eachlodII;
#else  /* if defined(MLINK) */
void bufferLikeOutput(currLike)
double currLike;
#endif  /* if defined(MLINK) */
{ 
  /* temporary output buffer */
  char tempBuff[TEMPBUFF_SIZE]; 

 if (dostream) {
    sprintf(tempBuff, "%12.6f\n", currLike);
    append(streamBuff->ipeds[absoluteThetanum], tempBuff);
  }
  
#if defined(MLINK)
  if (lodbyfamily)
    sprintf(tempBuff, "%12.6f LOD= %12.6f\n", currLike,
	    ((currLike - eachlodII) > BIGNEGATIVE) ?
	    currLike - eachlodII : -999.999999);
  else 
#endif  /* if defined(MLINK) */
  sprintf(tempBuff, "%12.6f\n", currLike);
  
  append(stdoutBuff->ipeds[absoluteThetanum], tempBuff);
  if (byfamily)
    append(outfileBuff->ipeds[absoluteThetanum], tempBuff);
}



void bufferTotalsOutput(currAlike, currTlike)
double currAlike, currTlike;
{
  /* temporary output buffer */
  char tempBuff[TEMPBUFF_SIZE]; 

  sprintf(tempBuff, "%s\nTOTALS    %12.6f %12.6f\n",
	  LINE, currAlike, currTlike);
  append(stdoutBuff->ipeds[absoluteThetanum], tempBuff);
  append(outfileBuff->ipeds[absoluteThetanum], tempBuff);
  if (dostream) {
#if defined(MLINK)
    sprintf(tempBuff, "% .5e % .5e\n", currAlike, currTlike);
#elif defined(LINKMAP)
    sprintf(tempBuff, "% .5e % .5e\n", -2 * currAlike, currTlike);
#endif
    append(streamBuff->ipeds[absoluteThetanum], tempBuff);
  }
}



void bufferLodOutput(currAlike, currTlike, currFirsttime)
double currAlike, currTlike;
boolInt currFirsttime;
{
  /* temporary output buffer */
  char tempBuff[TEMPBUFF_SIZE]; 

  /* pointers to specific entries in each iped array for this
     iteration */
  strBuff* stdBuff = stdoutBuff->ipeds[absoluteThetanum];
  strBuff* outfBuff = outfileBuff->ipeds[absoluteThetanum];
#if defined(MLINK)
  strBuff* strmBuff = streamBuff->ipeds[absoluteThetanum];
#endif  /* defined(MLINK) */
  
  sprintf(tempBuff, "-2 LN(LIKE) = % .5e", currAlike);
  append(stdBuff, tempBuff);
  append(outfBuff, tempBuff);
  
#if defined(LINKMAP)
  append(stdBuff, "\n");
  append(outfBuff, "\n");
#endif  /* if defined(LINKMAP) */
  
#if defined(MLINK)  
  /* Note: the reason that unlinkedLike is declared shared (replacing
     scorevalue) is that the lodscore computations depend on the
     evaluation at theta == 0.5.  This evaluation must done first.
     Since the loadbalancing algorithm requires an intitial theta
     evaluation, this is taken care of by ensuring that the 0.5 theta
     evaluation corresponds to absoluteThetanum 0. */
  if (score && (!risk)) {
    if (mlocus == 2) {
      if (maletheta->theta[which - 1] == 0.5)
	*unlinkedLike = currTlike;
      currAlike = currTlike - *unlinkedLike;
      
      sprintf(tempBuff, " LOD SCORE = %12.6f", currAlike);
      append(stdBuff, tempBuff);
      append(outfBuff, tempBuff);
      
    } else {
      if (maletheta->theta[which - 1] == 0.5)
	*unlinkedLike = currAlike;
      currAlike = *unlinkedLike - currAlike;
      
      sprintf(tempBuff, " LOG LIKE DIFFERENCE = %12.6f", currAlike);
      append(stdBuff, tempBuff);
      append(outfBuff, tempBuff);
      
    }
    if (dostream) {
      sprintf(tempBuff, "% .5e\n", currTlike - *unlinkedLike);
      append(strmBuff, tempBuff);
    } 
  }
  append(stdBuff, "\n");
  append(outfBuff, "\n");
#endif  /* if defined(MLINK) */

  if (Tmk_proc_id == 0) {
    if (currFirsttime) {
      if (thisc < maxcensor) {
	sprintf(tempBuff, "Maxcensor can be reduced to %12d\n", thisc);
	append(stdBuff, tempBuff);
      } else {
	if (thisc > maxcensor)
	  append(stdBuff,
		 "you may gain efficiency by increasing maxcensor\n");
      }
    }
  }
}

#endif  /* if PARALLEL -- cgh */
