/*This file contains new versions of the routines segup and segdown, */
/* and some auxiliary routines for use with parallel FASTLINK*/
/* The seqential modifications are described in the papers: */
/* 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. Cottinghm, Jr., */
/* Avoiding Recomputation In Linkage Analysis,*/
/* Hum. Hered. 44(1994), pp. 225-237 */

/* Code in this file was written by R. M. Idury, A. A. Schaffer, S. Dwarkadas,
and S. K. Gupta */


#include <sys/time.h>
#include "commondefs.h"
#include "moddefs.h"

#define PAR_SIZE1       6000
#define PAR_SIZEMANY	3000
#ifndef OVERHEAD
#define OVERHEAD        10000  /* Approximate time for overhead in microsec */
#endif

int pnonzcount, qnonzcount;

void loadbalance();
#if !defined(LESSMEMORY)
void onechildup();
#endif
void onechilddown();
void manychilddown();
void manychildup();

#if PRECOMPUTE
void allocprob()
{  
     probtable = (double**) Tmk_malloc(Tmk_nprocs * (sizeof(double *)));
     if (!probtable)
        Tmk_errexit("MALLOC ERROR - probtable\n");
     Tmk_distribute((char *) &probtable, sizeof(probtable));

     for(i = 0; i < Tmk_nprocs; i++) {
       probtable[i] = (double *) Tmk_malloc((maxisozygclass 
		    * nuneed * nuneed) * sizeof(double));
       if (!probtable[i])
	 Tmk_errexit("MALLOC ERROR - probtable[%d]\n",i);
     }

     if (!sexlink) {
       probtableindex = (unsigned **) Tmk_malloc(Tmk_nprocs * (sizeof(unsigned *)));
       if (!probtableindex)
	 Tmk_errexit("MALLOC ERROR - probtableindex, use the slower version\n");
       Tmk_distribute((char *) &probtableindex, sizeof(probtableindex));
   
       for(i = 0; i < Tmk_nprocs; i++) {
	 probtableindex[i] = (unsigned *) Tmk_malloc((nuneed * nuneed) * sizeof(unsigned));
	 if (!probtableindex[i])
	   Tmk_errexit("MALLOC ERROR - probtableindex[%d]\n",i);
       }
       if (sexdif) {
	 probtabledif = (double**) Tmk_malloc(Tmk_nprocs * (sizeof(double *)));
	 if (!probtabledif)
	   Tmk_errexit("MALLOC ERROR - probtabledif\n");
	 Tmk_distribute((char *) &probtabledif, sizeof(probtabledif));

	 for(i = 0; i < Tmk_nprocs; i++) {
	   probtabledif[i] = (double *) Tmk_malloc((maxisozygclass 
			  * nuneed * nuneed) * sizeof(double));
	   if (!probtabledif[i])
	     Tmk_errexit("MALLOC ERROR - probtabledif[%d]\n",i);
	 }
     }

     classsize = (unsigned *) Tmk_malloc(nuprobclass * sizeof(unsigned));
     if (!classsize)
	Tmk_errexit("MALLOC ERROR - classsize\n");
     Tmk_distribute((char *) &classsize, sizeof(classsize));
     classbase = (unsigned *) Tmk_malloc(nuprobclass  * sizeof(unsigned));
     if (!classbase)
	Tmk_errexit("MALLOC ERROR - classbase\n");
     Tmk_distribute((char *) &classbase, sizeof(classbase));
     }
}
#endif

#if PRECOMPUTE
void getprobtable()  /* compute joint recombination probabilities */
{
  static int size = 0, firsttime = 1;
  int indey, i, j, ii, jj;
  char *recomb_flag;
  
  if(firsttime && !sexlink) {
    if (!AUTOSOMAL_RUN)
      fprintf(stderr, "\nWARNING: You are doing an autosomal run but have AUTOSOMAL_RUN set to 0");
    if ((!SEXDIF_RUN) && sexdif)
      fprintf(stderr, "\nWARNING: You are doing a sexdif run but have SEXDIF_RUN set to 0");
    firsttime = 0;
    recomb_flag = (char *) malloc(nuneed * sizeof(char));
    if (recomb_flag == NULL)
      malloc_err("recomb_flag in getprobtable");
    for(i = 0; i < nuneed; i++)
      recomb_flag[i] = 0;
    for(i = 0; i < fgeno; i++)
      recomb_flag[probstart[i]-1] = 1;
    size = 0;
    for(i = 0; i < nuneed; i++)
      if(recomb_flag[i] == 1) classbase[size++] = i;
    classsize[size-1] = nuneed - classbase[size-1];
    for(i = size-2; i >= 0; i--)
      classsize[i] = classbase[i+1] - classbase[i];
  }

  indey = 0;
  if (!sexlink) {
    for(i = 0; i < size; i++) {
      for(j = 0; j < size; j++) {
	probtableindex[mymaster][classbase[i]* nuneed+classbase[j]] = indey;
	for(ii = classbase[i]; ii < classbase[i]+classsize[i]; ii++) {
	  for(jj = classbase[j]; jj < classbase[j]+classsize[j]; jj++) {
	    probtable[mymaster][indey++] = segprob2[ii* nuneed+jj];
	  }
	}
      }
    }
  }
  if (sexdif) {
    indey = 0;
    for(i = 0; i < size; i++) {
      for(j = 0; j < size; j++) {
	for(ii = classbase[i]; ii < classbase[i]+classsize[i]; ii++) {
	  for(jj = classbase[j]; jj < classbase[j]+classsize[j]; jj++) {
	    probtabledif[mymaster][indey++] = segprob2[jj * nuneed + ii];
	  }
	}
      }
    }
  }
}
#endif

/*segsum2 is used in segup to compute some common subexpressions in
the probability updates.
first and second are the joint genotypes of the two parents.
fslength is the number of probabilities needed for the combined
isozygote class of both parental genotypes; fs stands for the product
of first and second. */

/* cgh -- made void for gcc */

Local void segsum2(first,second,fslength)
unsigned first, second, fslength;
{
  int g1, g2, g3, g4; /*indices to store gene numbers*/
  int f1, f2, s1, s2; /*indices to store haplotype numbers*/
  int indey; /*counter for combined isozygote equivalence class,
                will range from 0 to fslength-1*/
  int i, j, k, l; /*loop indices*/
  int FORLIM; /*limit on a for loop*/
  int FORLIM1, FORLIM2; /*lower and upper limits on a for loop*/
  int *TEMPGENE1, *TEMPGENE2; /*temporary pointers into genenumber table*/
  double *tempwith3; /*temporarily stores genarray for current child*/

  FORLIM = fence[first]; /*start of the isozygote class for first*/
  FORLIM1 = base[second]; /*start of the isozygote class for second*/
  FORLIM2 = fence[second]; /*end of the isozygote class for second*/
  indey = 0; /*start with first isozygote in the class*/
  /*iterate over isozygotes of i*/
  for (i = base[first]; i < FORLIM; i++) {
    f1 = haps1[i]; /*retrieve first haplotype of joint genotype i*/
    f2 = haps2[i]; /*retrieve second haplotype*/
    TEMPGENE1 = genenumber[f1 - 1]; /*lookup partial information
					    in genenumber table*/
    TEMPGENE2 = genenumber[f2 - 1];
    /*iterate over isozygotes of j*/
    for (j = FORLIM1; j < FORLIM2; j++) {
      s1 = haps1[j]; /*retrieve first haplotype of joint genotype j*/
      s2 = haps2[j]; /*retrieve second haplotype*/
     /*lookup the four ways to combine one haplotype from i and one from j*/
      g1 = TEMPGENE1[s1 - 1];
      g2 = TEMPGENE1[s2 - 1];
      g3 = TEMPGENE2[s1 - 1];
      g4 = TEMPGENE2[s2 - 1];

    /*iterate over children; update partial computations of
      new probabilities and store in array tempseg
      note that tempseg has nchild*fslength relevant entries
      The fslength entries for child 1 come first, then
      the fslength entries, for child 2, etc. This is why
      the increment on l is fslength for each change of child*/

      for (l = indey, k = 0 ; k < nchild; l += fslength, k++) {
	tempwith3 = thischild[k]->genarray; /*retrieve genarray*/

       /* sum the probabilities for the four joint genotypes that
        the child can get from the current parental joint genotypes*/

	tempseg[l] = (tempwith3[g1 - 1] + tempwith3[g2 - 1] +
			       tempwith3[g3 - 1] + tempwith3[g4 - 1]);
      }
      indey++; /*increment isozygote class counter*/
    }
  }
}  /*segsum2*/

/*segsumdown2 is used in segdown to compute some common subexpressions in
the probability updates.
first and second are the joint genotypes of the two parents.
fslength is the number of probabilities needed for the combined
isozygote class for both parental genotypes; fs stands for the
product of first and second. */

/* cgh -- void for gcc */

Local void segsumdown2(first,second,fslength)
unsigned first, second, fslength;
{
  int g1, g2, g3, g4; /*indices to store gene numbers*/
  int f1, f2, s1, s2; /*indices to store haplotype numbers*/
  int indey; /*counter for combined isozygote equivalence class,
                will range from 0 to fslength-1*/
  int index2; /*used as index for isozygote class*/
  int i, j, k, l; /*loop indices*/
  int FORLIM; /*limit on a for loop*/
  int FORLIM1, FORLIM2; /*lower and upper limits on a for loop*/
  int *TEMPGENE1, *TEMPGENE2; /*temporary pointers into genenumber table*/
  double *tempwith3; /*temporarily stores genarray for current child*/

  FORLIM = fence[first]; /*start of the isozygote class for first*/
  FORLIM1 = base[second]; /*start of the isozygote class for second*/
  FORLIM2 = fence[second]; /*end of the isozygote class for second*/
  indey = 0; /*start with first isozygote in the class*/
  index2 = 0;
  /*iterate over isozygotes of i*/
  for (i = base[first]; i < FORLIM; i++) {
    f1 = haps1[i]; /*retrieve first haplotype of joint genotype i*/
    f2 = haps2[i]; /*retrieve second haplotype*/
    TEMPGENE1 = genenumber[f1 - 1]; /*lookup partial information
					    in genenumber table*/
    TEMPGENE2 = genenumber[f2 - 1];
    /*iterate over isozygotes of j*/
    for (j = FORLIM1; j < FORLIM2; j++) {
      s1 = haps1[j]; /*retrieve first haplotype of joint genotype j*/
      s2 = haps2[j]; /*retrieve second haplotype*/
     /*lookup the four ways to combine one haplotype from i and one from j*/
      g1 = TEMPGENE1[s1 - 1];
      g2 = TEMPGENE1[s2 - 1];
      g3 = TEMPGENE2[s1 - 1];
      g4 = TEMPGENE2[s2 - 1];
      /*store these gene numbers for later use; the
        key point is that we will want these numbers
        consecutively later, so we store them consecutively
        in segindex*/
      segindex[index2++] = g1;
      segindex[index2++] = g2;
      segindex[index2++] = g3;
      segindex[index2++] = g4; 

    /*iterate over children; update partial computations of
      new probabilities and store in array tempseg
      note that tempseg has nchild*fslength relevant entries
      The fslength entries for child 1 come first, then
      the fslength entries, for child 2, etc. This is why
      the increment on l is fslength for each change of child*/

      for (l = indey, k = 0 ; k < nchild; l += fslength, k++) {
	tempwith3 = thischild[k]->genarray; /*retrieve genarray*/

       /* sum the probabilities for the four joint genotypes that
        the child can get from the current parental joint genotypes*/

	tempseg[l] = (tempwith3[g1 - 1] + tempwith3[g2 - 1] +
			       tempwith3[g3 - 1] + tempwith3[g4 - 1]);
      }
      indey++; /*increment isozygote class counter*/
    }
  }
}     /*segsumdown2*/

/*lsegfun2 does a logical test similar to the computation
done in the original segfun to determine whether segfun
would return 0.0. If segfun would return 0.0, then lsegfun2
return 0 (FALSE), while if segfun would not return 0.0.,
lsegfun2 returns 1 (TRUE). Given, a combined isozygote class,
we want to know whether any elements of that isozygote
class are possible joint genotypes for the parents.
This will be the case if and only if each child has
a nonzero probability for at least one of the joint genotypes
that the parents can produce given their isozygote class.
first and second are the joint genotypes for the parents. */

unsigned lsegfun2(first,second)
unsigned first, second;
{
  int g1, g2, g3, g4; /*four gene numbers*/
  int i, j, k; /* loop indices*/
  int f1, f2, s1, s2; /*haplotype numbers*/
  int FORLIM; /*loop bound*/
  int FORLIM1, FORLIM2; /*loop bounds*/
  int *TEMPGENE1, *TEMPGENE2; /* store pointers into genenumber*/
  unsigned char *tempflag3; /*stores sparsity pattern for child's genarray*/

  FORLIM = fence[first]; /*find end of isozygote class for first*/
  FORLIM1 = base[second];/*find beginning and end of isozygote class
			   for second*/
  FORLIM2 = fence[second];

/*try to find a non-zero value for each child*/
for (k = 0; k < nchild; k++) {
  /*code for the non-boolean version is shown in comments
  tempwith3 = thischild[k]->genarray;*/
  /*retrieve sparsity pattern for child k*/
  tempflag3 = thischild[k]->sparseflag;
  
  /*iterate over all recombined isozygotes of first*/
  for (i = base[first]; i < FORLIM; i++) {
    f1 = haps1[i]; /*retrieve the haplotypes of this genotype*/
    f2 = haps2[i];
    TEMPGENE1 = genenumber[f1 - 1];/*get pointer into genenumber for
					   this haplotype*/
    TEMPGENE2 = genenumber[f2 - 1];

    /*iterate over all the recombined isozygotes of second*/
    for (j = FORLIM1; j < FORLIM2; j++) {
      s1 = haps1[j]; /*get haplotypes of this genotype*/
      s2 = haps2[j];
/*retrieve the four genes that this combination of joint haplotypes
  can produce*/
      g1 = TEMPGENE1[s1 - 1];
      g2 = TEMPGENE1[s2 - 1];
      g3 = TEMPGENE2[s1 - 1];
      g4 = TEMPGENE2[s2 - 1];
      /*if(tempwith3[g1 - 1] != 0.0 || tempwith3[g2 - 1] != 0.0 ||
	 tempwith3[g3 - 1] != 0.0 || tempwith3[g4 - 1] != 0.0) goto notzero;*/

   /*if any of the flags is TRUE, then this child can have this genotype,
     and we move immediately to testing the next child*/
      if(tempflag3[g1 - 1] != 0 || tempflag3[g2 - 1] != 0 ||
	 tempflag3[g3 - 1] != 0 || tempflag3[g4 - 1] != 0) goto notzero;
    }
  }

  return 0; /*this child failed to have any of the genotypes for
	      the isozygote class, so this isozygote class is not possible*/
  notzero: continue;
}
return 1; /*all children passed the test and have a possible joint genotype*/
}

