int main(int argc, char* argv[]) {
  int retval = 0;
  int i;

  char* progname = strrchr(argv[0], '/');
  if (progname)
    progname++;
  else
    progname = argv[0];

  if (VbArchInit()) {
    fprintf(stderr, "Failed to initialize\n");
    return -1;
  }

  /* If no args specified, print all params */
  if (argc == 1)
    return PrintAllParams(0);
  /* --all or -a prints all params including normally hidden ones */
  if (!strcasecmp(argv[1], "--all") || !strcmp(argv[1], "-a"))
    return PrintAllParams(1);

  /* Print help if needed */
  if (!strcasecmp(argv[1], "-h") || !strcmp(argv[1], "-?")) {
    PrintHelp(progname);
    return 0;
  }

  /* Otherwise, loop through params and get/set them */
  for (i = 1; i < argc && retval == 0; i++) {
    char* has_set = strchr(argv[i], '=');
    char* has_expect = strchr(argv[i], '?');
    char* name = strtok(argv[i], "=?");
    char* value = strtok(NULL, "=?");
    const Param* p;

    /* Make sure args are well-formed. '' or '=foo' or '?foo' not allowed. */
    if (!name || has_set == argv[i] || has_expect == argv[i]) {
      fprintf(stderr, "Poorly formed parameter\n");
      PrintHelp(progname);
      return 1;
    }
    if (!value)
      value=""; /* Allow setting/checking an empty string ('foo=' or 'foo?') */
    if (has_set && has_expect) {
      fprintf(stderr, "Use either = or ? in a parameter, but not both.\n");
      PrintHelp(progname);
      return 1;
    }

    /* Find the parameter */
    p = FindParam(name);
    if (!p) {
      fprintf(stderr, "Invalid parameter name: %s\n", name);
      PrintHelp(progname);
      return 1;
    }

    if (i > 1)
      printf(" ");  /* Output params space-delimited */
    if (has_set)
      retval = SetParam(p, value);
    else if (has_expect)
      retval = CheckParam(p, value);
    else
      retval = PrintParam(p);
  }

  return retval;
}
Exemple #2
0
int
main (int argc, char *argv[])
{
  double N1, N2, Nanc, NancLower, *uniqTauArray = NULL, *taxonTauArray = NULL,
         *descendant1ThetaArray = NULL, *descendant2ThetaArray = NULL,
         *ancestralThetaArray = NULL, spTheta, thetaMean, tauequalizer, gaussTime = 0.0,
         mig, rec, BottStr1, BottStr2, BottleTime;
  double *recTbl;
  int tauClass, *PSIarray = NULL, i;
  unsigned int numTauClasses = -1, u, locus, taxonID, zzz;
  unsigned long randSeed;
  unsigned long long rep;
  extern const gsl_rng *gBaseRand;
  int comp_nums (const void *, const void *);

  int b_constrain = 0;
  int *subParamConstrainConfig = NULL;

#ifndef HOMOGENEOUS_MUT
  double *mutScalerTbl;
#endif

  /* set up gParam and gMutParam, as well as gConParam if constrain */
  LoadConfiguration (argc, argv);

  /* set the lower Nanc */
  /* NancLower = 0.00001 * gParam.lowerTheta; */
  /* if (NancLower < 0.00000000004) { /1* 4 * (mu=10^(-11)) * (Ne=1) *1/ */
  /*   NancLower = 0.00000000004; */
  /* } */

  /* set b_constrain to 1 if constrain */
  if (gParam.constrain > 0)
    {
      //initialize constrain indicator
      b_constrain = 1;

      //initialize subParamConstrainConfig array
      subParamConstrainConfig = calloc (NUMBER_OF_CONPARAM, sizeof (int));
      if (subParamConstrainConfig == NULL)
	{
	  fprintf (stderr,
		   "ERROR: Not enough memory for subParamConstrainConfig\n");
	  exit (EXIT_FAILURE);
	}

      for (i = 0; i < strlen (gParam.subParamConstrain); i++)
	{
	  char a = (gParam.subParamConstrain)[i];

	  if (a == '1')
	    subParamConstrainConfig[i] = 1;
	  else if (a == '0')
	    subParamConstrainConfig[i] = 0;
	  else {
	    fprintf(stderr, "ERROR: subParamConstrain string in the config file"
		    "should be either 0 or 1\n");
	    exit (EXIT_FAILURE);
	  }
	}
    }

  /* for initiating the gsl random number generator */
  /* initialize PRNG */
  srand (gParam.prngSeed);	/* Better way of seeding here ? */
  randSeed = rand ();
  if (debug_level > 0)
    randSeed = 1;

  gBaseRand = gsl_rng_alloc (gsl_rng_mt19937);	/* set the base PRNG to
						   Mersenne Twister */
  gsl_rng_set (gBaseRand, randSeed);	/* seed the PRNG */

  /* print out all of the parameters */
  if(gParam.printConf) {
    PrintParam(stdout);
    exit (0);
  }

  /* set up arrays */
  /* Sizes are set to the number of taxon pairs (Max number of tau's) */
  if ((b_constrain == 1) && (subParamConstrainConfig[0] == 1)) {
    uniqTauArray = calloc (gParam.numTaxonLocusPairs, sizeof (double));
    PSIarray = calloc (gParam.numTaxonLocusPairs, sizeof (int));
    taxonTauArray = calloc(gParam.numTaxonLocusPairs, sizeof (double));
  } else {
    uniqTauArray = calloc (gParam.numTaxonPairs, sizeof (double));
    PSIarray = calloc (gParam.numTaxonPairs, sizeof (int));
    taxonTauArray = calloc(gParam.numTaxonPairs, sizeof (double));
  }
  descendant1ThetaArray = calloc (gParam.numTaxonPairs, sizeof (double));
  descendant2ThetaArray = calloc (gParam.numTaxonPairs, sizeof (double));
  ancestralThetaArray = calloc (gParam.numTaxonPairs, sizeof (double));

  recTbl = calloc (gParam.numLoci, sizeof (double));

  if (uniqTauArray == NULL || PSIarray == NULL || recTbl == NULL ||
          taxonTauArray == NULL || descendant1ThetaArray == NULL ||
          descendant2ThetaArray == NULL || ancestralThetaArray == NULL)
    {
      fprintf (stderr, "ERROR: Not enough memory for uniqTauArray, PSIarray, or recTbl\n");
      exit (EXIT_FAILURE);
    }

  /* deal with num tau classes */
  if (b_constrain == 0 || subParamConstrainConfig[0] != 1)
    {
      /* fixed numTauClasses configuration */
      if (gParam.numTauClasses != 0)
	{
	  if (gParam.numTauClasses > gParam.numTaxonPairs)
	    {
	      fprintf (stderr, "WARN: numTauClasses (%u) is larger than "
		       "numTaxonPairs (%u). Setting numTauClasses to %u",
		       gParam.numTauClasses, gParam.numTaxonPairs,
		       gParam.numTaxonPairs);
	      gParam.numTauClasses = gParam.numTaxonPairs;
	    }
	  numTauClasses = gParam.numTauClasses;
	}
    }  /* when tau is constrained numTauClasses are set later */

  /* deal with the case when tau is constrained */
  if ((b_constrain == 1) && (subParamConstrainConfig[0] == 1)) {
    int jj, kk;
    double *tempTauArray;
    if ((tempTauArray = calloc(gParam.numTaxonLocusPairs, sizeof(double))) 
	== NULL) {
      fprintf (stderr, "ERROR: Not enough memory for tempTauArray\n");
      exit (EXIT_FAILURE);
    }
    for (jj = 0; jj < gParam.numTaxonLocusPairs; jj++) {
      tempTauArray[jj] = (gConParam.conData[jj]).conTau;
    }
    numTauClasses = UniqueDouble(tempTauArray, uniqTauArray, 
			   gParam.numTaxonLocusPairs, DBL_EPSILON);
    
    if (gParam.numTauClasses != numTauClasses) {
      fprintf (stderr, "WARN: tau's are constrained and found %u different "
	       "classes in the constrain table. But numTauClasses = %u was set."
	       " Using the value found in the constrain table.\n", numTauClasses,
	       gParam.numTauClasses);
      gParam.numTauClasses = numTauClasses;
    } 
    
    /* count tau's to create PSIarray */
    for (jj = 0; jj < gParam.numTaxonLocusPairs; jj++) {
      PSIarray[jj] = 0;
    }
    for (jj = 0; jj < gParam.numTaxonLocusPairs; jj++) {
      for (kk = 0; kk < numTauClasses; kk++) {
	/* there shouldn't be fabs() below */
	if (tempTauArray[jj] - uniqTauArray[kk] < DBL_EPSILON) {
	  PSIarray[kk]++;
	  break;
	}
      }
    }
    free (tempTauArray);
  }

#ifndef HOMOGENEOUS_MUT
  if ((mutScalerTbl = calloc(gParam.numLoci, sizeof(double))) == NULL) {
    fprintf (stderr, "ERROR: Not enough memory for mutScalerTbl\n");
    exit(EXIT_FAILURE);
  }
#endif

  thetaMean = 1.0;
  if (gParam.timeInSubsPerSite == 0) {
    thetaMean = (gParam.lowerTheta + gParam.upperTheta) / 2.0;
  }

  /* Beginning of the main loop */
  for (rep = 0; rep < gParam.reps; rep++)
    {
      int lociTaxonPairIDcntr = 1;
      /*
       * Each taxon pair was separated at a time tau in the past.  Of
       * all pairs, some of them may have been separated at the same
       * time.  numTauClasses is the number of classes with different
       * divergence time.
       *
       * If gParam.numTauClasses is not set, we are sampling
       * numTauClasses from a uniform prior dist'n.
       */
      if (gParam.numTauClasses == 0)
	{			/* numTauClasses is NOT fixed */
	  numTauClasses =
	    1 + gsl_rng_uniform_int (gBaseRand, gParam.numTaxonPairs);
	}
      
      /* create the recombination rate table for each gene */
      rec = gsl_ran_flat (gBaseRand, 0.0, gParam.upperRec);
      for (u=0; u < gParam.numLoci; u++)
	{
	  /* all loci shares same recombination rate */
	  recTbl[u] = rec;
	  /* each locus has different recomb. rate 
	     recTbl[u] = gsl_ran_flat (gBaseRand, 0.0, gParam.upperRec);
	  */
	}
      
#ifndef HOMOGENEOUS_MUT
      /* create regional heterogeneity in the mutation rate */
      if (gParam.numLoci > 1) {
	double shape, scale;
	
	/* arbitrary sample the shape parameter from uniform dist'n */
	shape = gsl_ran_flat(gBaseRand, 1.0, 20);
	/* shape = 1 is exponential with lambda=1, 
	   larger shape -> normal dist'n with smaller var */
	scale = 1/shape; /* E[x] = 1, Var[x] = shape * scale^2 = 1/shape */
	
	/* use gamma */
	for (u=0; u < gParam.numLoci; u++) {
	  mutScalerTbl[u] = gsl_ran_gamma(gBaseRand, shape, scale);
	}
      } else {
	mutScalerTbl[0] = 1.0;
      }
#endif

      // Randomly generate TauArray only when NOT constrain
      if ((b_constrain == 0) || (subParamConstrainConfig[0] != 1))
	{
	  int counter;
	  /* sample tau's from uniform prior dist'n */
	  for (u = 0; u < numTauClasses; u++)
// JRO - modified - 11/17/2011
//	    uniqTauArray[u] = gsl_ran_flat (gBaseRand, 0.0, gParam.upperTau);
	    uniqTauArray[u] = gsl_ran_flat (gBaseRand, gParam.lowerTau,
	                                    gParam.upperTau);

          qsort(uniqTauArray, numTauClasses, sizeof(double),comp_nums);

          for (counter = 0; counter < numTauClasses; counter++) 
	    {
	      taxonTauArray[counter] = uniqTauArray[counter];
	      PSIarray[counter] = 1;
	    }

          for (counter = numTauClasses; 
	       counter < gParam.numTaxonPairs; counter++)
	    {
	      tauClass = gsl_rng_uniform_int(gBaseRand, numTauClasses);
	      taxonTauArray[counter] = uniqTauArray[tauClass];
	      PSIarray[tauClass] = PSIarray[tauClass] + 1;
	    }

	  /* randomly shuflling the order of taxonTauArray */
	  gsl_ran_shuffle(gBaseRand, taxonTauArray, 
			  gParam.numTaxonPairs, sizeof (double));
	}
      
      for (taxonID = 0; taxonID < gParam.numTaxonPairs; taxonID++)
	{
	  //Check upperAncPopSize before doing anything
	  /* ancestral population size prior */
	  if (gParam.upperAncPopSize < gParam.lowerTheta)
	    {
	      fprintf (stderr,
		       "The upper bound (%lf * %lf) of ancestral pop. size is "
		       "smaller than the lower bound (%lf)\n",
		       gParam.upperAncPopSize, gParam.upperTheta, gParam.lowerTheta);
	      exit (EXIT_FAILURE);
	    }

	  constrainedParameter conTaxonPairDat;

	  /* Population sizes during the bottleneck after the divergence of 2 
	     pops. This is same as the population sizes, immediately after the 
	     divergence/separation of the 2 pops. These are relative sizes. */
	  BottStr1 = gsl_ran_flat (gBaseRand, 0.01, 1.0);
	  BottStr2 = gsl_ran_flat (gBaseRand, 0.01, 1.0);

	  /* After the populations diverge, they experience pop. bottleneck.
	     Then the population size exponentially grows until current size.
	     BottleTime indicate the time when population started to grow.  
	     BottleTime of 1 means, populations start to expand immediately
	     after divergence. Closer to 0 means, populations hasn't started
	     to expand until very recently.  */
	  BottleTime = gsl_ran_flat (gBaseRand, 0.000001, 1.0);

	  /* migration rate prior */
	  mig = gsl_ran_flat (gBaseRand, 0.0, gParam.upperMig);
	  /* spTheta prior */
	  while ((spTheta = gsl_ran_flat (gBaseRand, gParam.lowerTheta,
					  gParam.upperTheta)) <= 0);

	  /* The ratio of current population sizes.  The populations
	     exponentially grow to these sizes after bottkleneck is done. */
	  /* both ends excluded for symmetry */
	  while ((N1 = gsl_ran_flat (gBaseRand, 0.01, 1.99)) == 0.01)
	    ;
	  
	  N2 = 2.0 - N1;

	  /* The upper limit of ancestral theta is defined by the product
	     of upper Theta (e.g. 40) and upper AncPopSize (e.g. 0.5) */
	  /* JRO - changing the following hard coded lower limit on ancestral
	     theta to the lower limit specified by user */
	  /* Nanc = gsl_ran_flat (gBaseRand, 0.01,
			       gParam.upperAncPopSize * gParam.upperTheta);*/
	  Nanc = gsl_ran_flat (gBaseRand, gParam.lowerTheta,
			       gParam.upperAncPopSize * gParam.upperTheta);

      descendant1ThetaArray[taxonID] = spTheta * N1;
      descendant2ThetaArray[taxonID] = spTheta * N2;
      ancestralThetaArray[taxonID] = Nanc;
	  
	  /* pick a tau for every taxon-pair with replacement from the
	     array of X taxon-pairs, where X is a uniform discrete RV
	     from 1 to number of taxon-pairs */
	  if ((b_constrain == 0) || (subParamConstrainConfig[0] != 1))
	    {
	      gaussTime = taxonTauArray[taxonID];
	    }

	  /* use the following if simulating a particular fixed history */
	  /* gaussTime = uniqTauArray[taxonID]; */
	  
	  /* print out the results by going through each locus */
	  for (locus = 0; locus < gParam.numLoci; locus++)
	    {
	      double locTheta, thisNanc, scaledGaussTime, scaledBottleTime;
	      /* check if this locus exist for this taxon pair */
	      /* this table contains 0-offset index for corresponding 
		 taxon:locus mutPara */
	      int mpIndex = gMutParam.locTbl->tbl[taxonID][locus];
	      
	      if(mpIndex<0) { /* this taxon:locus is not in the data */
		continue;
	      }

	      if (b_constrain == 1)
		{  /* If constrained, override with the fixed paras */
		  /* This part is not debugged well 2/14/2008, Naoki */
		  int mpIndex = gMutParam.locTbl->tbl[taxonID][locus];
		  conTaxonPairDat = gConParam.conData[mpIndex];

		  /* tau */
		  /* This allow that tau could differ between loci
		     within a single taxon pair */
		  if (subParamConstrainConfig[0] == 1)
		    gaussTime = conTaxonPairDat.conTau;

		  /** bottleneck priors **/
		  /* severity of bottle neck (how small the pop become) */
		  /* these should be [0,1] */
		  if (subParamConstrainConfig[1] == 1)
		    BottStr1 = conTaxonPairDat.conBottPop1;
		  if (subParamConstrainConfig[2] == 1)
		    BottStr2 = conTaxonPairDat.conBottPop2;
		  
		  /* timing of bottle neck */
		  /* should be [0,1] */
		  if (subParamConstrainConfig[3] == 1)
		    BottleTime = conTaxonPairDat.conBottleTime;
		  
		  /* migration rate prior */
		  if (subParamConstrainConfig[4] == 1)
		    mig = conTaxonPairDat.conMig;
		  
		  /* theta per site */
		  if (subParamConstrainConfig[5] == 1)
		    spTheta = conTaxonPairDat.conTheta;
		  
		  /* population sizes immediately after the separation, and 
		     what it grows to after the bottleneck (today) */
		  /* (0.01, 1.99) */
		  if (subParamConstrainConfig[6] == 1) {
		    N1 = conTaxonPairDat.conN1;
		    N2 = 2.0 - N1;
		  }
		  
		  /* The upper limit of ancestral theta is defined by the 
		     product of upper Theta (e.g. 40) and upper 
		     AncPopSize (e.g. 0.5), then converted to relative size 
		     to spTheta */
		  if (subParamConstrainConfig[7] == 1)
		    Nanc = conTaxonPairDat.conNanc * gParam.upperTheta;
		  
		  /* recombination rate per neighboring site */
		  if (subParamConstrainConfig[8] == 1)
		    recTbl[locus] = conTaxonPairDat.conRec;
		}  /* end of constrai */

	      /* access sample sizes, mutational model for this taxon:locus */
	      mutParameter taxonPairDat;
	      taxonPairDat = gMutParam.data[mpIndex];
	      
	      /* scale the theta for each locus */
	      /* Note that species wide theta (represents pop size) is 
	         4 Ne mu with mu per site, not per gene.
		 Assumes mu is constant.  This may be a problem with
	         mitochondoria */
	      locTheta = spTheta * taxonPairDat.seqLen * 
		taxonPairDat.NScaler * taxonPairDat.mutScaler;
#ifndef HOMOGENEOUS_MUT
	      locTheta *=  mutScalerTbl[locus];
#endif

	      /* thisNanc is basically a random deviate from a uniform dist'n:
		 [gParam.lowerTheta / spTheta, 
		   gParam.upperAncPopSize * gParam.upperTheta/spTheta) 
		 For example, if upperTheta = 10 & upperAncPopSize = 0.5,
		 upperAncTheta become 10 * 0.5 = 5.
		 msDQH specify the past population sizes in terms of the 
		 ratio of N_anc / N_theta, so the following division
		 by locTheta is required.
	      */
	      /* thisNanc = Nanc * taxonPairDat.seqLen / locTheta; */
	      thisNanc = Nanc / spTheta; /* this can be done outside of locus loop */

	      /* this scaling is done inside of locus loop to accomodate 
		 the gamma dist'n of mut rate for each locus */

	      /* tauequalizer = gParam.upperTheta / */ 
		/* 2 / (spTheta * taxonPairDat.NScaler); */
          tauequalizer = thetaMean / (spTheta * taxonPairDat.NScaler);
	      /* WORK, CONFIRM THIS. Naoki Nov 2, 2009.  IT USED TO BE
		 tauequalizer = gParam.upperTheta * taxonPairDat.seqLen / 
		 2 / locTheta;

	      */

	      /* Division by 2 is coming from N1 + N2 = 2.
		 We are considering that N_0 in theta_0 (=4 N_0 mu) specified 
		 for -t option (we use -t locTheta) of msDQH is equal to 
		 (N1+N2)/2 */

	      scaledGaussTime = gaussTime * tauequalizer;
	      /* 1 unit of tau (gaussTime) = 2 N_max (N_max is the 
		 N assumed in upperTheta) */
	      /* I think we should get rid of /2 from tauequalizer */

          /* JRO: Yes the following is weird and the threshold of 0.0001
           * coalescent units can actually be thousands of generations which
           * is not trivial. Also, the hack to avoid unrealistic growth rates
           * is the wrong approach. If the div time is essentially zero, then
           * there should simply be no bottleneck. Updating to make the
           * threshold smaller, and simply preventing a bottleneck if the
           * div time is smaller.*/
	      /* The following if is a little weird */
	      /* if (scaledGaussTime < 0.0001) { */
		/* scaledGaussTime  = 0.0001; */
		/* scaledBottleTime = 0.00005; */
	      /* } else { */
		/* scaledBottleTime = BottleTime * 0.95 * scaledGaussTime; */
	      /* } */
            if (scaledGaussTime < 0.000001) {
                // no bottleneck if div time is essentially zero
                BottStr1 = 1.0;
                BottStr2 = 1.0;
            }
            scaledBottleTime = BottleTime * 0.95 * scaledGaussTime;
	      
	      if (debug_level)
		fprintf (stderr, 
			 "DEBUG: scaled BottleTime:%lf\tgaussTime:%lf\n",
			 scaledBottleTime, scaledGaussTime);

	      /* We can send some extra info to msbayes.pl here */
	      printf ("%u %u %u ", lociTaxonPairIDcntr, taxonID+1, locus+1);
	      lociTaxonPairIDcntr ++; /* seriral id: 1 to # taxon:locus pairs */
	      printf ("%.17lf %.17lf %.17lf %.17lf ",
		      locTheta, scaledGaussTime, mig, 
		      recTbl[locus] * (taxonPairDat.seqLen - 1));
	      printf ("%.17lf %.17lf %.17lf ", scaledBottleTime, 
		      BottStr1 * N1, BottStr2 * N2);
	      printf ("%u %u %u %lf %lf %lf ",
		      taxonPairDat.numPerTaxa,
		      taxonPairDat.sample[0], taxonPairDat.sample[1],
		      taxonPairDat.tstv[0], taxonPairDat.tstv[1],
		      taxonPairDat.gamma);
	      printf ("%u %.17lf %.17lf %.17lf ",
		      taxonPairDat.seqLen, N1, N2, thisNanc);
	      printf ("%lf %lf %lf %lf\n",
		      taxonPairDat.freqA, taxonPairDat.freqC,
		      taxonPairDat.freqG, taxonPairDat.freqT);

	      /* These feed into the system command line (msDQH) within
	         the perl shell msbayes.  Some of these are used directly
	         by msDQH, but some are also passed on to the sumstats
	         programs via the msDQH commabnd line, .... like bp[taxonID],
	         theta, gaussTime, NumPerTax[taxonID], yy, */
	    }
	}

      /* The followings are used to calculate prior, processed in msbayes.pl */
      printf ("# TAU_PSI_TBL setting: %d realizedNumTauClasses: %u", 
	      gParam.numTauClasses, numTauClasses);
      printf(" tauTbl:");
      for (zzz = 0; zzz < gParam.numTaxonPairs; zzz++)
          printf (",%.11lf", taxonTauArray[zzz]);
      printf(" d1ThetaTbl:");
      for (zzz = 0; zzz < gParam.numTaxonPairs; zzz++)
          printf (",%lf", descendant1ThetaArray[zzz]);
      printf(" d2ThetaTbl:");
      for (zzz = 0; zzz < gParam.numTaxonPairs; zzz++)
          printf (",%lf", descendant2ThetaArray[zzz]);
      printf(" aThetaTbl:");
      for (zzz = 0; zzz < gParam.numTaxonPairs; zzz++)
          printf (",%lf", ancestralThetaArray[zzz]);
      printf("\n");

    }

  free (uniqTauArray);
  free (taxonTauArray);
  free (PSIarray);
  free (descendant1ThetaArray);
  free (descendant2ThetaArray);
  free (ancestralThetaArray);
  free (recTbl);
  free (subParamConstrainConfig);
  exit (0);
}
Exemple #3
0
int main (int argc, const char **argv) 
/* 
!C******************************************************************************

!Description: 'main' is the main function for the 'resamp' program.
 
!Input Parameters:
 argc           number of run-time (command line) arguments
 argv           list of run-time argument values

!Output Parameters:
 (returns)      status:
                  'EXIT_SUCCESS' = okay
		  'EXIT_FAILURE' = fatal error

!Team Unique Header:

 ! Design Notes:
   1. See 'USAGE' in 'parser.h' for information on how to use the program.
   2. An error status is returned when:
       a. there is a problem getting runtime parameters
       b. there is a bad input image, geolocation or kernel file
       c. unable to set up the input grid, scan data structure, 
          or the output space
       d. unable to generate kernel
       f. unable to free memory for data structures
       g. unable to set up intermediate patches data structure
       h. there is an error reading geolocation for a scan
       i. there is an error mapping a scan
       j. there is an error generating geolocation for a scan
       k. there is an error copying a scan
       l. there is an error extending the scan
       m. there is an error reading input data for a scan
       n. there is an error resampling a scan
       o. there is an error writting patches to disk
       p. there is an error closing input image, geolocation, kernel or 
          output files
       q. there is an error untouching patches
       r. there is an error creating output image file
       s. there is an error opening output file
       t. there is an error unscrambling the output file
       u. there is an error writing metadata.
   3. Errors are handled with the 'LOG_ERROR' macro.

!END****************************************************************************
*/
{
  int i,j,k;
  int curr_sds, curr_band;        /* current SDS and current band in SDS */
  char tmp_sds_name[MAX_STR_LEN];
  char errstr[M_MSG_LEN+1];              /* error string for OpenInput */
  char sdsname[256];              /* SDS name without '/'s */
  char msg[M_MSG_LEN+1];
  Param_t *param = NULL;
  Param_t *param_save = NULL;
  Geoloc_t *geoloc = NULL;
  Kernel_t *kernel = NULL;
  Input_t *input = NULL;
  Scan_t *scan = NULL;
  Space_t *output_space = NULL;
  Patches_t *patches = NULL;
  int iscan, kscan;
  int il, nl;
  Output_t *output = NULL;
  Img_coord_double_t img;
  Geo_coord_t geo;
  FILE_ID *MasterGeoMem;    /* Output GeoTiff file */
  FILE *rbfile = NULL;       /* Output Raw Binary file */
  char HDF_File[1024], CharThisPid[256], FinalFileName[1024];
  Output_t output_mem;       /* Contains output HDF file */
  int32 exec_resamp, ThisPid; 
  char filename[1024];       /* name of raw binary file to be written to */
  time_t startdate, enddate;  /* start and end date struct */
  bool file_created;         /* was the current HDF file created? */

  /* Initialize the log file */
  InitLogHandler();

  /* Print the MRTSwath header */
  LogInfomsg(
     "*******************************************************************"
     "***********\n");
  sprintf(msg, "%s (%s)\n", RESAMPLER_NAME, RESAMPLER_VERSION);
  LogInfomsg(msg);
  startdate = time(NULL);
  sprintf(msg, "Start Time:  %s", ctime(&startdate));
  LogInfomsg(msg);
  LogInfomsg(
  "------------------------------------------------------------------\n");

  /* Get runtime parameters */
  if (NeedHelp(argc, argv))
    exit(EXIT_SUCCESS);

  param_save = GetParam(argc, argv);
  if (param_save == (Param_t *)NULL)
    LOG_ERROR("getting runtime parameters", "main");

  /* Print out the user-specified processing information */
  PrintParam(param_save);

  /* Loop through all the SDSs */
  for (curr_sds = 0; curr_sds < param_save->num_input_sds; curr_sds++)
  {
    /* Loop through all the bands in the current SDS */
    for (curr_band = 0; curr_band < param_save->input_sds_nbands[curr_sds];
         curr_band++)
    {
      /* Is this band one that should be processed? */
      if (!param_save->input_sds_bands[curr_sds][curr_band])
        continue;

      /* Assume the HDF file does not need to be created */
      file_created = false;

      /* Get a copy of the user parameters */
      param = CopyParam(param_save);
      if (param == (Param_t *)NULL)
        LOG_ERROR("copying runtime parameters", "main");

      /* Create the input_sds_name which is "SDSname, band" */
      if (param->input_sds_nbands[curr_sds] == 1)
      {
        /* 2D product so the band number is not needed */
        sprintf(tmp_sds_name, "%s", param->input_sds_name_list[curr_sds]);
      }
      else
      {
        /* 3D product so the band number is required */
        sprintf(tmp_sds_name, "%s, %d", param->input_sds_name_list[curr_sds],
          curr_band);
      }

      param->input_sds_name = strdup (tmp_sds_name);
      if (param->input_sds_name == NULL)
        LOG_ERROR("error creating input SDS band name", "main");
      sprintf(msg, "\nProcessing %s ...\n", param->input_sds_name);
      LogInfomsg(msg);

      /* Update the system to process the current SDS and band */
      if (!update_sds_info(curr_sds, param))
        LOG_ERROR("error updating SDS information", "main");

      /* Open input file for the specified SDS and band */
      input = OpenInput(param->input_file_name, param->input_sds_name, 
        param->iband, param->rank[curr_sds], param->dim[curr_sds], errstr);
      if (input == (Input_t *)NULL) {
        /* This is an invalid SDS for our processing so skip to the next
           SDS. We will only process SDSs that are at the 1km, 500m, or
           250m resolution (i.e. a factor of 1, 2, or 4 compared to the
           1km geolocation lat/long data). We also only process CHAR8,
           INT8, UINT8, INT16, and UINT16 data types. */
        LOG_WARNING(errstr, "main");
        LOG_WARNING("not processing SDS/band", "main");
        break;
      }

      /* Setup kernel */
      kernel = GenKernel(param->kernel_type);
      if (kernel == (Kernel_t *)NULL)
        LOG_ERROR("generating kernel", "main");

      /* Open geoloc file */
      geoloc = OpenGeolocSwath(param->geoloc_file_name);
      if (geoloc == (Geoloc_t *)NULL)
        LOG_ERROR("bad geolocation file", "main");

      /* Setup input scan */
      scan = SetupScan(geoloc, input, kernel);
      if (scan == (Scan_t *)NULL)
        LOG_ERROR("setting up scan data structure", "main");

      /* Set up the output space, using the current pixel size and
         number of lines and samples based on the current SDS (pixel size
         and number of lines and samples are the same for all the bands
         in the SDS) */
      param->output_space_def.img_size.l = param->output_img_size[curr_sds].l;
      param->output_space_def.img_size.s = param->output_img_size[curr_sds].s;
      param->output_space_def.pixel_size = param->output_pixel_size[curr_sds];
      sprintf(msg, "  output lines/samples: %d %d\n",
        param->output_space_def.img_size.l, param->output_space_def.img_size.s);
      LogInfomsg(msg);
      if (param->output_space_def.proj_num == PROJ_GEO)
      {
        sprintf(msg, "  output pixel size: %.4f\n",
          param->output_space_def.pixel_size * DEG);
	LogInfomsg(msg);
      }
      else
      {
        sprintf(msg, "  output pixel size: %.4f\n",
          param->output_space_def.pixel_size);
	LogInfomsg(msg);
      }
      LogInfomsg("  output data type: ");
      switch (param->output_data_type)
      {
          case DFNT_CHAR8:
              LogInfomsg("CHAR8\n");
              break;
          case DFNT_UINT8:
              LogInfomsg("UINT8\n");
              break;
          case DFNT_INT8:
              LogInfomsg("INT8\n");
              break;
          case DFNT_UINT16:
              LogInfomsg("UINT16\n");
              break;
          case DFNT_INT16:
              LogInfomsg("INT16\n");
              break;
          case DFNT_UINT32:
              LogInfomsg("UINT32\n");
              break;
          case DFNT_INT32:
              LogInfomsg("INT32\n");
              break;
          default:
              LogInfomsg("same as input\n");
              break;
      }

      output_space = SetupSpace(&param->output_space_def);
      if (output_space == (Space_t *)NULL) 
        LOG_ERROR("setting up output space", "main");

      /* Compute and print out the corners */
      img.is_fill = false;
      img.l = img.s = 0.0;
      if (!FromSpace(output_space, &img, &geo)) 
      {
        LOG_WARNING("unable to compute upper left corner", "main");
      }
      else
      {
        sprintf(msg,
          "  output upper left corner: lat %13.8f  long %13.8f\n", 
          (DEG * geo.lat), (DEG * geo.lon));
	LogInfomsg(msg);
      }

      img.is_fill = false;
      img.l = output_space->def.img_size.l - 1; 
      img.s = output_space->def.img_size.s - 1;
      if (!FromSpace(output_space, &img, &geo)) 
      {
        LOG_WARNING("unable to compute lower right corner", "main");
      }
      else
      {
        sprintf(msg,
          "  output lower right corner: lat %13.8f  long %13.8f\n", 
          (DEG * geo.lat), (DEG * geo.lon));
        LogInfomsg(msg);
      }

      /* If output data type not specified, then set to input data type
         (changes from SDS to SDS) */
      if (param->output_data_type == -1) 
        param->output_data_type = input->sds.type;

      /* Save the data type of this SDS for output to the metadata */
      param_save->output_dt_arr[curr_sds] = param->output_data_type;

      /* Setup intermediate patches. Setup as the input data type. Then we
         will convert to the output data type later. */
      patches = SetupPatches(&param->output_space_def.img_size, 
        param->patches_file_name, input->sds.type, input->fill_value, input->factor, input->offset);
      if (patches == (Patches_t *)NULL) 
        LOG_ERROR("setting up intermediate patches data structure","main");

      if (param->input_space_type != SWATH_SPACE)
        LOG_ERROR("input space type is not SWATH", "main");

      sprintf(msg, "  input lines/samples: %d %d\n", input->size.l,
        input->size.s);
      LogInfomsg(msg);
      sprintf(msg, "  input scale factor: %g\n", input->factor);
      LogInfomsg(msg);
      sprintf(msg, "  input offset: %lg\n", input->offset);
      LogInfomsg(msg);
      switch (input->ires)
      {
        case 1:
          LogInfomsg("  input resolution: 1 km\n");
          break;
        case 2:
          LogInfomsg("  input resolution: 500 m\n");
          break;
        case 4:
          LogInfomsg("  input resolution: 250 m\n");
          break;
      }
      LogInfomsg("  %% complete: 0%");

      /* For each input scan */
      kscan = 0;
      for (iscan = 0; iscan < geoloc->nscan; iscan++)
      {
        /* Update status? */
        if (100 * iscan / geoloc->nscan > kscan)
        {
          kscan = 100 * iscan / geoloc->nscan;
          if (kscan % 10 == 0)
          {
            sprintf(msg, " %d%%", kscan);
            LogInfomsg(msg);
	  }
        }

        /* Read the geolocation data for the scan and map to output space */
        if (!GetGeolocSwath(geoloc, output_space, iscan)) 
          LOG_ERROR("reading geolocation for a scan", "main");

        /* Map scan to input resolution */
        if (!MapScanSwath(scan, geoloc)) 
          LOG_ERROR("mapping a scan (swath)", "main");

        /* Extend the scan */
        if (!ExtendScan(scan)) LOG_ERROR("extending the scan", "main");

        /* Read input scan data into extended scan */
        il = iscan * input->scan_size.l;
        nl = input->scan_size.l;
        if (il + nl > input->size.l)
          nl = input->size.l - il;

        if (!GetScanInput(scan, input, il, nl))
          LOG_ERROR("reading input data for a scan", "main");

        /* Resample all of the points in the extended scan */
        if (!ProcessScan(scan, kernel, patches, nl, param->kernel_type))
          LOG_ERROR("resampling a scan", "main");

        /* Toss patches that were not touched */
        if (!TossPatches(patches, param->output_data_type))
          LOG_ERROR("writting patches to disk", "main");

      } /* End loop for each input scan */

      /* Finish the status message */
      LogInfomsg(" 100%\n");

      /* Save the background fill value from the patches data structure for
         output to the metadata */
      param_save->fill_value[curr_sds] = patches->fill_value;

      /* If output is raw binary, then we need the patches information
         so write the header before deleting the patches info */
      if (param->output_file_format == RB_FMT)
      { /* Output is raw binary */
        /* Create the raw binary header file */
        if (!WriteHeaderFile (param, patches))
          LOG_ERROR("writing raw binary header file", "main");
      }

      /* Done with scan and kernel strutures */
      if (!FreeScan(scan))
        LOG_ERROR("freeing scan structure", "main");
      if (!FreeKernel(kernel))
        LOG_ERROR("freeing kernel structure", "main");

      /* Close geolocation file */
      if (!CloseGeoloc(geoloc))
         LOG_ERROR("closing geolocation file", "main");

      /* Close input file */
      if (!CloseInput(input)) LOG_ERROR("closing input file", "main");

      /* Free the output space structure */
      if (!FreeSpace(output_space)) 
        LOG_ERROR("freeing output space structure", "main");

      /* Write remaining patches in memory to disk */
      if (!UntouchPatches(patches)) 
        LOG_ERROR("untouching patches", "main");
      if (!TossPatches(patches, param->output_data_type))
        LOG_ERROR("writting remaining patches to disk", "main");
      if (!FreePatchesInMem(patches))
        LOG_ERROR("freeing patches data structure in memory", "main");

      /* Output format can be HDF, GeoTiff, raw binary, or both HDF and
         GeoTiff */
      if (param->output_file_format == HDF_FMT ||
          param->output_file_format == BOTH)
      { /* Output is HDF */
        /* Create output file. If the output has multiple resolutions, then
           the resolution value will be used as an extension to the basename.
           Otherwise no resolution extension will be used. */
        if (param->multires)
        {
          if (param->output_space_def.proj_num != PROJ_GEO)
            /* Output the pixel size with only two decimal places, since
               the pixel size will be in meters */
            sprintf(HDF_File, "%s_%dm.hdf", param->output_file_name,
              (int) param->output_pixel_size[curr_sds]);
          else
            /* Output the pixel size with four decimal places, since the
               pixel size will be in degrees (need to convert from radians) */
            sprintf(HDF_File, "%s_%.04fd.hdf", param->output_file_name,
              param->output_pixel_size[curr_sds] * DEG);
        }
        else
        {
          sprintf(HDF_File, "%s.hdf", param->output_file_name);
        }

        /* Does the HDF file need to be created? */
        if (param->create_output[curr_sds])
        {
          /* Create the output HDF file */
          if (!CreateOutput(HDF_File))
            LOG_ERROR("creating output image file", "main");
          file_created = true;

          /* Loop through the rest of the SDSs and unmark the ones of the same
             resolution, since they will be output to this same HDF file
             and therefore do not need to be recreated. */
          for (k = curr_sds; k < param_save->num_input_sds; k++)
          {
            if (param->output_pixel_size[k] ==
                param->output_pixel_size[curr_sds])
              param_save->create_output[k] = false;
          }
        }

        /* Open output file */
        output = OutputFile(HDF_File, param->output_sds_name,
          param->output_data_type, &param->output_space_def);
        if (output == (Output_t *)NULL)
          LOG_ERROR("opening output HDF file", "main");
      }

      if (param->output_file_format == GEOTIFF_FMT ||
          param->output_file_format == BOTH)
      { /* Output is geotiff */
        /* Attach the SDS name to the output file name */
        if (param->output_file_format == GEOTIFF_FMT)
        {
          output = &output_mem;
          output->size.l = param->output_space_def.img_size.l;
          output->size.s = param->output_space_def.img_size.s;
          output->open   = true;
        }

        /* Open and initialize the GeoTiff File */
        MasterGeoMem = Open_GEOTIFF(param);
        if( ! MasterGeoMem ) {
           LOG_ERROR("allocating GeoTiff file id structure", "main");
        } else if( MasterGeoMem->error ) {
           LOG_ERROR(MasterGeoMem->error_msg, "main");
        }

/* Remove due to clash of tiff and hdf header files.
 *        if (!OpenGeoTIFFFile (param, &MasterGeoMem))
 *         LOG_ERROR("opening and initializing GeoTiff file", "main");
 */
      }

      if (param->output_file_format == RB_FMT)
      { /* Output is raw binary */
        output = &output_mem;
        output->size.l = param->output_space_def.img_size.l;
        output->size.s = param->output_space_def.img_size.s;
        output->open   = true;

        /* Get the size of the data type */
        switch (param->output_data_type)
        {
          case DFNT_INT8:
          case DFNT_UINT8:
            /* one byte in size */
            output->output_dt_size = 1;
            break;

          case DFNT_INT16:
          case DFNT_UINT16:
            /* two bytes in size */
            output->output_dt_size = 2;
            break;

          case DFNT_INT32:
          case DFNT_UINT32:
          case DFNT_FLOAT32:
            /* four bytes in size */
            output->output_dt_size = 4;
            break;
        }

        /* Copy the SDS name and remove any '/'s in the SDSname */
        j = 0;
        for (i = 0; i < (int)strlen(param->output_sds_name); i++)
        {
          if (param->output_sds_name[i] != '/' &&
              param->output_sds_name[i] != '\\')
          {
            sdsname[j++] = param->output_sds_name[i];
          }
          sdsname[j] = '\0';
        }

        /* Remove any spaces (from the SDS name) from the name */
        k = 0;
        while (sdsname[k])
        {
          if (isspace(sdsname[k]))
            sdsname[k] = '_';
          k++;
        }

        /* Add the SDS band name and dat extension to the filename */
        sprintf(filename, "%s_%s.dat", param->output_file_name,
          sdsname);

        rbfile = fopen(filename, "wb");
        if (rbfile == NULL)
          LOG_ERROR("opening output raw binary file", "main");
      }

      /* Read patches (in input data type) and write to output file (in
         output data type). If NN kernel, then fill any holes left from the
         resampling process. */
      if (!UnscramblePatches(patches, output, param->output_file_format,
          MasterGeoMem, rbfile, param->output_data_type, param->kernel_type))
        LOG_ERROR("unscrambling the output file", "main");

      /* Done with the patches */
      if (!FreePatches(patches))
        LOG_ERROR("freeing patches", "main");

      /* Close output HDF file */
      if (param->output_file_format == HDF_FMT ||
          param->output_file_format == BOTH)
      {
        if (!CloseOutput(output))
          LOG_ERROR("closing output file", "main");

        /* If not appending, write metadata to output HDF file */
        if (file_created)
        {
          if (!WriteMeta(output->file_name, &param->output_space_def)) 
            LOG_ERROR("writing metadata", "main");
        }
      }

      /* Close output GeoTiff file */
      if (param->output_file_format == GEOTIFF_FMT ||
          param->output_file_format == BOTH)
      {
        Close_GEOTIFF( MasterGeoMem );
        /* CloseGeoTIFFFile(&MasterGeoMem); */
        output->open = false;
      }

      /* Close output raw binary file */
      if (param->output_file_format == RB_FMT)
      {
        fclose(rbfile);
        output->open = false;
      }

      /* Free remaining memory */
      if (!FreeGeoloc(geoloc)) 
        LOG_ERROR("freeing geoloc file stucture", "main");
      if (!FreeInput(input)) 
        LOG_ERROR("freeing input file stucture", "main");
      if (param->output_file_format == HDF_FMT ||
          param->output_file_format == BOTH) {
        if (!FreeOutput(output)) 
          LOG_ERROR("freeing output file stucture", "main");
      }

      /* Get rid of patches file */
      ThisPid = getpid();
      sprintf(CharThisPid,"%d",(int)ThisPid);
      strcpy(FinalFileName,param->patches_file_name);
      strcat(FinalFileName,CharThisPid);

      exec_resamp = remove(FinalFileName);
      if(exec_resamp == -1)
      {
        LOG_ERROR("Something bad happened deleting patches file", "main");
      }  

      /* Free the parameter structure */
      if (!FreeParam(param)) 
        LOG_ERROR("freeing user parameter structure", "main");
    } /* loop through bands in the current SDS */
  } /* loop through SDSs */

  /* If output format is HDF then append the metadata, for all resolutions */
  if (param_save->output_file_format == HDF_FMT ||
      param_save->output_file_format == BOTH)
  {
    /* Initialize the create_output structure again for all the SDSs. This
       will be used to determine if the metadata needs to be appended. */
    for (curr_sds = 0; curr_sds < param_save->num_input_sds; curr_sds++)
      param_save->create_output[curr_sds] = true;

    /* Loop through all the SDSs */
    for (curr_sds = 0; curr_sds < param_save->num_input_sds; curr_sds++)
    {
      /* Do we need to append the metadata or has it already been done for
         the current SDSs HDF file? */
      if (!param_save->create_output[curr_sds])
        continue;

      /* Determine the name of the output HDF file */
      if (param_save->multires)
      {
        if (param_save->output_space_def.proj_num != PROJ_GEO)
          /* Output the pixel size with only two decimal places, since
             the pixel size will be in meters */
          sprintf(HDF_File, "%s_%dm.hdf", param_save->output_file_name,
            (int) param_save->output_pixel_size[curr_sds]);
        else
          /* Output the pixel size with four decimal places, since the
             pixel size will be in degrees (need to convert from radians) */
          sprintf(HDF_File, "%s_%.04fd.hdf", param_save->output_file_name,
            param_save->output_pixel_size[curr_sds] * DEG);
      }
      else
      {
        sprintf(HDF_File, "%s.hdf", param_save->output_file_name);
      }

      /* Append the metadata for this HDF file, only for the SDSs of the
         current resolution */
      if (!AppendMetadata(param_save, HDF_File, param_save->input_file_name,
        curr_sds)) 
      {
          /* NOTE: We won't flag this as an error, since in some cases the
             resolution file may not exist.  For example, if a MOD02HKM is
             specified and the Latitude or Longitude data is specified, then
             that data is at a different resolution (1000m) than the rest of
             the image SDS data (500m).  The software will think that there
             should be a 1000m product, however the Latitude and Longitude
             data didn't actually get processed .... since it is float data.
             So, AppendMetadata will flag an error since that HDF file will
             not really exist. */
/*        LOG_ERROR("appending metadata to the output HDF file","main"); */
      }

      /* Loop through the rest of the SDSs and unmark the ones of the same
         resolution, since they will be output to this same HDF file
         and therefore do not need to be recreated. */
      for (k = curr_sds; k < param_save->num_input_sds; k++)
      {
        if (param_save->output_pixel_size[k] ==
            param_save->output_pixel_size[curr_sds])
          param_save->create_output[k] = false;
      }
    }
  }

  /* Free the saved parameter structure */
  if (!FreeParam(param_save))
    LOG_ERROR("freeing saved user parameter structure", "main");

  /* Stop timer and print elapsed time */
  enddate = time(NULL);
  sprintf(msg, "\nEnd Time:  %s", ctime(&enddate));
  LogInfomsg(msg);
  LogInfomsg("Finished processing!\n");
  LogInfomsg( 
    "*********************************************************************"
    "*********\n");

  /* Close the log file */
  CloseLogHandler();

  /* All done */
  exit (EXIT_SUCCESS);
}