/*segup updates the genotype probabilities for a parent (p) based
on the probabilities of children. The parameter LINK includes
all the genetic information about p, p's spouse q, and their
children*/

void segup(LINK)
struct LOC_seg *LINK;
{
  int  step1, step2; /*size of isozygote classes*/
  unsigned int i, j; /*genotype indices*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
						       p,q, and children*/
  unsigned char *newflag2, *newflag3; /*store sparsity patterns for
					p and q genarrays*/

  boolean depend; /*used to handle loops*/

  initseg(LINK); /*get data about this p,q,children triple*/

  gMem->trav_flag[mymaster] = MANYUP;

  /*get sparsity patterns for p and q genarrays*/
  newflag2 = (*LINK->p)->gen->sparseflag; 
  newflag3 = (*LINK->q)->gen->sparseflag;

  WITH2 = (*LINK->p)->gen; /*get genetic data for p*/
  WITH3 = (*LINK->q)->gen; /*get genetic data for q*/
  newwith2=WITH2->genarray; /*get genarray for p*/
  newwith3=WITH3->genarray; /*get genarray for q*/
  newwithr=thischild[0]->genarray; /*get genarray for first child*/

/*The case of 1 child is handled specially because the subcomputations
are much simpler. In particular we do not need to multiply the
probabilities among the different children. In a typical pedigree
many pairs will have only one child about which information is known
(in essence this is the child that keeps the pedigree connected), so
this is an important and common special case. */

#if !defined(LESSMEMORY)
if(nchild == 1) {
  gMem->trav_flag[mymaster] = ONEUP;

  pnonzcount = qnonzcount = 0;
/*find nonzero entries in q's genarray and make a list of them
  stored in qnonzgens; just get one per isozygote class*/
  if (*firstfe) {
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i++) {
      if(newflag3[i] != 0) {
	qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
      }
    }
    
    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i++) {
      if(newflag2[i] != 0) {
	pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
      }
    }
  }
  loadbalance(LINK);
}


else  {  /*nchild is bigger than 1*/
#endif
  newwith2=(*LINK->p)->gen->genarray; /*get p's genarray*/
 
/*find nonzero entries in q's genarray and make a list of them
  stored in qnonzgens; just get one per isozygote class*/
  pnonzcount = qnonzcount = 0;

  if (*firstfe) {
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i += step2) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step2 = probend[i] - probstart[i] + 1; 
      for(j = i; j < i+step2; j++)
	if(newflag3[j] != 0) {
	  qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }

    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i += step1) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step1 = probend[i] - probstart[i]+1; 

      /*work only on those isozygotes that are possible*/
      for(j = i; j < i+step1; j++)
	if(newflag2[j] != 0) {
	  pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
	  break; /*go to next isozygote in class*/
	}
    }
  }
  loadbalance(LINK);

#if !defined(LESSMEMORY)
}
#endif
/* If any of the nonzero entries in p's genarray became 0,
   we want to set them to zero to avoid computations on subsequent
   calls*/

/* Not parallelized because we're dealing with characters - memo diffs on 
   words
 */

  for(i = 0; i < fgeno; i++)
    if((newflag2[i] != 0) && (newwith2[i] == 0.0)) {
	newflag2[i] = 0;
    }
 /*Added by Alex to handle loops */
   if (loopfirstgen && (!(*LINK->p)->loopdepend)) {
     depend = false;
     for(i=0; i<nchild; i++)
       if (childarray[i]->loopdepend) {
         depend = true;
         break;
       }
     depend = (depend || ((*LINK->q)->loopdepend));
     if (depend) {
       (*LINK->p)->loopdepend = depend;
       (*LINK->p)->loopneeded = false;
     }
   }
   if ((*LINK->p)->loopdepend) {
     if (!((*LINK->q)->loopdepend))
       (*LINK->q)->loopneeded = true;
     for(i=0; i< nchild; i++)
       if (!(childarray[i]->loopdepend))
         childarray[i]->loopneeded = true;
   }

  cleanup(LINK->q, LINK->LINK);
  exitseg(LINK);
}  /*segup*/

#if !defined(LESSMEMORY)
void onechildup()
{
  int  FORLIM; /*loop bound*/
  int  pnonzindex, qnonzindex;    /*loop index and counter for nonzero values*/
  double valtemp; /*intermediate values in probability updates*/
  double val, temp1, tempr; /*temporaries to store intermediate values*/
  static unsigned current;
  unsigned int f1, f2; /*two haplotypes from parents*/
  unsigned int here, i, j, first; /*genotype indices*/
  int procindex;
  thisarray *WITH2, *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
			         p,q, and children*/
  thetavalues *WITH4; /*stores theta values for p parent*/
  thetavalues *WITH5; /*store theta values for q parent*/
  unsigned int c1, c2; /*haplotypes*/
  unsigned char *newflag2, *newflagr; /*store sparsity patterns for
				p and q genarrays*/


  /* newsegprob is  used to hold segprob
    arrays, which contain the probabilities for various patterns of
    recombination events*/
  double *newsegprob; 
  int ind;      /*used to store offset for probability array*/

  /* Structures to store start and end time for rows */
  struct timeval starttime, endtime;

  int pbase, pfence, qbase, qfence;

  pbase = gMem->pprocbase[Tmk_proc_id];
  pfence = gMem->pprocfence[Tmk_proc_id];
  qbase = gMem->qprocbase[Tmk_proc_id];
  qfence = gMem->qprocfence[Tmk_proc_id];
  nchild = gMem->nchild[mymaster];
  WITH2 = gMem->pgenptr[mymaster]; /*get genetic data for p*/
  WITH3 = gMem->qgenptr[mymaster]; /*get genetic data for q*/
  newwith2=WITH2->genarray; /*get genarray for p*/
  newwith3=WITH3->genarray; /*get genarray for q*/
  newflag2 = gMem->pgenptr[mymaster]->sparseflag;
  newflagr = gMem->rgenptr[mymaster]->sparseflag;
  newwithr=thischild[0]->genarray; /*get genarray for first child*/

  if ((!sexdif) || (!readfemale))
    WITH4 = WITH5 = maletheta;
  else {
    if (gMem->pmale[mymaster]) {
      WITH4 = maletheta; /*get male probabilities for p*/
      WITH5 = femaletheta; /*get female probabilities for q*/
    }
    else {
      WITH4 = femaletheta; /*get female probabilities for p*/
      WITH5 = maletheta; /*get male probabilities for q*/
    }
  }

  newsegprob = WITH5->segprob; /*use q probabilities to work with q*/

  if(!*firstfe) {
    /*find nonzero entries in q's genarray and make a list of them
      stored in qnonzgens; just get one per isozygote class*/
    qnonzgens = privateqnonzgens;
    qnonzcount = 0;
    
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i++) {
      if(newwith3[i] != 0.0) {
        qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
      }
    }

    pnonzgens = privatepnonzgens;
    pnonzcount = 0;
    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i++) {
      if(newwith2[i] != 0.0) {
        pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
      }
    }
    if (!onlymaster) {
      /*stripe pnonzgens array*/
      j = 0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < pnonzcount; i+=Tmk_nprocs)
	  stripe_pnonzgens[j++]=pnonzgens[i];
      }
      for(i = 0; i < pnonzcount; i++)
	pnonzgens[i] = stripe_pnonzgens[i];

      j =0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < qnonzcount; i+=Tmk_nprocs)
	  stripe_qnonzgens[j++]=qnonzgens[i];
      }
      for(i = 0; i < qnonzcount; i++)
	qnonzgens[i] = stripe_qnonzgens[i];
    }
  }
  else {
    pnonzgens = gpnonzgens[currentthetanum];
    qnonzgens = gqnonzgens[currentthetanum];
  }

/*initialize cache data structures*/
  for(i=0; i<maxhaplo; i++) {
    flag[i] = 0;
    phapcache1[i].first = 0;
    onechildupqsumcache[i] = 0.0;
  }

/*initialize gene array and set up flag array*/
  for(i = 0; i < fgeno; i++) {
    gene[i] = 0.0;
    if(newwithr[i] == 0.0) continue;
    flag[invgenenum1[i]-1] = 1;
    flag[invgenenum2[i]-1] = 1;
  }

  current = 1; /* current should start with 1, since 0 means a null ptr */

  /*iterate over genotypes for p*/
  for (pnonzindex = pbase; pnonzindex < pfence; pnonzindex++) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else
    if((*secondfe)&&(mymaster == 0))
#endif
      gettimeofday(&starttime, NULL);  /* Get start time */

    first = pnonzgens[pnonzindex];

    FORLIM = fence[first]; /*find end of isozygote class of first*/

  /*iterate over all members of first's isozygote class*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i]; /*get haplotypes*/
      f2 = haps2[i];
      ind = hind[i];  /*get probability offset for i*/

   /*if f1 is a possible haplotype for child add the
     probability offset and value of first to the cache*/
      if(flag[f1-1] != 0) {
	indpool[current] = ind; /*store values in cache*/
	invpool[current] = first;
	nextpool[current] = 0;
        
       /* increment cache indices*/
	if(phapcache1[f1-1].first == 0) {  
	  phapcache1[f1-1].first = current;
	  phapcache1[f1-1].last = current;
	}
	else {
	  nextpool[phapcache1[f1-1].last] = current;
	  phapcache1[f1-1].last = current;
	}
	current++;
      }
 
      /*similar to f1, if f2 is a possible haplotype for
        a child, cache the ind and first values for it*/
      if(flag[f2-1] != 0) {
	indpool[current] = ind;
	invpool[current] = first;
	nextpool[current] = 0;
	if(phapcache1[f2-1].first == 0) {
	  phapcache1[f2-1].first = current;
	  phapcache1[f2-1].last = current;
	}
	else {
	  nextpool[phapcache1[f2-1].last] = current;
	  phapcache1[f2-1].last = current;
	}
	current++;
      }
    }

#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else
    if((*secondfe)&&(mymaster == 0)) {
#endif
      gettimeofday(&endtime, NULL);  /* Get end time */
      rowtime[pnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                          + (endtime.tv_usec - starttime.tv_usec);
    }
  }

  /*This section of the code precomputes for each haplotype the probability
  that the child will inherit this haplotype from q. Each genotype has
  two haplotypes, but can produce others by recombination. Therefore,
  for each genotype we must sum over the different haplotypes that can
  be produced by its isozygote class. The contributions for each haplotype
  are stored in onechildupqsumcache.*/


 /*iterate over all joint genotypes*/
  for (qnonzindex = qbase; qnonzindex < qfence; qnonzindex++ ) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else
    if((*secondfe)&&(mymaster == 0))
#endif
      gettimeofday(&starttime, NULL);  /* Get start time */
    first = qnonzgens[qnonzindex];
    valtemp = newwith3[first]; /*get cond. prob. that q has genotype first*/
    FORLIM = fence[first]; /*find bounds for the isozygote class of first*/

 /*iterate over all the recombined genotypes of the isozygote class*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i];
      f2 = haps2[i];
      if((flag[f1-1] != 0) || (flag[f2-1] != 0)) {
/*conditional probability of first as a genotype multiplied by probability
  of passing on f1 (alternatively f2) as a haplotype*/
        val = valtemp*newsegprob[hind[i]];

       /*store in onechildupqsumcache*/
        if(flag[f1-1] != 0) {
	  onechildupqsumcache[f1 - 1] += val;
        }
        if(flag[f2-1] != 0) {
	  onechildupqsumcache[f2 - 1] += val;
        }
      }
    }
#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else
    if((*secondfe)&&(mymaster == 0)) {
#endif
      gettimeofday(&endtime, NULL);  /* Get end time */
      qrowtime[qnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                           + (endtime.tv_usec - starttime.tv_usec);
    }
  }

  
  if (((*slavesPerGroup) > 1) && (!onlymaster)) {
    for(i = 0; i < maxhaplo;i++) {
      arrqsumcache[Tmk_proc_id][i] = onechildupqsumcache[i];
      onechildupqsumcache[i] = 0;
    }
    if(((*slavesPerGroup) > 1) && (!onlymaster)) {
#if BARRIER_OUTPUT
      printBarrier("(%d) Group barrier at middle of onechildup\n",++barnum);
#endif
#if IS_SHMEM
      BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else
      Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif
    }

    for(j=mymaster; j<(mymaster + (*slavesPerGroup));j++)
      for(i = 0;i < maxhaplo;i++)
        onechildupqsumcache[i] += arrqsumcache[j][i];
  }

 /*In this section of the code we update the probabilities for
  the parent p based on the probabilities for the child*/  
  newsegprob = WITH4->segprob; /*use p probabilities to work with p*/

 /*Iterate over all joint genotypes of the child*/
  newflagr=thischild[0]->sparseflag;
  for(here = 0; here < fgeno; here++) {
    if(newflagr[here] == 0) continue;
    tempr = newwithr[here];
    c1 = invgenenum1[here];
    c2 = invgenenum2[here];
    temp1 = tempr * onechildupqsumcache[c2 - 1]; /*multiply probabilities for
					 haplotype c2 from q*/

  /*now find all the values of first that as genotypes of the
 father could have passed on the other haplotype c1; multiply
  by their probabilties, which are stored in phapcache, and
  add to the entry gene[first], which will be used to form
 the new genarray for p*/

    for(i=phapcache1[c1-1].first; i != 0; i = nextpool[i]) {
      first = invpool[i];
      gene[first] += temp1*newsegprob[indpool[i]];
    }

  /*if c1 is distinct from c2 we need to do the same computation reversing
    the roles of the two haplotypes*/
    if(c1 != c2) {
      temp1 = tempr * onechildupqsumcache[c1 - 1];
      for(i=phapcache1[c2-1].first; i != 0; i = nextpool[i]) {
        first = invpool[i];
	gene[first] += temp1*newsegprob[indpool[i]];
      }
    }
  }

/*set up new genarray for p; it is gene scaled by segscale*/
  for (pnonzindex = pbase; pnonzindex < pfence; pnonzindex++) {
    first = pnonzgens[pnonzindex];
    newwith2[first] *= segscale*gene[first];
  }

/* Commented out since no summation is needed (all gene computations are 
   independent and this parent will not
   be a parent in the next computation call. The synchronization 
   necessary for these updates will be achieved through seg_barrier
   at the time each process waits for more work - Sandhya
 */
  if ((*slavesPerGroup > 1) && (!onlymaster)) {
#if BARRIER_OUTPUT
    printBarrier("(%d) Group barrier at end of onechildup\n", ++barnum);
#endif /*BARRIER_OUTPUT*/
#if IS_SHMEM
    BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else /*!IS_SHMEM*/
    Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif /*IS_SHMEM*/
  }

} /* onechildup */
#endif


/*
manychildup handles the case of updating one parent from
spouse and children when the parents p and q have more than one child
(nchild > 0)
*/

void manychildup()
{
  int pnonzindex, qnonzindex;    /*loop index and counter for nonzero values*/
  int  step1, step2; /*size of isozygote classes*/
  unsigned int *tempstart; /*temporary index to probability array*/
  double val, temp1; /*temporaries to store intermediate values*/
  unsigned int i, j, first, second; /*genotype indices*/
  int procindex;
  unsigned int fslength; /*size of product isozygote class for p and q*/
#if !PRECOMPUTE
  int findex, sindex;
#endif
  int jointisoindex, fisoindex; /*indices to work within isozygote classes*/
  unsigned l; /*increment used to manage offset into probtableindex
                l is the number of probability values needed for the current
		isozygote class. This is obtained by multplying the
		number of probabilities (maxneed) times the size of the
		class*/
  unsigned k; /*index to loop over children*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
						       p,q, and children*/
#if !PRECOMPUTE  /* cgh - gcc */
  double* newsegr;   /* store genarrays for p,q, and children */
#endif  /* !PRECOMPUTE */

  thetavalues *WITH4; /*stores theta values for p parent*/
  thetavalues *WITH5; /*store theta values for q parent*/
  unsigned char *newflag2, *newflag3; /*store sparsity patterns for
					p and q genarrays*/

#if !PRECOMPUTE
  double *newsegprob1, *newsegprob2;
#endif

  double *tempprob; /*temporary holder for probability array*/
  int pbase, pfence, qbase, qfence; /*bounds for  p and q genotypes for this
                                      processor to work on*/

  /* Structures to store start and end time for rows */
  struct timeval starttime, endtime;

  pbase = gMem->pprocbase[Tmk_proc_id];
  pfence = gMem->pprocfence[Tmk_proc_id];
  qbase = gMem->qprocbase[Tmk_proc_id];
  qfence = gMem->qprocfence[Tmk_proc_id];
  nchild = gMem->nchild[mymaster];

  /*get sparsity patterns for p, q, and child genarrays*/
  WITH2 = gMem->pgenptr[mymaster]; /*get genetic data for p*/
  WITH3 = gMem->qgenptr[mymaster]; /*get genetic data for q*/
  newwith2=WITH2->genarray; /*get p's genarray*/
  newwith3=WITH3->genarray; /* get q's genarray */
  newflag2 = gMem->pgenptr[mymaster]->sparseflag; 
  newflag3 = gMem->qgenptr[mymaster]->sparseflag;

  /* newwithr=thischild[0]->genarray; get genarray for first child*/
  if ((!sexdif) || (!readfemale))
    WITH4 = WITH5 = maletheta;
  else {
    if (gMem->pmale[mymaster]) {
      WITH4 = maletheta; /*get male probabilities for p*/
      WITH5 = femaletheta; /*get female probabilities for q*/
    }
    else {
      WITH4 = femaletheta; /*get female probabilities for p*/
      WITH5 = maletheta; /*get male probabilities for q*/
    }
  }
#if !PRECOMPUTE
  newsegprob1 = WITH4->segprob; /*get p probabilities*/
  newsegprob2 = WITH5->segprob; /*get q probabilties*/
#endif

  if(!*firstfe) {
    /*find nonzero entries in q's genarray and make a list of them
      stored in qnonzgens; just get one per isozygote class*/
    qnonzgens = privateqnonzgens;
    qnonzcount = 0;

    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i += step2) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step2 = probend[i] - probstart[i] + 1;
      for(j = i; j < i+step2; j++)
	if(newflag3[j] != 0) {
	  qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }
    qfence = qnonzcount;   /* Set qfence to correct value */
    
    pnonzgens = privatepnonzgens;
    pnonzcount = 0;
    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i += step1) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step1 = probend[i] - probstart[i]+1;

      /*work only on those isozygotes that are possible*/
      for(j = i; j < i+step1; j++)
	if(newflag2[j] != 0) {
	  pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
	  break; /*go to next isozygote in class*/
	}
    }
    /*stripe pnonzgens array*/
    if (!onlymaster) {
      j = 0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < pnonzcount; i+=Tmk_nprocs)
	  stripe_pnonzgens[j++]=pnonzgens[i];
      }
      for(i = 0; i < pnonzcount; i++)
	pnonzgens[i] = stripe_pnonzgens[i];
    }
  }
  else {
    pnonzgens = gpnonzgens[currentthetanum];
    qnonzgens = gqnonzgens[currentthetanum];
  }

  /*iterate over genotypes for p*/
  for (pnonzindex = pbase; pnonzindex < pfence; pnonzindex++) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else
    if((*secondfe)&&(mymaster == 0))
#endif
      gettimeofday(&starttime, NULL);  /* Get start time */

    first = pnonzgens[pnonzindex];
    step1 = probend[first] - probstart[first]+1;

    /*initialize update multiple for each isozygote in class*/
    for(i = 0; i < step1; i++) segval[i] = 0.0;

    /*iterate over the genotypes representing isozygote classes that
     q may have*/
    for (qnonzindex = qbase; qnonzindex < qfence; qnonzindex++) {
      second = qnonzgens[qnonzindex];
      /*check if this first, second pair yield a nonzero value
        among children's probabilities*/
      if(lsegfun2(first,second) == 0) continue;

      /*number of distinct probabilties needed for second's isoz. class*/
      step2 = probend[second] - probstart[second] + 1; 
      fslength = step1 * step2; /*number of probs. for combined isozygote class*/
#if PRECOMPUTE
      fisoindex = (probstart[first] - 1) * nuneed - 1; /*probability array offset*/
#endif /*PRECOMPUTE*/
      tempstart = probstart + second; /*set tempstart to the start of
					the section of probstart that
					we want*/
      l = step1 * nuneed; 
  
   /*call segsum2 to compute the part of the conditional probability
     update that is common to all the members of the combined isozygote
     class defined by first and second */
      segsum2(first,second,fslength);

#if !PRECOMPUTE
      newsegr = tempseg2;
      tempprob = tempseg;
      for (k = 0;k < nchild; k++) {
        for(i = 0; i < step1; i++) {
          newwithr = tempprob;
          findex = probstart[first + i] - 1;
          temp1 = newsegprob1[findex];
          for (sindex = 0; sindex < step2; sindex++)
            newsegr[sindex] = temp1*(*newwithr++);
          for(findex++; findex < probend[first +i]; findex++) {
            temp1 = newsegprob1[findex];
            for(sindex = 0; sindex < step2; sindex++)
              newsegr[sindex] += temp1*(*newwithr++);
          }
          newsegr += step2;
        }
        tempprob += fslength;
      }
#endif /*!PRECOMPUTE*/

      /*now specialize update for each member of first's class*/
      for(i = 0; i < step1; i++) {
	if(newflag2[first+i] == 0) {
#if PRECOMPUTE
	  fisoindex += l; /*increment by number of probabilities
			   needed for this iso. class*/
#endif /*PRECOMPUTE*/
	  continue; /*skip if this isozygote is not possible*/
	}
        /*further specialize update for each member of second's isozygote
          class*/
	for(j = 0; j < step2; j++) {
        /*skip if this isozygote not possible*/
	  if(newflag3[second+j] == 0) continue; 

          /*get offset into probtable; the offset depends on
            the isozygote class size and index of each parent
            note that fisozygoteindex gets incremented by the size
            of the joint class each time, so it represents a
            sum of all the numbers of distinct probabilities
            needed for all joint iso. classes  considered before the
            current p isozygote class*/

#if PRECOMPUTE
#if AUTOSOMAL_RUN
	  if ((!sexdif) || (gMem->pmale[mymaster]))
	    tempprob = probtable[mymaster] + probtableindex[mymaster][fisoindex+tempstart[j]];
#if SEXDIF_RUN
          else
	    tempprob = probtabledif[mymaster] + probtableindex[mymaster][fisoindex+tempstart[j]];
#endif /*SEXDIF_RUN*/
#endif /*AUTOSOMAL_RUN*/

        /*combine for all children*/
        /*due to the arrangement in segsum all the probability contributions
          for a given child are contiguous in the newwithr array.
          the number of contributions is fslength which is the number of
          probabilities needed for the joint isozygote class of the parents.
          We get the contribution of the first child (index 0) and
          then loop over the rest*/
	  val = tempprob[0] * tempseg[0];
         /*iterate over joint isozygote class*/
	  for(jointisoindex = 1; jointisoindex < fslength; jointisoindex++)
	    val += tempprob[jointisoindex] * tempseg[jointisoindex];
	  newwithr = tempseg + fslength; /*move the base of newwithr*/
#else /* !PRECOMPUTE */
          val = 1.0;
          newwithr = tempseg2 + i*step2;
          tempprob = newsegprob2 + probstart[second + j] -1;
#endif /* PRECOMPUTE */
#if PRECOMPUTE
         /*iterate over all the remaining children; notice that the
           loop index k is not used inside the loop. this is because the
           last loop statement which moves the offset of newwithr
           has the effect of incrementing the child*/
	  for(k = 1; k < nchild; k++) {
	    temp1 = tempprob[0] * newwithr[0];
	    for(jointisoindex = 1; jointisoindex < fslength; jointisoindex++)
	      temp1 += tempprob[jointisoindex] * newwithr[jointisoindex];
#else /* !PRECOMPUTE*/
          for(k = 0; k < nchild; k++) {
            temp1 = 0.0;
            for(sindex = 0; sindex < step2; sindex++)
              temp1 += tempprob[sindex] * newwithr[sindex];
#endif /* PRECOMPUTE */
	    val *= temp1;
	    newwithr += fslength;
	  }
         /*update segval entry for this isozygote of first*/
	  segval[i] += newwith3[second+j] * val;
	}
#if PRECOMPUTE
	fisoindex += l; /*go to next isozygote for p*/
#endif /* PRECOMPUTE */
      }
    }
    /*update p's genarray for each isozygote in this class*/
    for(i = 0; i < step1; i++) {
	newwith2[first+i] *= segval[i] * segscale;
    }
#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else /* !LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0)) {
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&endtime, NULL);  /* Get end time */
      rowtime[pnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                          + (endtime.tv_usec - starttime.tv_usec);
    }
  }


/* Commented out since no summation is needed (all gene computations are 
   independent and this parent will not
   be a parent in the next computation call. The synchronization 
   necessary for these updates will be achieved through seg_barrier
   at the time each process waits for more work - Sandhya
 */

  if ((*slavesPerGroup > 1) && (!onlymaster)) {
#if BARRIER_OUTPUT
    printBarrier("(%d) Group barrier at end of manychildup\n", ++barnum);
#endif /*BARRIER_OUTPUT*/
#if IS_SHMEM
    BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else /* !IS_SHMEM*/
    Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif
  }
}  /*manychildup*/

/* loadbalancer that splits according to the p index evenly*/

void loadbalance(LINK)
struct LOC_seg *LINK;
{ /*B+1*/
   int procindex;
   int fenceindex;
   int i,j; /*loop indices*/
   static int currentfamilynum = -1;
   double totaltime, accumtime;   /* Add computation time for each row */
   int remainder;
   static int printout = 0;
   int oh;

/*  gettimeofday(&starttime, NULL); */ /* Get start time */

/*   printf("Entering loadbalance with numnuclear = %d, nfe = %d\n",*numNuclear,gnfe[currentthetanum]);*/

   if(pnonzcount > fgeno) { /*B+2*/
     Tmk_errexit("rowtime cannot hold %d times\n",pnonzcount);
   } /*B+2*/

   if(((qnonzcount) > fgeno) && ((gMem->trav_flag[mymaster] == ONEUP) ||
      (gMem->trav_flag[mymaster] == ONEDOWN))) { /*B+2*/
     Tmk_errexit("qrowtime cannot hold %d times\n",qnonzcount);
   } /*B+2*/

   
   gMem->pgenptr[mymaster] = (*LINK->p)->gen;
   gMem->qgenptr[mymaster] = (*LINK->q)->gen;
   gMem->rgenptr[mymaster] = (*LINK->r)->gen;
   gMem->pmale[mymaster] = (*LINK->p)->male;

/*retrieve thetas to propagate to all processors in group*/
#if (defined(MLINK) || defined(LINKMAP))  /* cgh */
   if (sexdif && readfemale)
       for(j=0;j<mlocus - 1;j++) { /*B+2*/
	   maletheta->theta[j] = gmaletheta[absoluteThetanum][j];
	   femaletheta->theta[j] = gfemaletheta[absoluteThetanum][j];
       } /*B+2*/
   else
       for(j=0;j<mlocus - 1;j++) 
	   maletheta->theta[j] = gmaletheta[absoluteThetanum][j];
#else  /* if (defined(MLINK) || defined(LINKMAP)) */
   if (sexdif && readfemale)
       for(j=0;j<mlocus - 1;j++) { /*B+2*/
	   maletheta->theta[j] = gmaletheta[currentthetanum][j];
	   femaletheta->theta[j] = gfemaletheta[currentthetanum][j];
       } /*B+2*/
   else
       for(j=0;j<mlocus - 1;j++) 
	   maletheta->theta[j] = gmaletheta[currentthetanum][j];
#endif  /* if (defined(MLINK) || defined(LINKMAP)) -- cgh */

   if (*firstfe) { /*B+2*/
     (*numNuclear)++;
     currentfamilynum++;
     currentfamilynum = currentfamilynum % MAXNUMFAM;
   } /*B+2*/
   else
     currentfamilynum = (currentfamilynum + 1) % (*numNuclear);

   if (*firstfe) { /*B=2*/
     /*stripe pnonzgens array*/
     j = 0;
     for(procindex = 0; procindex < Tmk_nprocs; procindex++){ /*B+3*/
       for(i = procindex; i < pnonzcount; i+=Tmk_nprocs)
	 stripe_pnonzgens[j++]=pnonzgens[i];
     } /*B+3*/
     for(i = 0; i < pnonzcount; i++)
       pnonzgens[i] = stripe_pnonzgens[i];

     if((gMem->trav_flag[mymaster] == ONEUP) ||
	(gMem->trav_flag[mymaster] == ONEDOWN)) { /*B+3*/
       /*stripe qnonzgens array*/
       j =0;
       for(procindex = 0; procindex < Tmk_nprocs; procindex++){ /*B+4*/
	 for(i = procindex; i < qnonzcount; i+=Tmk_nprocs)
	   stripe_qnonzgens[j++]=qnonzgens[i];
       } /*B+4*/
       for(i = 0; i < qnonzcount; i++)
	 qnonzgens[i] = stripe_qnonzgens[i];
     } /*B+3*/
   } /*B+2*/

   if (*firstfe) {/* If this is the first function evaluation */ /*B+2*/
     /*schaffer changed test here to avoid int overflow in product*/
     if((((gMem->trav_flag[mymaster] == ONEUP)
	  || (gMem->trav_flag[mymaster] == ONEDOWN))
	 &&((pnonzcount <= PAR_SIZE1) && (qnonzcount <= PAR_SIZE1) &&
             (pnonzcount*qnonzcount)<=PAR_SIZE1)
	||(((gMem->trav_flag[mymaster] != ONEUP)
	    && (gMem->trav_flag[mymaster] != ONEDOWN))
	   &&((pnonzcount <= PAR_SIZEMANY) && (qnonzcount <= PAR_SIZEMANY) &&
             (pnonzcount*qnonzcount)<=PAR_SIZEMANY))))
       for(procindex = 0; procindex < (Tmk_nprocs); procindex++) { /*B+3*/
         (*rowfence)[currentfamilynum][procindex] = pnonzcount;
         (*qfence)[currentfamilynum][procindex] = qnonzcount;
       } /*B+3*/
     else { /*B+3*/
       remainder = pnonzcount % Tmk_nprocs;   /* Setup base/fence values */
       (*rowfence)[currentfamilynum][0] = pnonzcount/Tmk_nprocs;
       for(procindex = 1; procindex < (Tmk_nprocs); procindex++) { /*B+4*/
	 (*rowfence)[currentfamilynum][procindex] =
	   (*rowfence)[currentfamilynum][procindex-1] + pnonzcount/Tmk_nprocs;
	 if(remainder > 0) { /*B+5*/
	   (*rowfence)[currentfamilynum][procindex]++;
	   remainder--;
	 } /*B+5*/
       } /*B+4*/
       if((gMem->trav_flag[mymaster] == ONEUP) ||
	  (gMem->trav_flag[mymaster] == ONEDOWN)) { /*B+ 4*/
	 remainder = qnonzcount % Tmk_nprocs;   /* Setup base/fence values */
	 (*qfence)[currentfamilynum][0] = qnonzcount/Tmk_nprocs;
	 for(procindex = 1; procindex < Tmk_nprocs; procindex++) { /*B+5*/
	   (*qfence)[currentfamilynum][procindex] =
	     (*qfence)[currentfamilynum][procindex-1] + qnonzcount/Tmk_nprocs;
	   if(remainder > 0) { /*B+6*/
	     (*qfence)[currentfamilynum][procindex]++;
	     remainder--;
	   } /*B+6*/
	 } /*B+5*/
       } /*B+4*/
     } /*B+3*/
   } /*B+2*/

   gMem->pprocbase[Tmk_proc_id] = 0;
   gMem->qprocbase[Tmk_proc_id] = 0;
   for(procindex=Tmk_proc_id,fenceindex = (Tmk_nprocs / (*slavesPerGroup));
       procindex < (Tmk_proc_id + (*slavesPerGroup));
       procindex++, fenceindex += (Tmk_nprocs / (*slavesPerGroup))){ /*B+2*/

/*   distribute q only if in onechildup or onechilddown since the p and
     q iterations are not nested in the onechild case
 */

     if((gMem->trav_flag[mymaster] == ONEUP) ||
	(gMem->trav_flag[mymaster] == ONEDOWN)) { /*B+3*/
       if (procindex > Tmk_proc_id)
         gMem->qprocbase[procindex] = gMem->qprocfence[procindex - 1];
       gMem->qprocfence[procindex] = (*qfence)[currentfamilynum][fenceindex - 1];
     } /*B+3*/
     else { /*B+3*/
       gMem->qprocbase[procindex] = 0;
       gMem->qprocfence[procindex] = qnonzcount;
     } /*B+3*/

     if (procindex > Tmk_proc_id)
       gMem->pprocbase[procindex] = gMem->pprocfence[procindex - 1];
     gMem->pprocfence[procindex] = (*rowfence)[currentfamilynum][fenceindex - 1];
   } /*B+2*/
   if((gMem->pprocfence[Tmk_proc_id] == gMem->pprocfence[Tmk_proc_id+*slavesPerGroup-1]) &&
      (gMem->qprocfence[Tmk_proc_id] == gMem->qprocfence[Tmk_proc_id+*slavesPerGroup-1]))
       onlymaster = 1;

   /* schaffer && cgh -- Added this loop here to zero out these arrays
      to fix bug.  In case with only one processor working on
      theta, even though others are available, *after* other processor
      has made changes too arr{p,q}sumcache arrays from *previous*
      iteration, these values were incorrectly added in the next time
      around. */
   if ((gMem->trav_flag[mymaster] == ONEUP) ||
       (gMem->trav_flag[mymaster] == ONEDOWN))
     for (j = mymaster; j< (mymaster + (*slavesPerGroup)); j++)
       for (i = 0; i < maxhaplo; i++) {
	 arrqsumcache[j][i] = 0.0;
	 arrpsumcache[j][i] = 0.0;
       }
   

   /*Make sure that all loop bounds are passed to all processors*/
   if ((*slavesPerGroup > 1) && (!onlymaster)) { /*B+2*/
#if BARRIER_OUTPUT
     printBarrier("(%d) Group barrier at middle of loadbalance\n",++barnum);
#endif /*BARRIER_OUTPUT*/
#if IS_SHMEM
     BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else /* !IS_SHMEM */
     Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif /* IS_SHMEM */
   } /*B+2*/
 
  switch(gMem->trav_flag[mymaster]) { /*B+2*/
    case ONEDOWN:
        onechilddown();
        break;
    case MANYDOWN:
        manychilddown();
        break;
    case ONEUP:
#if defined(LESSMEMORY)
	manychildup();
#else
        onechildup();
#endif
        break;
    case MANYUP:
        manychildup();
        break;
    default:
        printf("ERROR: unknown flag in child\n");
        exit(1);
        break;
      } /*B+2*/

   /* Print out times for each processor */
#if LOADBALANCE_OUTPUT
   if(Tmk_proc_id == 0)
     printout = 1;
#endif /* LOADBALANCE_OUTPUT */
   if (printout && !*firstfe) {
     printf("\n");
     for(procindex = 0; procindex < (*slavesPerGroup); procindex++) {
       if(procindex == 0)
	 j = 0;
       else
	 j = gMem->pprocfence[procindex-1];
       printf("Nuclear family %d: Processor %d: rowtime:\n",currentfamilynum, procindex);
       accumtime = 0;
       i = 0;
       for(; j < gMem->pprocfence[procindex]; j++) {
	 if (i == 0) {
	   printf("%.0f", rowtime[j]);
	   i = 1;
	 }
	 else
	   printf(" + %.0f", rowtime[j]);
	 accumtime += rowtime[j];
       }
       printf(" = %.0f\n",accumtime);
     }
     if((gMem->trav_flag[mymaster] == ONEUP) ||
	(gMem->trav_flag[mymaster] == ONEDOWN))
       for(procindex = 0; procindex < (*slavesPerGroup); procindex++) {
	 if(procindex == 0)
	   j = 0;
	 else
	   j = gMem->qprocfence[procindex-1];
	 printf("Nuclear family %d: Processor %d: qrowtime:\n",currentfamilynum, procindex);
	 accumtime = 0;
	 i = 0;
	 for(; j < gMem->qprocfence[procindex]; j++) {
	   if (i == 0) {
	     printf("%.0f", qrowtime[j]);
	     i = 1;
	   }
	   else
	     printf(" + %.0f", qrowtime[j]);
	   accumtime += qrowtime[j];
	 }
	 printf(" = %.0f\n",accumtime);
       }
   }

   if ((*secondfe)&&(currentthetanum == 0)) {
     for(procindex = Tmk_proc_id; 
	 procindex < (Tmk_proc_id+(*slavesPerGroup)); 
	 procindex++) /* Remove overhead */
       if((gMem->pprocfence[procindex] - gMem->pprocbase[procindex]) > 1)
	 rowtime[gMem->pprocbase[procindex]] = rowtime[gMem->pprocbase[procindex] + 1];
     if((gMem->trav_flag[mymaster] == ONEUP) ||
	(gMem->trav_flag[mymaster] == ONEDOWN))
       for(procindex = Tmk_proc_id;
	   procindex < (Tmk_proc_id+(*slavesPerGroup));
	   procindex++) /* Remove overhead */
	 if((gMem->qprocfence[procindex] - gMem->qprocbase[procindex]) > 1)
	   qrowtime[gMem->pprocbase[procindex]] =
	     qrowtime[gMem->pprocbase[procindex] + 1];
     totaltime = 0;              /* Try to balance work more evenly */
     for(i=0; i < pnonzcount; i++)
       totaltime += rowtime[i];
     if((gMem->trav_flag[mymaster] == ONEUP) ||
	(gMem->trav_flag[mymaster] == ONEDOWN))
       for(i=0; i < qnonzcount; i++)
	 totaltime += qrowtime[i];
     oh = 40000 + 10000 * (Tmk_nprocs - 2);
     if((Tmk_nprocs == 1) || 
	(totaltime < (oh*Tmk_nprocs/(Tmk_nprocs - 1))) || 
	((pnonzcount < (2*Tmk_nprocs)) && 
	 (!((gMem->trav_flag[mymaster] == ONEUP) 
	    || (gMem->trav_flag[mymaster] == ONEDOWN)) 
	  || (qnonzcount < (2*Tmk_nprocs))))) {
       /*    if(onlymaster) {*/
       for(procindex = 0; procindex < Tmk_nprocs; procindex++)
	 (*temprowfence)[currentfamilynum][procindex] = pnonzcount;
       if((gMem->trav_flag[mymaster] == ONEUP) ||
	  (gMem->trav_flag[mymaster] == ONEDOWN))
	 for(procindex = 0; procindex < Tmk_nprocs; procindex++)
	   (*tempqfence)[currentfamilynum][procindex] = qnonzcount;
     }
     else {
       totaltime = 0;              /* Try to balance work more evenly */
       for(i=0; i < pnonzcount; i++)
	 totaltime += rowtime[i];
       accumtime = 0;
       procindex = 0;
       for(i=0; i < pnonzcount; i++) {
	 accumtime += rowtime[i];
	 if(accumtime >= ((totaltime * (procindex + 1)) / Tmk_nprocs))
	   (*temprowfence)[currentfamilynum][procindex++] = i + 1;
       }
       /*    saveindex = procindex;*/
       for(; procindex < Tmk_nprocs; procindex++)
	 (*temprowfence)[currentfamilynum][procindex] = pnonzcount;
       /* In case the times for the last few rows is 0 */
       (*temprowfence)[currentfamilynum][Tmk_nprocs-1] = pnonzcount;
       if((gMem->trav_flag[mymaster] == ONEUP) ||
	  (gMem->trav_flag[mymaster] == ONEDOWN)) {
	 totaltime = 0;              /* Try to balance work more evenly */
	 for(i=0; i < qnonzcount; i++)
	   totaltime += qrowtime[i];
	 accumtime = 0;
	 procindex = 0;

	 for(i=0; i < qnonzcount; i++) {
	   accumtime += qrowtime[i];
	   if(accumtime >= ((totaltime * (procindex + 1)) / Tmk_nprocs))
	     (*tempqfence)[currentfamilynum][procindex++] = i + 1;
	 }
	 for(; procindex < Tmk_nprocs; procindex++)
	   (*tempqfence)[currentfamilynum][procindex] = qnonzcount;
	 /* In case the times for the last few rows is 0 */
	 (*tempqfence)[currentfamilynum][Tmk_nprocs-1] = qnonzcount;
       }
     }
   }
   if (gMem->trav_flag[mymaster] != MANYDOWN)
     onlymaster = 0;
}
   
/* segdown updates the genotype probabilities for a child  based
on the probabilities of parents and other children. The parameter LINK includes
all the genetic information about p, p's spouse q, and their
children */

void segdown(LINK)
struct LOC_seg *LINK;
{
  int  step1, step2; /*size of isozygote classes*/
  unsigned int here, i, j, first; /*genotype indices*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
						       p,q, and children*/
  thetavalues *WITH4; /*stores theta values for male parent*/
  thetavalues *WITH5; /*store theta values for female parent*/

  unsigned int c1, c2; /*haplotypes*/
  unsigned char *newflag2, *newflag3, *newflagr; /*store sparsity patterns for
					p and q genarrays*/

  int proc; /*processor number index*/

/* The arrays localpsumcache and localqsumcache store conditional probabilities of 
   different haplotypes being passed on from p and q respectively */
  double *localpsumcache, *localqsumcache;
  boolean depend;
  int loopprocbound;

  initseg(LINK); /*get data about this p,q,children triple*/

  gMem->trav_flag[mymaster] = MANYDOWN;

  /*get sparsity patterns for p, q, and child genarrays*/
  newflag2 = (*LINK->p)->gen->sparseflag; 
  newflag3 = (*LINK->q)->gen->sparseflag;
  newflagr = (*LINK->r)->gen->sparseflag;

  WITH2 = (*LINK->p)->gen; /*get genetic data for p*/
  WITH3 = (*LINK->q)->gen; /*get genetic data for q*/
  newwith2 = WITH2->genarray; /*get genarray for p*/
  newwith3 = WITH3->genarray; /*get genarray for q*/
  newwithr = (*LINK->r)->gen->genarray; /*get genarray for first child*/

  if ((!sexdif) || (!readfemale))
    WITH4 = WITH5 = maletheta;
  else {
    if (gMem->pmale[mymaster]) {
      WITH4 = maletheta; /*get male probabilities for p*/
      WITH5 = femaletheta; /*get female probabilities for q*/
    }
    else {
      WITH4 = femaletheta; /*get female probabilities for p*/
      WITH5 = maletheta; /*get male probabilities for q*/
    }
  }

/*The case of 1 child (nchild==0) is handled specially because the
subcomputations are much simpler. In particular we do not need to multiply the
probabilities among the different children. In a typical pedigree
many pairs will have only one child about which information is known
(in essence this is the child that keeps the pedigree connected), so
this is an important and common special case. */

if(nchild == 0) {

  gMem->trav_flag[mymaster] = ONEDOWN;

/*find nonzero entries in q's genarray and make a list of them
  stored in qnonzgens; just get one per isozygote class*/
  pnonzcount = qnonzcount = 0;

  if (*firstfe) {
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i++) {
      if(newflag3[i] != 0) {
        qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
      }
    }

    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i++) {
      if(newflag2[i] != 0) {
	pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
      }
    }
  }
  loadbalance(LINK);
  localqsumcache = arrqsumcache[mymaster];
  localpsumcache = arrpsumcache[mymaster];
  for(j=(mymaster + 1); j<(mymaster + (*slavesPerGroup));j++) {
    for (i = 0; i < maxhaplo; i++) {
      localqsumcache[i] += arrqsumcache[j][i];
      localpsumcache[i] += arrpsumcache[j][i];
    }
  }


 /*In this section of the code we update the probabilities for
  the child based on the probabilities for the parents*/  

 /*initialize gene array */
  for(i = 0; i < fgeno; i++) {
    gene[i] = 0.0;
  }
  
  /*Iterate over all joint genotypes of the child*/
  
  for(here = 0; here < fgeno; here++) {
    if(newflagr[here] == 0) continue;
    c1 = invgenenum1[here];
    c2 = invgenenum2[here];
    
    /*probability of child getting genotype here as a
      result of p passing on c1 and q passing on c2 is
      summed to gene[here] */
    
    gene[here] += localpsumcache[c1-1] * localqsumcache[c2-1];
    
    /*if c1 is distinct from c2 we need to do the same computation reversing
      the roles of the two haplotypes*/
    if(c1 != c2) {
      gene[here] += localpsumcache[c2-1] * localqsumcache[c1-1];
    }
  }
  
  /*set up new genarray for r; it is gene scaled by segscale*/      
  for (first = 0; first < fgeno; first++) {
    if(newflagr[first] == 0) continue;
    if(gene[first] == 0.0) newflagr[first] = 0;
    newwithr[first] *= segscale*gene[first];
  }

}

else  {  /*nchild is bigger than 0*/

/*find nonzero entries in p's genarray and make a list of them
  stored in pnonzgens; just get one per isozygote class*/
  qnonzcount = pnonzcount = 0;

  if (*firstfe) {
    /*iterate over genotypes for p*/
    for(i = 0; i < fgeno; i += step1) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step1 = probend[i] - probstart[i] + 1; 
      for(j = i; j < i+step1; j++)
	if(newflag2[j] != 0) {
	  pnonzgens[pnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }

    /*find nonzero entries in q's genarray and make a list of them
      stored in qnonzgens; just get one per isozygote class*/
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i += step2) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step2 = probend[i] - probstart[i] + 1; 
      for(j = i; j < i+step2; j++)
	if(newflag3[j] != 0) {
	  qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }
  }

  loadbalance(LINK);
  if (onlymaster)
    loopprocbound = mymaster +1;
  else
    loopprocbound = mymaster + (*slavesPerGroup);
  /*sum up different contributions to gene*/
  for(i=0; i < fgeno; i++){
    if(newflagr[i] == 0) continue;
    else {
      gene[i] = 0.0;
      for(proc=mymaster; proc < loopprocbound; proc++)
        gene[i] += arrgene[proc][i];
        
    }
  }
  onlymaster =0;

  /*finally update child's real genarray by copying gene multiplied
    by scale factor segscale*/
  for(i = 0; i < fgeno; i++) {
    if(newflagr[i] == 0) continue;
    if(gene[i] == 0.0) newflagr[i] = 0; /*if probability changes from nonzero
					  to 0.0 change flag to 0*/
    newwithr[i] *= segscale * gene[i];
  }
}

 /*Added by A. A. Schaffer to handle loops */
   if (loopfirstgen && (!((*LINK->r)->loopdepend))) {
     depend = false;
     for(i=0; i<nchild; i++)
       if (childarray[i]->loopdepend) {
         depend = true;
         break;
       }
     depend = (depend || ((*LINK->p)->loopdepend) || ((*LINK->q)->loopdepend));
     if (depend) {
      (*LINK->r)->loopdepend = depend;
      (*LINK->r)->loopneeded = false;
     }
   }
   if ((*LINK->r)->loopdepend) {
     if (!((*LINK->p)->loopdepend))
       (*LINK->p)->loopneeded = true;
     if (!((*LINK->q)->loopdepend))
       (*LINK->q)->loopneeded = true;
     for(i=0; i< nchild; i++)
       if (!(childarray[i]->loopdepend))
         childarray[i]->loopneeded = true;
   }
  cleanup(LINK->p, LINK->LINK);
  cleanup(LINK->q, LINK->LINK);
  exitseg(LINK);
}  /*segdown*/

/*onechilddown handles the case up updating a child from both
parents, when there is just one child */
void onechilddown()
{
  int  FORLIM; /*loop bound*/
  int pnonzindex, qnonzindex; /*loop indices for nonzero values*/
  double valtemp; /*intermediate values in probability updates*/
  double val; /*temporaries to store intermediate values*/
  unsigned int f1, f2; /*two haplotypes from parents*/
  unsigned int i, j, first; /*genotype indices*/
  int procindex;
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
						       p,q, and children*/
  thetavalues *WITH4; /*stores theta values for male parent*/
  thetavalues *WITH5; /*store theta values for female parent*/
  unsigned char *newflag2, *newflag3, *newflagr; /*store sparsity patterns for
					p and q genarrays*/


  /* newsegprob is  used to hold segprob
    arrays, which contains the probabilities for various patterns of
    recombination events*/
  double *newsegprob; 
  int ind;      /*used to store offset for probability array*/

  /* Structures to store start and end time for rows */
  struct timeval starttime, endtime;

/* The arrays localpsumcache and localqsumcache 
   store conditional probabilities of 
   different haplotypes being passed on from p and q respectively */
  double *localpsumcache, *localqsumcache;
  int pbase, pfence, qbase, qfence; /*bounds for  p and q genotypes for this
                                      processor to work on*/
  pbase = gMem->pprocbase[Tmk_proc_id];
  pfence = gMem->pprocfence[Tmk_proc_id];
  qbase = gMem->qprocbase[Tmk_proc_id];
  qfence = gMem->qprocfence[Tmk_proc_id];
  nchild = gMem->nchild[mymaster];

  /*get sparsity patterns for p, q, and child genarrays*/
  newflag2 = gMem->pgenptr[mymaster]->sparseflag;
  newflag3 = gMem->qgenptr[mymaster]->sparseflag;
  newflagr = gMem->rgenptr[mymaster]->sparseflag;

  WITH2 = gMem->pgenptr[mymaster]; /*get genetic data for p*/
  WITH3 = gMem->qgenptr[mymaster]; /*get genetic data for q*/
  newwithr = gMem->rgenptr[mymaster]->genarray; /*get genarray for first child*/

  newwith2 = WITH2->genarray; /*get genarray for p*/
  newwith3 = WITH3->genarray; /*get genarray for q*/

  if ((!sexdif) || (!readfemale))
    WITH4 = WITH5 = maletheta;
  else {
    if (gMem->pmale[mymaster]) {
      WITH4 = maletheta; /*get male probabilities for p*/
      WITH5 = femaletheta; /*get female probabilities for q*/
    }
    else {
      WITH4 = femaletheta; /*get female probabilities for p*/
      WITH5 = maletheta; /*get male probabilities for q*/
    }
  }

  localpsumcache = arrpsumcache[Tmk_proc_id];
  localqsumcache = arrqsumcache[Tmk_proc_id];

/*initialize cache data structures*/
  for(i = 0;i < maxhaplo;i++) {
    flag[i] = 0;
    localpsumcache[i] = 0.0;
    localqsumcache[i] = 0.0;
  }

/*set up flag array*/
  for(i = 0; i < fgeno; i++) {
    if(newwithr[i] == 0.0) continue;
    flag[invgenenum1[i]-1] = 1;
    flag[invgenenum2[i]-1] = 1;
  }

  if(!*firstfe) {
    /*find nonzero entries in q's genarray and make a list of them
      stored in qnonzgens; just get one per isozygote class*/
    /*iterate over genotypes for q*/
    qnonzgens = privateqnonzgens;
    qnonzcount = 0;

    for(i = 0; i < fgeno; i++) {
      if(newwith3[i] != 0.0) {
        qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
      }
    }

    pnonzgens = privatepnonzgens;
    pnonzcount = 0;
    /*iterate over genotypes for p*/
    for (i = 0; i < fgeno; i++) {
      if(newwith2[i] != 0.0) {
	pnonzgens[pnonzcount++] = i; /* store index of nonzero value */
      }
    }
    /*stripe pnonzgens array*/
    if (!onlymaster) {
      j = 0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < pnonzcount; i+=Tmk_nprocs)
	  stripe_pnonzgens[j++]=pnonzgens[i];
      }
      for(i = 0; i < pnonzcount; i++)
	pnonzgens[i] = stripe_pnonzgens[i];

      /*stripe qnonzgens array*/
      j =0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < qnonzcount; i+=Tmk_nprocs)
	  stripe_qnonzgens[j++]=qnonzgens[i];
      }
      for(i = 0; i < qnonzcount; i++)
	qnonzgens[i] = stripe_qnonzgens[i];
    }
  }
  else {
    pnonzgens = gpnonzgens[currentthetanum];
    qnonzgens = gqnonzgens[currentthetanum];
  }

  /*This section of the code precomputes for each haplotype the the probability
  that the child will inherit this haplotype from p. Each genotype has
  two haplotypes, but can produce others by recombination. Therefore,
  for each genotype we must sum over the different haplotypes that can
  be produced by its isozygote class. The contributions for each haplotype
  are stored in localpsumcache.
  Afterwards a similar computation is done for the inheritance from q
  with the results stored in localqsumcache.*/


  newsegprob = WITH4->segprob; /*get p probabilities for recomb. patterns*/
  for (pnonzindex = pbase; pnonzindex < pfence; pnonzindex++) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else /* !LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0))
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&starttime, NULL);  /* Get start time */

    first = pnonzgens[pnonzindex];
    FORLIM = fence[first]; /*find end of isozygote class of first*/
    valtemp = newwith2[first]; /*probability of getting this genotype*/

  /*iterate over all members of first's isozygote calss*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i]; /*get haplotypes*/
      f2 = haps2[i];
      if ((flag[f1-1] !=0) || (flag[f2-1] != 0)) {
         ind = hind[i];  /*get probability offset for i*/
       /*multiply probability of getting genotype times
	 probability of this recombination pattern and haplo. choice*/
         val = valtemp * newsegprob[ind];

       /*add to psumcache*/
         if(flag[f1-1] != 0) {
	   localpsumcache[f1-1] += val;
          }
 
         if(flag[f2-1] != 0) {
	   localpsumcache[f2-1] += val;
         }
       }
    }

#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else /* ! LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0)) {
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&endtime, NULL);  /* Get end time */
      rowtime[pnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                          + (endtime.tv_usec - starttime.tv_usec);
    }
  }

  newsegprob = WITH5->segprob; /*get q probabilities*/

 /*iterate over all joint genotypes*/
  for (qnonzindex = qbase; qnonzindex < qfence; qnonzindex++) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else /* ! LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0))
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&starttime, NULL);  /* Get start time */
    first = qnonzgens[qnonzindex];
    valtemp = newwith3[first]; /*get cond. prob. that q has genotype first*/
    FORLIM = fence[first]; /*find bounds for the isozygote class of first*/

 /*iterate over all the recombined genotypes of the isozygote class*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i];
      f2 = haps2[i];

      if((flag[f1-1] !=0) || (flag[f2-1] !=0)) {

/*condition probability of first as a genotype multiplied by probability
  of passing on f1 (alternatively f2) as a haplotype*/
        ind = hind[i];  /*get probability offset for i*/
        val = valtemp*newsegprob[hind[i]];
     /*store in qsumcache*/
        if(flag[f1-1] != 0) {
	  localqsumcache[f1 - 1] += val;
        }
        if(flag[f2-1] != 0) {
	  localqsumcache[f2 - 1] += val;
        }
      }
    }
#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else /* !LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0)) {
#endif /*LOADBALANCE_OUTPUT */
      gettimeofday(&endtime, NULL);  /* Get end time */
      qrowtime[qnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                           + (endtime.tv_usec - starttime.tv_usec);
    }
  }
  if (((*slavesPerGroup) > 1)&&(!onlymaster)) {
#if BARRIER_OUTPUT
    printBarrier("(%d) Group barrier at end of onechilddown\n", ++barnum);
#endif /* BARRIER_OUTPUT */
#if IS_SHMEM
    BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else /* !IS_SHMEM */
    Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif /* IS_SHMEM */
  }
}

/* segdown updates the genotype probabilities for a child based on the
probabilities of parents and other children. The parameter LINK
includes all the genetic information about p, p's spouse q, and their
children manychilddown handles the case when p and q have more than
one child (nchild > 0) */

void manychilddown()
{

  int pbase, pfence, qbase, qfence; /*bounds for  p and q genotypes for this
                                      processor to work on*/
#if !PRECOMPUTE
  int findex, sindex;
#endif
  int pnonzindex, qnonzindex; /*loop index  for nonzero values*/
  int  step1, step2; /*size of isozygote classes*/
  unsigned int *tempstart; /*temporary index to probability array*/
  double val, temp1; /*temporaries to store intermediate values*/
  unsigned int i, j, first, second; /*genotype indices*/
  int procindex;
  unsigned int fslength; /*number of probs. for product isoz. class of p,q*/
  int jointisoindex, fisoindex; /*indices to work within isozygote classes*/
  unsigned currentindex; /*index to update genarray within isozygote class*/
  unsigned l; /*increment used to manage offset into probtableindex
                l is the number of probability values needed for the current
		isozygote class. This is obtained by multplying the
		number of probabilities (maxneed) times the size of the
		class*/
  unsigned k; /*index to loop over children*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr, *newwithc; /*store genarrays for
						       p,q, and children*/
  
#if !PRECOMPUTE  /* cgh - gcc */
  double* newsegr;   /* store genarrays for p,q, and children */
#endif  /* !PRECOMPUTE */

  thetavalues *WITH4; /*stores theta values for p parent*/
  thetavalues *WITH5; /*store theta values for q parent*/
  unsigned char *newflag2, *newflag3, *newflagr; /*store sparsity patterns for
					p and q genarrays*/
  double *localgene;

  /* newsegprob1, and newsegprob2 are  used to hold segprob
    arrays, which contain the probabilities for various patterns of
    recombination events*/
  double *newsegprob1, *newsegprob2; 
  double *tempprob; /*temporary holder for probability array*/

  /* Structures to store start and end time for rows */
  struct timeval starttime, endtime;


  pbase = gMem->pprocbase[Tmk_proc_id];
  pfence = gMem->pprocfence[Tmk_proc_id];
  qbase = gMem->qprocbase[Tmk_proc_id];
  qfence = gMem->qprocfence[Tmk_proc_id];
  nchild = gMem->nchild[mymaster];
  /*get sparsity patterns for p, q, and child genarrays*/
  WITH2 = gMem->pgenptr[mymaster]; /*get genetic data for p*/
  WITH3 = gMem->qgenptr[mymaster]; /*get genetic data for q*/
  newflag2 = gMem->pgenptr[mymaster]->sparseflag; 
  newflag3 = gMem->qgenptr[mymaster]->sparseflag;
  newflagr = gMem->rgenptr[mymaster]->sparseflag;

  newwith2 = WITH2->genarray; /*get genarray for p*/
  newwith3 = WITH3->genarray; /*get genarray for q*/
  newwithr = gMem->rgenptr[mymaster]->genarray; /*get genarray for first child*/

  if ((!sexdif) || (!readfemale))
    WITH4 = WITH5 = maletheta;
  else {
    if (gMem->pmale[mymaster]) {
      WITH4 = maletheta; /*get male probabilities for p*/
      WITH5 = femaletheta; /*get female probabilities for q*/
    }
    else {
      WITH4 = femaletheta; /*get female probabilities for p*/
      WITH5 = maletheta; /*get male probabilities for q*/
    }
  }

  newsegprob1 = WITH4->segprob; /*get p probabilities*/
  newsegprob2 = WITH5->segprob; /*get q probabilties*/

 /*initialize genarray entries for child to 0*/
/*  if(onlymaster)
    for(i = 0; i < fgeno; i++) {
      if(newflagr[i] == 0) continue;
      for(j=(Tmk_proc_id+1);j<(Tmk_proc_id+*slavesPerGroup);j++)
        arrgene[j][i] = 0.0;
    }*/
  for(i = 0; i < fgeno; i++) {
    arrgene[Tmk_proc_id][i] = 0.0;
  }

  localgene = arrgene[Tmk_proc_id];

  if(!*firstfe) {
    /*find nonzero entries in p's genarray and make a list of them
      stored in pnonzgens; just get one per isozygote class*/
    pnonzgens = privatepnonzgens;
    pnonzcount = 0;

    /*iterate over genotypes for p*/
    for(i = 0; i < fgeno; i += step1) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step1 = probend[i] - probstart[i] + 1; 
      for(j = i; j < i+step1; j++)
	if(newflag2[j] != 0) {
	  pnonzgens[pnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }

    /*find nonzero entries in q's genarray and make a list of them
      stored in qnonzgens; just get one per isozygote class*/
    qnonzgens = privateqnonzgens;
    qnonzcount = 0;
    
    /*iterate over genotypes for q*/
    for(i = 0; i < fgeno; i += step2) {
      /*number of distinct probabilties needed for i's isoz. class*/
      step2 = probend[i] - probstart[i] + 1; 
      for(j = i; j < i+step2; j++)
	if(newflag3[j] != 0) {
	  qnonzgens[qnonzcount++] = i; /*store index of nonzero value*/
	  break;                        /*go to next isozygote class*/
	}
    }
    qfence = qnonzcount;   /* Set qfence to correct value */
    
    /*stripe pnonzgens array*/
    if (!onlymaster) {
      j = 0;
      for(procindex = 0; procindex < Tmk_nprocs; procindex++){
	for(i = procindex; i < pnonzcount; i+=Tmk_nprocs)
	  stripe_pnonzgens[j++]=pnonzgens[i];
      }
      for(i = 0; i < pnonzcount; i++)
	pnonzgens[i] = stripe_pnonzgens[i];
    }
  }
  else {
    pnonzgens = gpnonzgens[currentthetanum];
    qnonzgens = gqnonzgens[currentthetanum];
  }


  /*iterate over genotypes for p*/
  for (pnonzindex = pbase; pnonzindex < pfence; pnonzindex++) {
#if LOADBALANCE_OUTPUT
    if(mymaster == 0)
#else /* !LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0))
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&starttime, NULL);  /* Get start time */

    first = pnonzgens[pnonzindex];
    step1 = probend[first] - probstart[first]+1; 

    /*iterate over the genotypes representing isozygote classes that
     q may have*/
    for (qnonzindex = qbase; qnonzindex < qfence; qnonzindex++) {
      second = qnonzgens[qnonzindex];
      /*check if this first, second pair yield a nonzero value
        among children's probabilities*/
      if(lsegfun2(first,second) == 0) continue;

      /*number of distinct probabilties needed for second's isoz. class*/
      step2 = probend[second] - probstart[second] + 1; 
      fslength = step1 * step2; /*number of probs. of combined isozygote class*/
#if PRECOMPUTE
      fisoindex = (probstart[first] - 1) * nuneed - 1; /*probability array offset*/
#endif
      tempstart = probstart + second; /*set tempstart to the start of
					the section of probstart that
					we want*/
      l = step1 * nuneed; /*number of probabilities for this
			     isozygote class*/
  
   /*call segsumdown2 to compute the part of the conditional probability
     update that is common to all the members of the combined isozygote
     class defined by first and second */

      segsumdown2(first,second,fslength);

      for(jointisoindex = 0; jointisoindex < fslength; jointisoindex++)
	segval[jointisoindex] = 0.0;
#if !PRECOMPUTE
      newsegr = tempseg2;
      tempprob = tempseg;
      for (k = 0;k < nchild; k++) {
        for(i = 0; i < step1; i++) {
          newwithr = tempprob;
          findex = probstart[first + i] - 1;
          temp1 = newsegprob1[findex];
          for (sindex = 0; sindex < step2; sindex++)
            newsegr[sindex] = temp1*(*newwithr++);
          for(findex++; findex < probend[first + i]; findex++) {
            temp1 = newsegprob1[findex];
            for(sindex = 0; sindex < step2; sindex++)
              newsegr[sindex] += temp1*(*newwithr++);
          }
          newsegr += step2;
        }
        tempprob += fslength;
      }
#endif

      /*now specialize update for each member of first's class*/
      for(i = 0; i < step1; i++) {
	if(newflag2[first+i] == 0) {
#if PRECOMPUTE
	  fisoindex += l; /*increment by number of probabilities
			   needed for this iso. class*/
#endif
	  continue; /*skip if this isozygote is not possible*/
	}
        /*further specialize update for each member of second's isozygote
          class*/
	for(j = 0; j < step2; j++) {
        /*skip if this isozygote not possible*/
	  if(newflag3[second+j] == 0) {
	    continue; 
	  }

          /*get offset into probtable; the offset depends on
            the isozygote class size and index of each parent
            note that fisozygoteindex gets incremented by the size
            of the joint class each time, so it represents a
            sum of all the numbers of distinct probabilities
            needed for all joint iso. classes  considered before the
            current p isozygote class*/

#if PRECOMPUTE
#if AUTOSOMAL_RUN
	  if ((!sexdif) || (gMem->pmale[mymaster]))
	    tempprob = probtable[mymaster] + probtableindex[mymaster][fisoindex+tempstart[j]];
#if SEXDIF_RUN
          else
	    tempprob = probtabledif[mymaster] + probtableindex[mymaster][fisoindex+tempstart[j]];
#endif /*SEXDIF_RUN*/
#endif /*AUTOSOMAL_RUN*/
#endif /*PRECOMPUTE*/
        /*combine for all children*/
        /*due to the arrangement in segsum all the probability contributions
          for a given child are contiguous in the newwithr array.
          the number of contributions is fslength which is the number of
          probabilties needed for the joint isozygote class for the parents.
          We get the contribution of the first child (index 0) and
          then loop over the rest*/
#if PRECOMPUTE
	  val = tempprob[0] * tempseg[0];
         /*iterate over joint isozygote class*/
	  for(jointisoindex = 1; jointisoindex < fslength; jointisoindex++)
	    val += tempprob[jointisoindex] * tempseg[jointisoindex];
	  newwithc = tempseg + fslength; /*move the base of newwithc*/
#else
         val = 1.0;
         newwithc = tempseg2 + i * step2;
         tempprob = newsegprob2 + probstart[second+j] - 1;
#endif
         /*iterate over all the remaining children; notice that the
           loop index k is not used inside the loop. this is because the
           last loop statement which moves the offset of newwithc
           has the effect of incrementing the child*/
#if PRECOMPUTE
	  for(k = 1; k < nchild; k++) {
	    temp1 = tempprob[0] * newwithc[0];
	    for(jointisoindex = 1; jointisoindex < fslength; jointisoindex++)
	      temp1 += tempprob[jointisoindex] * newwithc[jointisoindex];
#else
          for(k = 0; k < nchild; k++) {
            temp1 = 0.0;
            for(sindex = 0; sindex < step2; sindex++)
              temp1 += tempprob[sindex] * newwithc[sindex];
#endif
	    val *= temp1;
	    newwithc += fslength;
	  }
          /*probability of this combination of parent genotypes*/
	  val *= newwith2[first+i] * newwith3[second+j];
#if PRECOMPUTE
	  for(jointisoindex = 0; jointisoindex < fslength; jointisoindex++) {
          /*probability of this recombination pattern (based on other children)*/
	    segval[jointisoindex] += tempprob[jointisoindex] * val;
	  }
#else
          jointisoindex = 0;
          for(findex = probstart[first+i]-1; findex < probend[first+i]; findex++)
            for(sindex = probstart[second + j]-1; sindex < probend[second + j]; sindex++)
              segval[jointisoindex++] +=newsegprob1[findex] * newsegprob2[sindex] * val;
#endif
	}
#if PRECOMPUTE
	fisoindex += l; /*go to next isozygote for p*/
#endif
      }
      /*update the probabilities of four joint genotypes the
       child might get; each different choice of recombination
       pattern will lead to a different set of four genotypes*/
      currentindex = 0;
      for(jointisoindex = 0; jointisoindex < fslength; jointisoindex++) {
	temp1 = segval[jointisoindex];
	localgene[segindex[currentindex++]-1] += temp1;
	localgene[segindex[currentindex++]-1] += temp1;
	localgene[segindex[currentindex++]-1] += temp1;
	localgene[segindex[currentindex++]-1] += temp1;
      }
    }
#if LOADBALANCE_OUTPUT
    if(mymaster == 0) {
#else /* !LOADBALANCE_OUTPUT */
    if((*secondfe)&&(mymaster == 0)) {
#endif /* LOADBALANCE_OUTPUT */
      gettimeofday(&endtime, NULL);  /* Get end time */
      rowtime[pnonzindex] = 1000000*(endtime.tv_sec - starttime.tv_sec)
                          + (endtime.tv_usec - starttime.tv_usec);
    }
  }
  if (((*slavesPerGroup) > 1)&&(!onlymaster)) {
#if BARRIER_OUTPUT
    printBarrier("(%d) Group barrier at end of manychilddown\n", ++barnum);
#endif /* BARRIER_OUTPUT */
#if IS_SHMEM
    BARRIER(partial_barrier[mymaster]->barrier,*slavesPerGroup);
#else /* !IS_SHMEM */
    Tmk_barrier(MakeMask(mymaster,mymaster+(*slavesPerGroup)-1));
#endif /* IS_SHMEM */
  }
}  /*manychilddown*/


unsigned lsegsexfun2(first,second,LINK)
int first, second;
struct LOC_seg *LINK;
{
  int g1, g2; /*four gene numbers*/
  int j, k; /* loop indices*/
  int s1, s2; /*haplotype numbers*/
  int FORLIM1, FORLIM2; /*loop bounds*/
  int *TEMPGENE1; /* store pointers into genenumber*/
  unsigned char *tempflag3; /*stores sparsity pattern for child's genarray*/

  FORLIM1 = base[second];/*find beginning and end of isozygote class
			   for second*/
  FORLIM2 = fence[second];
  TEMPGENE1 = genenumber[first];/*get pointer into genenumber for
					 this haplotype*/
  /*try to find a non-zero value for each child*/
  for (k = 0; k < nchild; k++) {

    /*retrieve sparsity pattern for child k*/
    tempflag3 = thischild[k]->sparseflag;
  
    /*iterate over all the recombined isozygotes of second*/
    for (j = FORLIM1; j < FORLIM2; j++) {
      s1 = haps1[j]; /*get haplotypes of this genotype*/
      s2 = haps2[j];
      
      if(malechild[k]) {
	if(tempflag3[s1 - 1] != 0 || tempflag3[s2 - 1] != 0)
	  goto notzero;
	else
	  continue;
      }
      g1 = TEMPGENE1[s1 - 1];
      g2 = TEMPGENE1[s2 - 1];
      
      /*if any of the flags is TRUE, then this child can have this genotype,
	and we move immediately to testing the next child*/
      if(tempflag3[g1 - 1] != 0 || tempflag3[g2 - 1] != 0) goto notzero;
    }
    return 0; /*this child failed to have any of the genotypes for
		the isozygote class, so this isozygote class is not possible*/
  notzero:
    continue;
  }
  return 1; /*all children passed the test and have a possible joint genotype*/
}

/* segsexsum2 is used in segsexup to compute some common subexpressions in
the probability updates.
first and second are the joint genotypes of the two parents.
fslength is the number of probabilities needed for the combined
isozygote class of both parental genotypes; fs stands for the product
of first and second. LINK is used to pass the genetic information for
parents and children */

/* cgh -- made void for gcc */

Local void segsexsum2(first,second,fslength,LINK)
int first, second, fslength;
struct LOC_seg *LINK;
{
  int g1, g2; /*indices to store gene numbers*/
  int f1, s1, s2; /*indices to store haplotype numbers*/
  int indey; /*counter for combined isozygote equivalence class,
                will range from 0 to fslength-1*/
  int i, j, k, l; /*loop indices*/
  int FORLIM1, FORLIM2; /*lower and upper limits on a for loop*/
  int *TEMPGENE1; /*temporary pointers into genenumber table*/
  double *tempwith3; /*temporarily stores genarray for current child*/

  FORLIM1 = base[second]; /*start of the isozygote class for second*/
  FORLIM2 = fence[second]; /*end of the isozygote class for second*/
  indey = 0; /*start with first isozygote in the class*/
  
  i = base[first];
  f1 = haps1[i]; /*retrieve first haplotype of joint genotype i*/
  TEMPGENE1 = genenumber[f1 - 1]; /*lookup partial information
					    in genenumber table*/
  /*iterate over isozygotes of j*/
  for (j = FORLIM1; j < FORLIM2; j++) {
    s1 = haps1[j]; /*retrieve first haplotype of joint genotype j*/
    s2 = haps2[j]; /*retrieve second haplotype*/
   /*lookup the four ways to combine one haplotype from i and one from j*/
    g1 = TEMPGENE1[s1 - 1];
    g2 = TEMPGENE1[s2 - 1];

    /*iterate over children; update partial computations of
      new probabilities and store in array tempseg
      note that tempseg has nchild*fslength relevant entries
      The fslength entries for child 1 come first, then
      the fslength entries, for child 2, etc. This is why
      the increment on l is fslength for each change of child*/

      for (l = indey, k = 0 ; k < nchild; l += fslength, k++) {
	tempwith3 = thischild[k]->genarray; /*retrieve genarray*/

       /* sum the probabilities for the four joint genotypes that
        the child can get from the current parental joint genotypes*/

	if(malechild[k])
	  tempseg[l] = (tempwith3[s1 - 1] + tempwith3[s2 - 1]);
	else
	  tempseg[l] = (tempwith3[g1 - 1] + tempwith3[g2 - 1]);
      }
      indey++; /*increment isozygote class counter*/
    }
}

/*segsexsumdown2 is used in segdown to compute some common subexpressions in
the probability updates.
first and second are the joint genotypes of the two parents.
fslength is the number of probabilities needed for the combined
isozygote class for both parental genotypes; fs stands for the
product of first and second. LINK is used to pass the genetic information for
parents and children */

/* cgh -- void for gcc */

Local void segsexsumdown2(first,second,fslength,male,LINK)
int first, second, fslength, male;
struct LOC_seg *LINK;
{
  int g1, g2; /*indices to store gene numbers*/
  int f1, s1, s2; /*indices to store haplotype numbers*/
  int indey; /*counter for combined isozygote equivalence class,
                will range from 0 to fslength-1*/
  int index2; /*used as index for isozygote class*/
  int i, j, k, l; /*loop indices*/
  int FORLIM1, FORLIM2; /*lower and upper limits on a for loop*/
  int *TEMPGENE1; /*temporary pointers into genenumber table*/
  double *tempwith3; /*temporarily stores genarray for current child*/

  FORLIM1 = base[second]; /*start of the isozygote class for second*/
  FORLIM2 = fence[second]; /*end of the isozygote class for second*/
  indey = 0; /*start with first isozygote in the class*/
  index2 = 0;
  /*iterate over isozygotes of i*/
  i = base[first];
  f1 = haps1[i]; /*retrieve first haplotype of joint genotype i*/
  TEMPGENE1 = genenumber[f1 - 1]; /*lookup partial information
					    in genenumber table*/
  /*iterate over isozygotes of j*/
  for (j = FORLIM1; j < FORLIM2; j++) {
    s1 = haps1[j]; /*retrieve first haplotype of joint genotype j*/
    s2 = haps2[j]; /*retrieve second haplotype*/
    /*lookup the four ways to combine one haplotype from i and one from j*/
    g1 = TEMPGENE1[s1 - 1];
    g2 = TEMPGENE1[s2 - 1];
    /*store these gene numbers for later use; the
      key point is that we will want these numbers
      consecutively later, so we store them consecutively
      in segindex*/
    if(male) {
      segindex[index2++] = s1;
      segindex[index2++] = s2;
    }
    else {
      segindex[index2++] = g1;
      segindex[index2++] = g2;
    }

    /*iterate over children; update partial computations of
      new probabilities and store in array tempseg
      note that tempseg has nchild*fslength relevant entries
      The fslength entries for child 1 come first, then
      the fslength entries, for child 2, etc. This is why
      the increment on l is fslength for each change of child*/

      for (l = indey, k = 0 ; k < nchild; l += fslength, k++) {
	tempwith3 = thischild[k]->genarray; /*retrieve genarray*/

       /* sum the probabilities for the four joint genotypes that
        the child can get from the current parental joint genotypes*/

	if(malechild[k])
	  tempseg[l] = (tempwith3[s1 - 1] + tempwith3[s2 - 1]);
	else
	  tempseg[l] = (tempwith3[g1 - 1] + tempwith3[g2 - 1]);
      }
      indey++; /*increment isozygote class counter*/
    }
}

/*segsexup updates the genotype probabilities for a parent (p) based
on the probabilities of children. The parameter LINK includes
all the genetic information about p, p's spouse q, and their
children*/

void segsexup(LINK)
struct LOC_seg *LINK;
{
  int  FORLIM; /*loop bound*/
  int nonzindex, nonzcount;    /*loop index and counter for nonzero values*/
  int  step1, step2; /*size of isozygote classes*/
  double valtemp; /*intermediate values in probability updates*/
  double val, temp1, tempr; /*temporaries to store intermediate values*/
  unsigned int f1, f2; /*four haplotypes from parents*/
  unsigned int here, i, j, first, second; /*genotype indices*/
  int jointisoindex; /*indices to work within isozygote classes*/
  unsigned k; /*index to loop over children*/
  unsigned char skip; /*used to skip iterations of a loop*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr; /*store genarrays for
						       p,q, and children*/

  unsigned int c1, c2; /*haplotypes*/
  unsigned char *newflag2, *newflag3, *newflagr; /*store sparsity patterns for
					p and q genarrays*/

  static unsigned current;
  /* newsegprob, newsegprob1, and newsegprob2 are  used to hold segprob
    arrays, which contain the probabilities for various patterns of
    recombination events*/
  double *newsegprob, *newsegprob2; 
  double *tempprob; /*temporary holder for probability array*/
  int ind;      /*used to store offset for probability array*/

  initseg(LINK); /*get data about this p,q,children triple*/

  /*clear out pools, debugging
  for(i=0; i<= current; i++){
    indpool[i]=0;
    invpool[i]=0;
    nextpool[i]=0;
  } */
  /*get sparsity patterns for p and q genarrays*/
  newflag2 = (*LINK->p)->gen->sparseflag; 
  newflag3 = (*LINK->q)->gen->sparseflag;

  WITH2 = (*LINK->p)->gen; /*get genetic data for p*/
  WITH3 = (*LINK->q)->gen; /*get genetic data for q*/
  newwith2=WITH2->genarray; /*get genarray for p*/
  newwith3=WITH3->genarray; /*get genarray for q*/
  newwithr=thischild[0]->genarray; /*get genarray for first child*/

  if((*LINK->p)->male) {
/*The case of 1 child is handled specially because the subcomputations
are much simpler. In particular we do not need to multiply the
probabilities among the different children. In a typical pedigree
many pairs will have only one child about which information is known
(in essence this is the child that keeps the pedigree connected), so
this is an important and common special case. */

if(nchild == 1) {
/*initialize cache data structures*/
  for(i=0;i<maxhaplo;i++) {
    flag[i] = 0;
    phapcache1[i].first = 0;
    qsumcache[i] = 0.0;
  }

/*initialize gene array and set up flag array*/
  if(malechild[0]) {
    for(i = 0; i < mgeno; i++) {
      gene[i] = 0.0;
      if(newwithr[i] == 0.0) continue;
      flag[i] = 1;
    }
  }
  else {
    for(i = 0; i < fgeno; i++) {
      gene[i] = 0.0;
      if(newwithr[i] == 0.0) continue;
      flag[invgenenum1[i]-1] = 1;
      flag[invgenenum2[i]-1] = 1;
    }
  }

  /*This section of the code precomputes for each haplotype the the probability
  that the child will inherit this haplotype from q. Each genotype has
  two haplotypes, but can produce others by recombination. Therefore,
  for each genotype we must sum over the different haplotypes that can
  be produced by its isozygote class. The contributions for each haplotype
  are stored in qsumcache.*/

  newsegprob = femaletheta->segprob; /*use female probabilities to work with q*/

 /*iterate over all joint genotypes*/
  for (first = 0; first < fgeno; first++ ) {
    if(newflag3[first] == 0) continue; /*check if joint genotype is possible*/
    valtemp = newwith3[first]; /*get cond. prob. that q has genotype first*/
    FORLIM = fence[first]; /*find bounds for the isozygote class of first*/

 /*iterate over all the recombined genotypes of the isozygote class*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i];
      f2 = haps2[i];
      if((flag[f1-1] != 0) || (flag[f2-1] != 0)) {
/*conditional probability of first as a genotype multiplied by probability
  of passing on f1 (alternatively f2) as a haplotype*/
        val = valtemp*newsegprob[hind[i]];

       /*store in qsumcache*/
        if(flag[f1-1] != 0) {
	  qsumcache[f1 - 1] += val;
        }
        if(flag[f2-1] != 0) {
	  qsumcache[f2 - 1] += val;
        }
      }
    }
  }


 /*In this section of the code we update the probabilities for
  the parent p based on the probabilities for the child*/  
 /*Iterate over all joint genotypes of the child*/
  if(malechild[0]) {
  newflagr=thischild[0]->sparseflag;
  temp1 = 0.0;
  for(here = 0; here < mgeno; here++) {
    if(newflagr[here] == 0) continue;
    tempr = newwithr[here];
    temp1 = tempr * qsumcache[here]; 
  }

  for(here = 0; here < mgeno; here++)
    gene[here] = temp1;
  }
  else {
  newflagr=thischild[0]->sparseflag;
  for(here = 0; here < fgeno; here++) {
    if(newflagr[here] == 0) continue;
    tempr = newwithr[here];
    c1 = invgenenum1[here];
    c2 = invgenenum2[here];
    gene[c1 - 1] += tempr * qsumcache[c2 - 1];
    if(c1 != c2)
      gene[c2 - 1] += tempr * qsumcache[c1 - 1];
  }
  }

/*set up new genarray for p; it is gene scaled by segscale*/      
  for (first = 0; first < mgeno; first++) {
    if(newflag2[first] == 0.0) continue;
    newwith2[first] *= segscale*gene[first];
  }

}


else  {  /*nchild is bigger than 1*/
  newwith2=(*LINK->p)->gen->genarray; /*get p's genarray*/


/*find nonzero entries in q's genarray and make a list of them
  stored in nonzgens; just get one per isozygote class*/
  nonzcount = 0;
  newwith3=(*LINK->q)->gen->genarray;

  /*iterate over genotypes for q*/
  for(i = 0; i < fgeno; i += step2) {
    /*number of distinct probabilties needed for i's isoz. class*/
    step2 = probend[i] - probstart[i] + 1; 
    for(j = i; j < i+step2; j++)
      if(newflag3[j] != 0) {
        nonzgens[nonzcount++] = i; /*store index of nonzero value*/
	break;                        /*go to next isozygote class*/
      }
  }

  newsegprob2 = femaletheta->segprob; /*get female probabilties*/

  /*iterate over genotypes for p*/
  for (first = 0; first < mgeno; first++) {

    if(newflag2[first] == 0) continue;

    /*initialize update multiple for each isozygote in class*/
    segval[0] = 0.0;

    /*iterate over the genotypes representing isozygote classes that
     q may have*/
    for (nonzindex = 0; nonzindex < nonzcount; nonzindex++) {
      second = nonzgens[nonzindex];
      /*check if this first, second pair yield a nonzero value
        among children's probabilities*/
      if(lsegsexfun2(first,second,LINK) == 0) continue;

      /*number of distinct probabilties needed for second's isoz. class*/
      step2 = probend[second] - probstart[second] + 1; 
  
   /*call segsum2 to compute the part of the conditional probability
     update that is common to all the members of the combined isozygote
     class defined by first and second */
      segsexsum2(first,second,step2,LINK);

      /*now specialize update for each member of first's class*/
        /*further specialize update for each member of second's isozygote
          class*/
	for(j = 0; j < step2; j++) {
        /*skip if this isozygote not possible*/
	  if(newflag3[second+j] == 0) continue; 

          /*get offset into probtable; the offset depends on
            the isozygote class size and index of each parent
            note that fisozygoteindex gets incremented by the size
            of the joint class each time, so it represents a
            sum of all the numbers of distinct probabilities
            needed for all joint iso. classes  considered before the
            current p isozygote class*/
	  tempprob = newsegprob2 + probstart[second+j] - 1;

        /*combine for all children*/
        /*due to the arrangement in segsum all the probability contributions
          for a given child are contiguous in the newwithr array.
          the number of contributions is fslength which is the number of
          probabilities needed for the joint isozygote class of the parents.
          We get the contribution of the first child (index 0) and
          then loop over the rest*/
	  val = tempprob[0] * tempseg[0];
         /*iterate over joint isozygote class*/
	  for(jointisoindex = 1; jointisoindex < step2; jointisoindex++)
	    val += tempprob[jointisoindex] * tempseg[jointisoindex];
	  newwithr = tempseg + step2; /*move the base of newwithr*/

         /*iterate over all the remaining children; notice that the
           loop index k is not used inside the loop. this is because the
           last loop statement which moves the offset of newwithr
           has the effect of incrementing the child*/
	  for(k = 1; k < nchild; k++) {
	    temp1 = tempprob[0] * newwithr[0];
	    for(jointisoindex = 1; jointisoindex < step2; jointisoindex++)
	      temp1 += tempprob[jointisoindex] * newwithr[jointisoindex];
	    val *= temp1;
	    newwithr += step2;
	  }
         /*update segval entry for this isozygote of first*/
	  segval[0] += newwith3[second+j] * val;
	}
    }
    /*update p's genarray for each isozygote in this class*/
    newwith2[first] *= segval[0] * segscale;
  }
}

/* If any of the nonzero entries in p's genarray became 0,
   we want to set them to zero to avoid computations on subsequent
   calls*/

  for(i = 0; i < mgeno; i++)
    if((newflag2[i]==1) && (newwith2[i] == 0.0)) newflag2[i] = 0;
  }
  else { /* p is female */

if(nchild == 1) {
/*initialize cache data structures*/
  for(i=0;i<maxhaplo;i++) {
    flag[i] = 0;
    phapcache1[i].first = 0;
    qsumcache[i] = 0.0;
  }

/*initialize gene array and set up flag array*/
  if(malechild[0]) {
    for(i = 0; i < mgeno; i++) {
      gene[i] = 0.0;
      if(newwithr[i] == 0.0) continue;
      flag[i] = 1;
    }
  }
  else {
    for(i = 0; i < fgeno; i++) {
      gene[i] = 0.0;
      if(newwithr[i] == 0.0) continue;
      flag[invgenenum1[i]-1] = 1;
      flag[invgenenum2[i]-1] = 1;
    }
  }

  current = 1; /* current should start with 1, since 0 means a null ptr */

  for (first = 0; first < fgeno; first++) {
    if(newflag2[first] == 0) continue; /*use only possible genotypes*/
    FORLIM = fence[first]; /*find end of isozygote class of first*/

  /*iterate over all members of first's isozygote calss*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i]; /*get haplotypes*/
      f2 = haps2[i];
      ind = hind[i];  /*get probability offset for i*/

   /*if f1 is a possible haplotype for child add the
     probability offset and value of first to the cache*/
      if(flag[f1-1] != 0) {
	indpool[current] = ind; /*store values in cache*/
	invpool[current] = first;
	nextpool[current] = 0;
        
       /* increment cache indices*/
	if(phapcache1[f1-1].first == 0) {  
	  phapcache1[f1-1].first = current;
	  phapcache1[f1-1].last = current;
	}
	else {
	  nextpool[phapcache1[f1-1].last] = current;
	  phapcache1[f1-1].last = current;
	}
	current++;
      }
 
      /*similar to f1, if f2 is a possible haplotype for
        a child, cache the ind and first values for it*/
      if(flag[f2-1] != 0) {
	indpool[current] = ind;
	invpool[current] = first;
	nextpool[current] = 0;
	if(phapcache1[f2-1].first == 0) {
	  phapcache1[f2-1].first = current;
	  phapcache1[f2-1].last = current;
	}
	else {
	  nextpool[phapcache1[f2-1].last] = current;
	  phapcache1[f2-1].last = current;
	}
	current++;
      }
    }
  }

  for(i = 0; i < mgeno; i++) {
    qsumcache[0] += newwith3[i];
  }

 /*In this section of the code we update the probabilities for
  the parent p based on the probabilities for the child*/  
  newsegprob = femaletheta->segprob; /*use male probabilities to work with p*/
 /*Iterate over all joint genotypes of the child*/
  newflagr=thischild[0]->sparseflag;
  if(malechild[0]) {
  for(here = 0; here < mgeno; here++) {
    if(newflagr[here] == 0) continue;
    tempr = qsumcache[0] * newwithr[here];

    for(i=phapcache1[here].first; i != 0; i = nextpool[i]) {
      first = invpool[i];
      gene[first] += tempr*newsegprob[indpool[i]];
    }

  }
  }
  else {
  for(here = 0; here < fgeno; here++) {
    if(newflagr[here] == 0) continue;
    tempr = newwithr[here];
    c1 = invgenenum1[here];
    c2 = invgenenum2[here];

  /*now find all the values of first that as genotypes of the
 father could have passed on the other haplotype c1; multiply
  by their probabilties, which are stored in phapcache, and
  add to the entry gene[first], which will be used to form
 the new genarray for p*/

    temp1 = tempr * newwith3[c2 - 1];
    for(i=phapcache1[c1-1].first; i != 0; i = nextpool[i]) {
      first = invpool[i];
      gene[first] += temp1*newsegprob[indpool[i]];
    }

  /*if c1 is distinct from c2 we need to do the same computation reversing
    the roles of the two haplotypes*/
    if(c1 != c2) {
      temp1 = tempr * newwith3[c1 - 1];
      for(i=phapcache1[c2-1].first; i != 0; i = nextpool[i]) {
        first = invpool[i];
	gene[first] += temp1*newsegprob[indpool[i]];
      }
    }
  }
  }

/*set up new genarray for p; it is gene scaled by segscale*/      
  for (first = 0; first < fgeno; first++) {
    if(newflag2[first] == 0.0) continue;
    newwith2[first] *= segscale*gene[first];
  }

}


else  {  /*nchild is bigger than 1*/
  newwith2=(*LINK->p)->gen->genarray; /*get p's genarray*/


/*find nonzero entries in q's genarray and make a list of them
  stored in nonzgens; just get one per isozygote class*/
  nonzcount = 0;
  newwith3=(*LINK->q)->gen->genarray;

  /*iterate over genotypes for q*/
  for(i = 0; i < mgeno; i++)
    if(newflag3[i] != 0)
      nonzgens[nonzcount++] = i; /*store index of nonzero value*/

  newsegprob2 = femaletheta->segprob; /*get female probabilties*/

  /*iterate over genotypes for p*/
  for (first = 0; first < fgeno; first += step1) {
      /*number of distinct probabilties needed for first's isoz. class*/
    step1 = probend[first] - probstart[first]+1; 
    skip = 1;

    /*work only on those isozygotes that are possible*/
    for(i = first; i < first+step1; i++)
      if(newflag2[i] != 0) {
	skip = 0;
	break; /*go to next isozygote in class*/
      }
    if(skip) continue;

    /*initialize update multiple for each isozygote in class*/
    for(i = 0; i < step1; i++) segval[i] = 0.0;

    /*iterate over the genotypes representing isozygote classes that
     q may have*/
    for (nonzindex = 0; nonzindex < nonzcount; nonzindex++) {
      second = nonzgens[nonzindex];
      /*check if this first, second pair yield a nonzero value
        among children's probabilities*/
      if(lsegsexfun2(second,first,LINK) == 0) continue;

      /*number of distinct probabilties needed for second's isoz. class*/

  
   /*call segsum2 to compute the part of the conditional probability
     update that is common to all the members of the combined isozygote
     class defined by first and second */
      segsexsum2(second,first,step1,LINK);

      /*now specialize update for each member of first's class*/
      for(i = 0; i < step1; i++) {
	if(newflag2[first+i] == 0) {
	  continue; /*skip if this isozygote is not possible*/
	}
        /*further specialize update for each member of second's isozygote
          class*/
        /*skip if this isozygote not possible*/
	  if(newflag3[second] == 0) continue; 

          /*get offset into probtable; the offset depends on
            the isozygote class size and index of each parent
            note that fisozygoteindex gets incremented by the size
            of the joint class each time, so it represents a
            sum of all the numbers of distinct probabilities
            needed for all joint iso. classes  considered before the
            current p isozygote class*/
	  tempprob = newsegprob2 + probstart[first+i] - 1;

        /*combine for all children*/
        /*due to the arrangement in segsum all the probability contributions
          for a given child are contiguous in the newwithr array.
          the number of contributions is fslength which is the number of
          probabilities needed for the joint isozygote class of the parents.
          We get the contribution of the first child (index 0) and
          then loop over the rest*/
	  val = tempprob[0] * tempseg[0];
         /*iterate over joint isozygote class*/
	  for(jointisoindex = 1; jointisoindex < step1; jointisoindex++)
	    val += tempprob[jointisoindex] * tempseg[jointisoindex];
	  newwithr = tempseg + step1; /*move the base of newwithr*/

         /*iterate over all the remaining children; notice that the
           loop index k is not used inside the loop. this is because the
           last loop statement which moves the offset of newwithr
           has the effect of incrementing the child*/
	  for(k = 1; k < nchild; k++) {
	    temp1 = tempprob[0] * newwithr[0];
	    for(jointisoindex = 1; jointisoindex < step1; jointisoindex++)
	      temp1 += tempprob[jointisoindex] * newwithr[jointisoindex];
	    val *= temp1;
	    newwithr += step1;
	  }
         /*update segval entry for this isozygote of first*/
	  segval[i] += newwith3[second] * val;
      }
    }
    /*update p's genarray for each isozygote in this class*/
    for(i = 0; i < step1; i++) newwith2[first+i] *= segval[i] * segscale;
  }
}

/* If any of the nonzero entries in p's genarray became 0,
   we want to set them to zero to avoid computations on subsequent
   calls*/

  for(i = 0; i < fgeno; i++)
    if((newflag2[i]==1) && (newwith2[i] == 0.0)) newflag2[i] = 0;
}
  cleanup(LINK->q, LINK->LINK);
  exitseg(LINK);
}  /*segsexup*/

/* segdown updates the genotype probabilities for a child  based
on the probabilities of parents and other children. The parameter LINK includes
all the genetic information about p, p's spouse q, and their
children */

void segsexdown(LINK)
struct LOC_seg *LINK;
{
  int  FORLIM; /*loop bound*/
  int nonzindex, nonzcount;    /*loop index and counter for nonzero values*/
  unsigned cgeno;
  int step2; /*size of isozygote classes*/
  double valtemp; /*intermediate values in probability updates*/
  double val, temp1; /*temporaries to store intermediate values*/
  unsigned int f1, f2; /*four haplotypes from parents*/
  unsigned int here, i, j, first, second; /*genotype indices*/
  int jointisoindex; /*indices to work within isozygote classes*/
  unsigned currentindex; /*index to update genarray within isozygote class*/
  unsigned k; /*index to loop over children*/
  thisarray *WITH2; /*stores genetic information about p*/
  thisarray *WITH3; /*stores gnetic information about q*/
  double *newwith2, *newwith3, *newwithr, *newwithc; /*store genarrays for
						       p,q, and children*/
  thetavalues *WITH4; /*stores theta values for male parent*/
  thetavalues *WITH5; /*store theta values for female parent*/
  unsigned int  c1, c2; /*haplotypes*/
  unsigned char *newflag2, *newflag3, *newflagr; /*store sparsity patterns for
					p and q genarrays*/
  unsigned char male;


  /* newsegprob, newsegprob1, and newsegprob2 are  used to hold segprob
    arrays, which contain the probabilities for various patterns of
    recombination events*/
  double *newsegprob, *newsegprob2; 
  double *tempprob; /*temporary holder for probability array*/
  int ind;      /*used to store offset for probability array*/

  initseg(LINK); /*get data about this p,q,children triple*/

  /*get sparsity patterns for p, q, and child genarrays*/
  newflag2 = (*LINK->p)->gen->sparseflag; 
  newflag3 = (*LINK->q)->gen->sparseflag;
  newflagr = (*LINK->r)->gen->sparseflag;

  WITH2 = (*LINK->p)->gen; /*get genetic data for p*/
  WITH3 = (*LINK->q)->gen; /*get genetic data for q*/
  newwith2 = WITH2->genarray; /*get genarray for p*/
  newwith3 = WITH3->genarray; /*get genarray for q*/
  newwithr = (*LINK->r)->gen->genarray; /*get genarray for first child*/
  WITH4 = maletheta; /*get male probabilities*/
  WITH5 = femaletheta; /*get female probabilities*/
  male = (*LINK->r)->male;
  if(male) cgeno = mgeno;
  else cgeno = fgeno;

/*The case of 1 child (nchild==0) is handled specially because the
subcomputations are much simpler. In particular we do not need to multiply the
probabilities among the different children. In a typical pedigree
many pairs will have only one child about which information is known
(in essence this is the child that keeps the pedigree connected), so
this is an important and common special case. */

if(nchild == 0) {
/*initialize cache data structures*/
  for(i = 0;i < maxhaplo;i++) {
    flag[i] = 0;
    psumcache[i] = 0.0;
    qsumcache[i] = 0.0;
  }

/*initialize gene array and set up flag array*/
    for(i = 0; i < cgeno; i++) {
      if(newwithr[i] == 0.0) continue;
      gene[i] = 0.0;
      flag[invgenenum1[i]-1] = 1;
      flag[invgenenum2[i]-1] = 1;
    }



  newsegprob = femaletheta->segprob; /*use female probabilities to work with q*/

 /*iterate over all joint genotypes*/
  for (first = 0; first < fgeno; first++ ) {
    if(newflag3[first] == 0) continue; /*check if joint genotype is possible*/
    valtemp = newwith3[first]; /*get cond. prob. that q has genotype first*/
    FORLIM = fence[first]; /*find bounds for the isozygote class of first*/

 /*iterate over all the recombined genotypes of the isozygote class*/
    for (i = base[first]; i < FORLIM; i++) {
      f1 = haps1[i];
      f2 = haps2[i];

      if((flag[f1-1] !=0) || (flag[f2-1] !=0)) {

/*condition probability of first as a genotype multiplied by probability
  of passing on f1 (alternatively f2) as a haplotype*/
        ind = hind[i];  /*get probability offset for i*/
        val = valtemp*newsegprob[hind[i]];
     /*store in qsumcache*/
        if(flag[f1-1] != 0) {
	  qsumcache[f1 - 1] += val;
        }
        if(flag[f2-1] != 0) {
	  qsumcache[f2 - 1] += val;
        }
      }
    }
  }


 /*In this section of the code we update the probabilities for
  the child based on the probabilities for the parents*/  

 /*Iterate over all joint genotypes of the child*/

  if(male) {
    double temp1 = 0.0;
    for(here = 0; here < mgeno; here++) {
      temp1 += newwith2[here];
    }
    for(here = 0; here < mgeno; here++) {
      if(newflagr[here] == 0) continue;
  
      gene[here] =  temp1 * qsumcache[here];
  
    }
  }
  else {
    for(here = 0; here < fgeno; here++) {
      if(newflagr[here] == 0) continue;
      c1 = invgenenum1[here];
      c2 = invgenenum2[here];
  
     /*probability of child getting genotype here as a
       result of p passing on c1 and q passing on c2 is
       summed to gene[here] */
  
      gene[here] += newwith2[c1-1] * qsumcache[c2-1];
  
    /*if c1 is distinct from c2 we need to do the same computation reversing
      the roles of the two haplotypes*/
      if(c1 != c2) {
        gene[here] += newwith2[c2-1] * qsumcache[c1-1];
      }
    }
  }

/*set up new genarray for r; it is gene scaled by segscale*/      
    for (first = 0; first < cgeno; first++) {
      if(newflagr[first] == 0) continue;
      if(gene[first] == 0.0) newflagr[first] = 0;
      newwithr[first] *= segscale*gene[first];
    }

}


else  {  /*nchild is bigger than 0*/
  newwith2=(*LINK->p)->gen->genarray; /*get p's genarray*/

 /*initialize genarray entries for child to 0*/
    for(i = 0; i < cgeno; i++) {
      if(newflagr[i] == 0) continue;
      gene[i] = 0.0;
    }

/*find nonzero entries in q's genarray and make a list of them
  stored in nonzgens; just get one per isozygote class*/
  nonzcount = 0;
  newwith3=(*LINK->q)->gen->genarray;

  /*iterate over genotypes for q*/
  for(i = 0; i < fgeno; i += step2) {
    /*number of distinct probabilties needed for i's isoz. class*/
    step2 = probend[i] - probstart[i] + 1; 
    for(j = i; j < i+step2; j++)
      if(newflag3[j] != 0) {
        nonzgens[nonzcount++] = i; /*store index of nonzero value*/
	break;                        /*go to next isozygote class*/
      }
  }

  newsegprob2 = femaletheta->segprob; /*get female probabilties*/

  /*iterate over genotypes for p*/
  for (first = 0; first < mgeno; first++) {

    if(newflag2[first] == 0) continue;

    /*iterate over the genotypes representing isozygote classes that
     q may have*/
    for (nonzindex = 0; nonzindex < nonzcount; nonzindex++) {
      second = nonzgens[nonzindex];
      /*check if this first, second pair yield a nonzero value
        among children's probabilities*/
      if(lsegsexfun2(first,second,LINK) == 0) continue;

      /*number of distinct probabilties needed for second's isoz. class*/
      step2 = probend[second] - probstart[second] + 1; 
  
   /*call segsumdown2 to compute the part of the conditional probability
     update that is common to all the members of the combined isozygote
     class defined by first and second */
      segsexsumdown2(first,second,step2,male,LINK);

      for(jointisoindex = 0; jointisoindex < step2; jointisoindex++)
	segval[jointisoindex] = 0.0;

      /*now specialize update for each member of first's class*/
	if(newflag2[first] == 0) continue;

        /*further specialize update for each member of second's isozygote
          class*/
	for(j = 0; j < step2; j++) {
        /*skip if this isozygote not possible*/
	  if(newflag3[second+j] == 0) {
	    continue; 
	  }

	  tempprob = newsegprob2 + probstart[second+j] - 1;

        /*combine for all children*/
        /*due to the arrangement in segsum all the probability contributions
          for a given child are contiguous in the newwithr array.
          the number of contributions is fslength which is the number of
          probabilties needed for the joint isozygote class for the parents.
          We get the contribution of the first child (index 0) and
          then loop over the rest*/
	  val = tempprob[0] * tempseg[0];
         /*iterate over joint isozygote class*/
	  for(jointisoindex = 1; jointisoindex < step2; jointisoindex++)
	    val += tempprob[jointisoindex] * tempseg[jointisoindex];
	  newwithc = tempseg + step2; /*move the base of newwithc*/

         /*iterate over all the remaining children; notice that the
           loop index k is not used inside the loop. this is because the
           last loop statement which moves the offset of newwithc
           has the effect of incrementing the child*/
	  for(k = 1; k < nchild; k++) {
	    temp1 = tempprob[0] * newwithc[0];
	    for(jointisoindex = 1; jointisoindex < step2; jointisoindex++)
	      temp1 += tempprob[jointisoindex] * newwithc[jointisoindex];
	    val *= temp1;
	    newwithc += step2;
	  }
          /*probability of this combination of parent genotypes*/
	  val *= newwith2[first] * newwith3[second+j];
	  for(jointisoindex = 0; jointisoindex < step2; jointisoindex++) {
          /*probability of this recombination pattern (based on other children)*/
	    segval[jointisoindex] += tempprob[jointisoindex] * val;
	  }
	}
      /*update the probabilities of four joint genotypes the
       child might get; each different choice of recombination
       pattern will lead to a different set of four genotypes*/
      currentindex = 0;
      for(jointisoindex = 0; jointisoindex < step2; jointisoindex++) {
	temp1 = segval[jointisoindex];
	gene[segindex[currentindex++]-1] += temp1;
	gene[segindex[currentindex++]-1] += temp1;
      }
    }
  }
  /*finally update child's real genarray by coppy gene multiplied
    by scale factor segscale*/
  for(i = 0; i < cgeno; i++) {
    if(newflagr[i] == 0) continue;
    if(gene[i] == 0.0) newflagr[i] = 0; /*if probability changes from nonzero
					  to 0.0 change flag to 0*/
    newwithr[i] *= segscale * gene[i];
  }
}

  cleanup(LINK->q, LINK->LINK);
  exitseg(LINK);
}  /*segsexdown*/


