static char help[] = "\n";
/* 
  Include "petscmat.h" so that we can use matrices.
  automatically includes:
     petsc.h       - base PETSc routines   petscvec.h    - vectors
     petscsys.h    - system routines       petscmat.h    - matrices
     petscis.h     - index sets            petscviewer.h - viewers               
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "petscmat.h"
#include "petsctime.h"

#include "petsc_matvec_utils.h"
#include "tmm_forcing_utils.h"
#include "tmm_external_forcing.h"
#include "tmm_external_bc.h"
#include "tmm_timer.h"
#include "tmm_profile_utils.h"
#include "tmm_profile_data.h"
#include "tmm_monitor.h"
#include "tmm_misfit.h"
#include "tmm_main.h"

PetscScalar deltaTClock, time0;
PetscInt maxSteps, Iter0, writeSteps;
PetscInt *gIndices, gLow, gHigh;
PetscInt *gBCIndices, lBCSize, gBCSize, gbcLow, gbcHigh;
PetscBool doMisfit = PETSC_FALSE;

extern PetscErrorCode forwardStep(PetscScalar tc, PetscInt iLoop, PetscScalar dt, PetscInt numTracers, 
                                  PetscBool useForcingFromFile, PetscBool useExternalForcing, PetscBool usePrescribedBC, 
                                  Vec *v, Mat Ae, Mat Ai, Mat Be, Mat Bi, Vec *uf, Vec *uef, Vec *bcc, Vec *bcf, Vec *vtmp);

extern PetscErrorCode waitForSignal(PetscInt waitTime);

#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc,char **args)
{
  PetscInt numTracers, n;
  Vec templateVec;
  Vec *v, *vtmp;
/* TM's */
  Mat Ae, Ai;
  PeriodicMat Aep, Aip;
  char mateFile[PETSC_MAX_PATH_LEN], matiFile[PETSC_MAX_PATH_LEN], rfsFile[PETSC_MAX_PATH_LEN];
  PetscBool periodicMatrix = PETSC_FALSE;
  PeriodicTimer matrixTimer;
  
/* Forcing */
  Vec *uf, *uef;
  PeriodicVec up[MAXNUMTRACERS];
  char *forcingFile[MAXNUMTRACERS];
  PeriodicTimer forcingTimer;
  PetscInt numForcing;
  Vec **utdf;
  PetscScalar *tdfT; /* array for time dependent (nonperiodic) forcing */
  PetscScalar tf0, tf1;

/* Rescale forcing */
  Vec Rfs;
  PeriodicVec Rfsp;
  
/* BC's */
  Vec *bcc, *bcf;
  PeriodicVec bcp[MAXNUMTRACERS];
  char *bcFile[MAXNUMTRACERS];
  PetscInt numBC;
  Vec **bctd;
  PetscScalar *tdbcT; /* array for time dependent (nonperiodic) forcing */
  PeriodicTimer bcTimer;  
  PetscScalar tbc0, tbc1;
  PetscInt bcCutOffStep = -1;
  Mat Be, Bi;
  PeriodicMat Bep, Bip;
  char matbeFile[PETSC_MAX_PATH_LEN], matbiFile[PETSC_MAX_PATH_LEN];
  Vec bcTemplateVec;
  
/* I/O   */
  char *iniFile[MAXNUMTRACERS];  
  char *outFile[MAXNUMTRACERS];  
  char *bcoutFile[MAXNUMTRACERS];
  char *ufoutFile[MAXNUMTRACERS], *uefoutFile[MAXNUMTRACERS];
  char pickupFile[PETSC_MAX_PATH_LEN];
  char pickupoutFile[PETSC_MAX_PATH_LEN];  
  char outTimeFile[PETSC_MAX_PATH_LEN];  
  PetscBool appendOutput = PETSC_FALSE;
  PetscBool doWriteBC = PETSC_FALSE;
  PetscBool doWriteUF = PETSC_FALSE;
  PetscBool doWriteUEF = PETSC_FALSE;
  PetscBool pickupFromFile = PETSC_FALSE;
  PetscBool doTimeAverage = PETSC_FALSE;
  StepTimer avgTimer;
  char *avgOutFile[MAXNUMTRACERS];  
  Vec *vavg;
  PetscViewer fdavgout[MAXNUMTRACERS];
  char *bcavgOutFile[MAXNUMTRACERS];
  Vec *bcavg;
  PetscViewer fdbcavgout[MAXNUMTRACERS];
  char *ufavgOutFile[MAXNUMTRACERS], *uefavgOutFile[MAXNUMTRACERS];
  Vec *ufavg, *uefavg;
  PetscViewer fdufavgout[MAXNUMTRACERS], fduefavgout[MAXNUMTRACERS];
  FILE *fptime;
  PetscViewer fd, fdp, fdout[MAXNUMTRACERS];
  PetscViewer fdbcout[MAXNUMTRACERS], fdufout[MAXNUMTRACERS], fduefout[MAXNUMTRACERS];

#if defined (FORSPINUP) || defined (FORJACOBIAN)
  PetscViewer fdin[MAXNUMTRACERS];
  PetscInt itjac;
  PetscInt fp;  
#endif
  
/* run time options */
  PetscBool useExternalForcing = PETSC_FALSE;
  PetscBool useForcingFromFile = PETSC_FALSE;
  PetscBool usePrescribedBC = PETSC_FALSE;
  PetscBool applyBC = PETSC_FALSE;  
  PetscBool periodicForcing = PETSC_FALSE;
  PetscBool timeDependentForcing = PETSC_FALSE;
  PetscBool constantForcing = PETSC_FALSE;
  PetscBool periodicBC = PETSC_FALSE;
  PetscBool timeDependentBC = PETSC_FALSE;
  PetscBool constantBC = PETSC_FALSE;
  PetscBool doCalcBC = PETSC_FALSE;
  PetscBool rescaleForcing = PETSC_FALSE;
  PetscBool useMonitor = PETSC_FALSE;

  PetscMPIInt numProcessors, myId;  
  PetscErrorCode ierr;
  PetscBool flg1,flg2;
  PetscScalar t1, t2, tc, tf;
  PetscInt iLoop, Iterc;
  PetscInt it;
  PetscInt itr, maxValsToRead;
  char tmpFile[PETSC_MAX_PATH_LEN];
  PetscScalar zero = 0.0, one = 1.0;
  PetscInt il;
  
  PetscInitialize(&argc,&args,(char *)0,help);
  ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&myId);CHKERRQ(ierr);
  ierr = MPI_Comm_size(PETSC_COMM_WORLD,&numProcessors);CHKERRQ(ierr);  
  myId=myId+1; /* process ID (starting at 1) */

  PetscPushErrorHandler(PetscAbortErrorHandler,NULL); /* force code to abort on error */

/* Some defaults */
  time0=0.0;
  deltaTClock=1.0;
  Iter0=0;  
 
  numTracers=1;
  
/* Process options and load files */  
/* Number of tracers */
  ierr = PetscOptionsGetInt(PETSC_NULL,"-numtracers",&numTracers,&flg1);CHKERRQ(ierr);
  if (numTracers>MAXNUMTRACERS) {
   SETERRQ(PETSC_COMM_WORLD,1,"Number of tracers exceeds maximum allowable. Please increase the variable MAXNUMTRACERS and recompile");
  }  
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Number of tracers to be integrated: %d\n", numTracers);CHKERRQ(ierr); 

/* Time step data */
  ierr = PetscOptionsGetReal(PETSC_NULL,"-deltat_clock",&deltaTClock,&flg1);CHKERRQ(ierr);

  ierr = PetscOptionsGetReal(PETSC_NULL,"-t0",&time0,&flg1);CHKERRQ(ierr);  
  ierr = PetscOptionsGetInt(PETSC_NULL,"-iter0",&Iter0,&flg2);CHKERRQ(ierr);
  if ((flg1) && (!flg2)) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate both or neither time0 and Iter0 with the -t0 and -iter0 flags");
  if ((!flg1) && (flg2)) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate both or neither time0 and Iter0 with the -t0 and -iter0 flags");        
  ierr = PetscOptionsGetInt(PETSC_NULL,"-max_steps",&maxSteps,&flg1);CHKERRQ(ierr);
  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate maximum number of steps with the -max_steps option");
  ierr = PetscOptionsGetInt(PETSC_NULL,"-write_steps",&writeSteps,&flg1);CHKERRQ(ierr);
  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate output step with the -write_steps option");

/*Data for time averaging */
  ierr = PetscOptionsHasName(PETSC_NULL,"-time_avg",&doTimeAverage);CHKERRQ(ierr);
  if (doTimeAverage) {
    ierr = iniStepTimer("avg_", Iter0, &avgTimer);CHKERRQ(ierr);
//     avgStartTimeStep = Iter0 + 1; /* by default we start accumulating at first time step */
//     ierr = PetscOptionsGetInt(PETSC_NULL,"-avg_start_time_step",&avgStartTimeStep,&flg1);CHKERRQ(ierr);
//     ierr = PetscOptionsGetInt(PETSC_NULL,"-avg_time_steps",&avgNumTimeSteps,&flg1);CHKERRQ(ierr);
//     if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate number of time averaging time steps with the -avg_time_step flag");
	for (itr=0; itr<numTracers; itr++) {
	  avgOutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
	}
	maxValsToRead = numTracers;
	ierr = PetscOptionsGetStringArray(PETSC_NULL,"-avg_files",avgOutFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
	if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate file name(s) for writing time averages with the -avg_files option");
	if (maxValsToRead != numTracers) {
	  SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of time average file names specified");
	}  
	ierr = PetscPrintf(PETSC_COMM_WORLD,"Time averages will be computed starting at (and including) time step: %d\n", avgTimer.startTimeStep);CHKERRQ(ierr);
	ierr = PetscPrintf(PETSC_COMM_WORLD,"Time averages will be computed over %d time steps\n", avgTimer.numTimeSteps);CHKERRQ(ierr);	
	ierr = PetscPrintf(PETSC_COMM_WORLD,"Time averages will be written to:\n");CHKERRQ(ierr);
	for (itr=0; itr<numTracers; itr++) {
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,avgOutFile[itr]);CHKERRQ(ierr);
	}      
  }
  
/* Initialize profile data and create template vector */
  ierr = iniProfileData(myId);CHKERRQ(ierr);
  if (useProfiles) {
    ierr = VecCreate(PETSC_COMM_WORLD,&templateVec);CHKERRQ(ierr);
    ierr = VecSetSizes(templateVec,lSize,PETSC_DECIDE);CHKERRQ(ierr);
    ierr = VecSetFromOptions(templateVec);CHKERRQ(ierr);
    ierr = VecGetSize(templateVec,&n);CHKERRQ(ierr);
  }

#if defined (FORSPINUP) || defined (FORJACOBIAN)
  ierr = waitForSignal(0);CHKERRQ(ierr); /* initialize */
#endif

/* Matrices */
  ierr = PetscOptionsGetString(PETSC_NULL,"-me",mateFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate binary matrix file with the -me option");
  ierr = PetscOptionsGetString(PETSC_NULL,"-mi",matiFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate binary matrix file with the -mi options");

  ierr = MatCreate(PETSC_COMM_WORLD,&Ae);CHKERRQ(ierr);
  ierr = MatCreate(PETSC_COMM_WORLD,&Ai);CHKERRQ(ierr);

/*  Set layout information */  
  if ((useProfiles) && (numProcessors>1)) {
	ierr = MatSetSizes(Ae,lSize,lSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
	ierr = MatSetSizes(Ai,lSize,lSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
  }   
  
  ierr = MatSetType(Ae,MATMPIAIJ);CHKERRQ(ierr);      
  ierr = MatSetFromOptions(Ae);CHKERRQ(ierr);  
  ierr = MatSetType(Ai,MATMPIAIJ);CHKERRQ(ierr);        
  ierr = MatSetFromOptions(Ai);CHKERRQ(ierr);
  
  ierr = PetscOptionsHasName(PETSC_NULL,"-periodic_matrix",&periodicMatrix);CHKERRQ(ierr);  
  if (periodicMatrix) {    
    ierr=PetscPrintf(PETSC_COMM_WORLD,"Periodic matrices specified\n");CHKERRQ(ierr);
    ierr=PetscStrcat(mateFile,"_");CHKERRQ(ierr);
    ierr=PetscStrcat(matiFile,"_");CHKERRQ(ierr);
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Ae basename is %s\n", mateFile);CHKERRQ(ierr); 
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Ai basename is %s\n", matiFile);CHKERRQ(ierr);     
    
/*  read time data */
    ierr = iniPeriodicTimer("matrix_", &matrixTimer);CHKERRQ(ierr);
//     ierr = PetscOptionsGetReal(PETSC_NULL,"-matrix_cycle_period",&matrixCyclePeriod,&flg2);CHKERRQ(ierr);
//     if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate matrix cycling time with the -matrix_cycle_period option");
//     ierr = PetscOptionsGetReal(PETSC_NULL,"-matrix_cycle_step",&matrixCycleStep,&flg2);CHKERRQ(ierr);
//     if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate cycling step with the -matrix_cycle_step option");
//     numMatrixPeriods=matrixCyclePeriod/matrixCycleStep;
/*  array for holding extended time array */
//     PetscMalloc((numMatrixPeriods+2)*sizeof(PetscScalar), &tdpMatrix); 
//     ierr = PetscPrintf(PETSC_COMM_WORLD,"Periodic matrix specified at times:\n");CHKERRQ(ierr);            
//     for (it=0; it<=numMatrixPeriods+1; it++) {
//       tdpMatrix[it]=(-matrixCycleStep/2.0) + it*matrixCycleStep;
//       ierr = PetscPrintf(PETSC_COMM_WORLD,"tdpMatrix=%10.5f\n", tdpMatrix[it]);CHKERRQ(ierr);        
//     }    
    
/*  Read here to set sparsity pattern */
	strcpy(tmpFile,"");
	sprintf(tmpFile,"%s%02d",mateFile,0);
	ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,tmpFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	ierr = MatLoad(Ae,fd);CHKERRQ(ierr);
	ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

	strcpy(tmpFile,"");
	sprintf(tmpFile,"%s%02d",matiFile,0);
	ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,tmpFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	ierr = MatLoad(Ai,fd);CHKERRQ(ierr);
	ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);    

    Aep.firstTime = PETSC_TRUE;
    Aip.firstTime = PETSC_TRUE;
    
  } else { /*  not periodic. read matrices here */

	ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,mateFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	ierr = PetscPrintf(PETSC_COMM_WORLD,"Reading Ae from file %s\n", mateFile);CHKERRQ(ierr);  
	ierr = MatLoad(Ae,fd);CHKERRQ(ierr);
	ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

	ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,matiFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	ierr = PetscPrintf(PETSC_COMM_WORLD,"Reading Ai from file %s\n", matiFile);CHKERRQ(ierr);  
	ierr = MatLoad(Ai,fd);CHKERRQ(ierr);    
	ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);      
    
  }

/* create template vector here if not using profiles */
  if (!useProfiles) {
    ierr = MatGetSize(Ae,0,&n);CHKERRQ(ierr);
    ierr = VecCreate(PETSC_COMM_WORLD,&templateVec);CHKERRQ(ierr);
    ierr = VecSetSizes(templateVec,PETSC_DECIDE,n);CHKERRQ(ierr);
    ierr = VecSetFromOptions(templateVec);CHKERRQ(ierr);
    ierr = VecGetLocalSize(templateVec,&lSize);CHKERRQ(ierr); /* lSize is otherwise set in iniProfiles */
  }  
  
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Matrix size is %d x %d\n", n,n);CHKERRQ(ierr);  

/*   Compute global indices for local piece of vectors */
  ierr = VecGetOwnershipRange(templateVec,&gLow,&gHigh);CHKERRQ(ierr);
  gHigh = gHigh - 1; /* Note: gHigh is one more than the last local element */
  ierr = PetscMalloc(lSize*sizeof(PetscInt),&gIndices);CHKERRQ(ierr);  
  for (il=0; il<lSize; il++) {
    gIndices[il] = il + gLow;
  }  

/* Output file */
  for (itr=0; itr<numTracers; itr++) {
    outFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
  }
  maxValsToRead = numTracers;
  ierr = PetscOptionsGetStringArray(PETSC_NULL,"-o",outFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate output file name(s) with the -o option");
  if (maxValsToRead != numTracers) {
    SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of output file names specified");
  }  
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Output will be written to:\n");CHKERRQ(ierr);
  for (itr=0; itr<numTracers; itr++) {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,outFile[itr]);CHKERRQ(ierr);
  }  
  ierr = PetscOptionsHasName(PETSC_NULL,"-append",&appendOutput);CHKERRQ(ierr);
  if (appendOutput) {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Output will be appended\n");CHKERRQ(ierr);
  } else {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Output will overwrite existing file(s)\n");CHKERRQ(ierr);
  }    

/* Output times */
  ierr = PetscOptionsGetString(PETSC_NULL,"-time_file",outTimeFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
  if (!flg1) {
	strcpy(outTimeFile,"");
    sprintf(outTimeFile,"%s","output_time.txt");
  }
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Output times will be written to %s\n",outTimeFile);CHKERRQ(ierr);

/* File name for final pickup */
  ierr = PetscOptionsGetString(PETSC_NULL,"-pickup_out",pickupoutFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
  if (!flg1) {
	strcpy(pickupoutFile,"");
    sprintf(pickupoutFile,"%s","pickup.petsc");
  }
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Final pickup will be written to %s\n",pickupoutFile);CHKERRQ(ierr);

/* tracer vectors */
  ierr = VecDuplicateVecs(templateVec,numTracers,&v);CHKERRQ(ierr);
  ierr = VecDuplicateVecs(templateVec,numTracers,&vtmp);CHKERRQ(ierr); /* temporary work space needed by forwardStep */

/* Initial condition     */
  for (itr=0; itr<numTracers; itr++) {
    iniFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
  }
  ierr = PetscOptionsGetString(PETSC_NULL,"-pickup",pickupFile,PETSC_MAX_PATH_LEN-1,&pickupFromFile);CHKERRQ(ierr);
  if (pickupFromFile) {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Pickup file has been specified\n");CHKERRQ(ierr);
    ierr = PetscPrintf(PETSC_COMM_WORLD,"  Reading initial conditions from %s\n", pickupFile);CHKERRQ(ierr);
    ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,pickupFile,FILE_MODE_READ,&fdp);CHKERRQ(ierr);
    for (itr=0; itr<numTracers; itr++) {
      ierr = VecLoad(v[itr],fdp);CHKERRQ(ierr); /* IntoVector */
    }
    ierr = PetscViewerDestroy(&fdp);CHKERRQ(ierr);          
  } else {
    maxValsToRead = numTracers;
    ierr = PetscOptionsGetStringArray(PETSC_NULL,"-i",iniFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
    if (flg1) {  /* read from file */
      if (maxValsToRead != numTracers) {
        SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of input file names specified");
      }      
#if defined (FORSPINUP) || defined (FORJACOBIAN)
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Waiting for new initial condition ...\n");CHKERRQ(ierr);
      ierr = waitForSignal(10);CHKERRQ(ierr);
#endif	  
      for (itr=0; itr<numTracers; itr++) {
        ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading initial condition from file %s\n", itr,iniFile[itr]);CHKERRQ(ierr);
        ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
        ierr = VecLoad(v[itr],fd);CHKERRQ(ierr);/* IntoVector */
        ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);          
      }  
    } else {  /* set to zero */
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting initial condition to zero\n");CHKERRQ(ierr);
      for (itr=0; itr<numTracers; itr++) {
        VecSet(v[itr],zero);
      }        
    }
  }

/* Forcing/RHS   */
/* The tracer(s) can be forced in 3 ways (any combination of which can be turned on): */
/* 1) Forcing term read from file (can be periodic, constant, or time-dependent) */
/* 2) External forcing computed in S/R calcExternalForcing */
/* 3) Prescribed boundary condition (can be periodic, constant, or time-dependent) */
  ierr = PetscOptionsHasName(PETSC_NULL,"-forcing_from_file",&useForcingFromFile);CHKERRQ(ierr);
  ierr = PetscOptionsHasName(PETSC_NULL,"-prescribed_bc",&usePrescribedBC);CHKERRQ(ierr);
  ierr = PetscOptionsHasName(PETSC_NULL,"-external_forcing",&useExternalForcing);CHKERRQ(ierr);

/*   if (useExternalForcing) { */
/*     if ((useForcingFromFile) | (usePrescribedBC)) { */
/*       SETERRQ(PETSC_COMM_WORLD,1,"Cannot use the -external_forcing option with the -forcing_from_file or -prescribed_bc options");   */
/*     }   */
/*   } */

  if (useForcingFromFile) {  
  	ierr=PetscPrintf(PETSC_COMM_WORLD,"Forcing from file(s) specified\n");CHKERRQ(ierr);  
	for (itr=0; itr<numTracers; itr++) {
	  forcingFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
	}
	maxValsToRead = numTracers;
	ierr = PetscOptionsGetStringArray(PETSC_NULL,"-forcing_files",forcingFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
	if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"MUST specify forcing files with the -forcing_files option");
    if (maxValsToRead != numTracers) {
      SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of forcing file names specified");
    }    
    ierr = VecDuplicateVecs(templateVec,numTracers,&uf);CHKERRQ(ierr);    
/*  There are 3 possibilities: periodic, constant, and time-dependent forcing */
    ierr = PetscOptionsHasName(PETSC_NULL,"-periodic_forcing",&periodicForcing);CHKERRQ(ierr);
    if (periodicForcing) {
/*    Read some info. Forcing is read in interpPeriodicForcing. */
      numForcing=-1;
      ierr=PetscPrintf(PETSC_COMM_WORLD,"Periodic forcing from file(s) specified\n");CHKERRQ(ierr);
      for (itr=0; itr<numTracers; itr++) {
        ierr=PetscStrcat(forcingFile[itr],"_");CHKERRQ(ierr);        
	    ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d periodic forcing basename is %s\n",itr,forcingFile[itr]);CHKERRQ(ierr); 
        up[itr].firstTime = PETSC_TRUE; /* initialize periodic vector */        	    
      }      

/*    read time data */
      ierr = iniPeriodicTimer("forcing_", &forcingTimer);CHKERRQ(ierr);
//       ierr = PetscOptionsGetReal(PETSC_NULL,"-forcing_cycle_period",&forcingCyclePeriod,&flg2);CHKERRQ(ierr);
//       if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate forcing cycling time with the -forcing_cycle_period option");
//       ierr = PetscOptionsGetReal(PETSC_NULL,"-forcing_cycle_step",&forcingCycleStep,&flg2);CHKERRQ(ierr);
//       if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate cycling step with the -forcing_cycle_step option");
//       numForcingPeriods=forcingCyclePeriod/forcingCycleStep;
/*    array for holding extended time array */
//       PetscMalloc((numForcingPeriods+2)*sizeof(PetscScalar), &tdpForcing); 
//       ierr = PetscPrintf(PETSC_COMM_WORLD,"Periodic forcing specified at times:\n");CHKERRQ(ierr);            
//       for (it=0; it<=numForcingPeriods+1; it++) {
//         tdpForcing[it]=(-forcingCycleStep/2.0) + it*forcingCycleStep;
//         ierr = PetscPrintf(PETSC_COMM_WORLD,"tdpForcing=%10.5f\n", tdpForcing[it]);CHKERRQ(ierr);        
//       }
    } else { /* constant or (nonperiodic) time dependent forcing */
/*    Read info AND forcing here */    
      ierr = PetscOptionsHasName(PETSC_NULL,"-time_dependent_forcing",&timeDependentForcing);CHKERRQ(ierr);
      if (timeDependentForcing) {      
        ierr=PetscPrintf(PETSC_COMM_WORLD,"Time dependent forcing specified\n");CHKERRQ(ierr);
        ierr = PetscOptionsGetInt(PETSC_NULL,"-number_forcing_vecs",&numForcing,&flg2);CHKERRQ(ierr);
        if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate number of forcing vectors in file with the -number_forcing_vecs option");
/*      Make sure we have all the time info         */
        ierr = PetscOptionsGetReal(PETSC_NULL,"-t0",&time0,&flg2);CHKERRQ(ierr);
        if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate initial time with the -t0 option");
        ierr = PetscOptionsGetReal(PETSC_NULL,"-deltat_clock",&deltaTClock,&flg2);CHKERRQ(ierr);
        if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate time step with the -deltat_clock option");      
        ierr = PetscOptionsGetReal(PETSC_NULL,"-tfini",&tf0,&flg2);CHKERRQ(ierr);
        if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate first forcing time with the -tfini option");
        ierr = PetscOptionsGetReal(PETSC_NULL,"-tfend",&tf1,&flg2);CHKERRQ(ierr);
        if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate last forcing time with the -tfend option");        
        utdf = malloc(numTracers*sizeof(Vec *));
        for (itr=0; itr<numTracers; itr++) {   
          ierr = VecDuplicateVecs(templateVec,numForcing,&utdf[itr]);CHKERRQ(ierr);
          ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading forcing from file %s\n", itr,forcingFile[itr]);CHKERRQ(ierr);
          ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,forcingFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
          for (it=0; it<numForcing; it++) {
            ierr = VecLoad(utdf[itr][it],fd);CHKERRQ(ierr); /* IntoVector */
          }
          ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
          ierr = PetscPrintf(PETSC_COMM_WORLD,"   Read %d forcing vectors\n", numForcing);CHKERRQ(ierr);            
        }
        PetscMalloc(numForcing*sizeof(PetscScalar), &tdfT); 
        ierr = PetscPrintf(PETSC_COMM_WORLD,"Time dependent forcing specified at times:\n");CHKERRQ(ierr);        
        for (it=0; it<numForcing; it++) {
          tdfT[it] = tf0 + ((tf1-tf0)/(numForcing-1.0))*it;
          ierr = PetscPrintf(PETSC_COMM_WORLD,"tdfT=%10.5f\n", tdfT[it]);CHKERRQ(ierr);        
        }
      } else { /* constant forcing */
        ierr=PetscPrintf(PETSC_COMM_WORLD,"Constant forcing specified\n");CHKERRQ(ierr);      
        constantForcing = PETSC_TRUE;
        numForcing=1;
		for (itr=0; itr<numTracers; itr++) {   
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading forcing from file %s\n", itr,forcingFile[itr]);CHKERRQ(ierr);
		  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,forcingFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
		  ierr = VecLoad(uf[itr],fd);CHKERRQ(ierr); /* IntoVector */
		  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"   Read %d forcing vectors\n", numForcing);CHKERRQ(ierr);            
		}
      }  /* TD/constant forcing */
    }  /* periodic/nonperiodic forcing */

/*  Initialize data to write out uf */
    if ((periodicForcing) || (timeDependentForcing)) {
	  for (itr=0; itr<numTracers; itr++) {
		ufoutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
	  }
	  maxValsToRead = numTracers;
	  ierr = PetscOptionsGetStringArray(PETSC_NULL,"-ouf",ufoutFile,&maxValsToRead,&doWriteUF);CHKERRQ(ierr);
	  if (doWriteUF) {
		if (maxValsToRead != numTracers) {
		  SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of forcing-from-file (uf) output file names specified");
		}  
		ierr = PetscPrintf(PETSC_COMM_WORLD,"Forcing-from-file (uf) output will be written to:\n");CHKERRQ(ierr);
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,ufoutFile[itr]);CHKERRQ(ierr);
		}
		ierr = PetscPrintf(PETSC_COMM_WORLD,"Note: forcing-from-file (uf) output is discrete in time. Divide by the appropriate time step to obtain a tendency\n");CHKERRQ(ierr);
		ierr = PetscPrintf(PETSC_COMM_WORLD,"Note: forcing-from-file (uf) output is shifted by one time step relative to the stated output time step\n");CHKERRQ(ierr);
		if (doTimeAverage) {
		  for (itr=0; itr<numTracers; itr++) {
			ufavgOutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
		  }
		  maxValsToRead = numTracers;
		  ierr = PetscOptionsGetStringArray(PETSC_NULL,"-ufavg_files",ufavgOutFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
		  if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate file name(s) for writing time averages with the -ufavg_files option");
		  if (maxValsToRead != numTracers) {
			SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of forcing-from-file (uf) time average file names specified");
		  }  
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"Forcing-from-file (uf) time averages will be written to:\n");CHKERRQ(ierr);
		  for (itr=0; itr<numTracers; itr++) {
			ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,ufavgOutFile[itr]);CHKERRQ(ierr);
		  }      
		}
	  }
    }
  } else {  /* no forcing */
    numForcing=0;
    ierr = PetscPrintf(PETSC_COMM_WORLD,"No forcing from file(s) specified\n");CHKERRQ(ierr);    
  }

  if (useExternalForcing) {  /* external forcing present */  
    ierr = PetscPrintf(PETSC_COMM_WORLD,"External forcing is being used\n");CHKERRQ(ierr);    
    ierr = VecDuplicateVecs(templateVec,numTracers,&uef);CHKERRQ(ierr);        
    ierr = iniExternalForcing(time0,Iter0,numTracers,v,uef);CHKERRQ(ierr);

/*  Initialize data to write out uef */
	for (itr=0; itr<numTracers; itr++) {
	  uefoutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
	}
	maxValsToRead = numTracers;
	ierr = PetscOptionsGetStringArray(PETSC_NULL,"-ouef",uefoutFile,&maxValsToRead,&doWriteUEF);CHKERRQ(ierr);
	if (doWriteUEF) {
	  if (maxValsToRead != numTracers) {
		SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of external forcing (uef) output file names specified");
	  }  
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"External forcing (uef) output will be written to:\n");CHKERRQ(ierr);
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,uefoutFile[itr]);CHKERRQ(ierr);
	  }
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Note: external forcing (uef) output is discrete in time. Divide by the appropriate time step to obtain a tendency\n");CHKERRQ(ierr);	  
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Note: external forcing (uef) output is shifted by one time step relative to the stated output time step\n");CHKERRQ(ierr);
      if (doTimeAverage) {
		for (itr=0; itr<numTracers; itr++) {
		  uefavgOutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
		}
		maxValsToRead = numTracers;
		ierr = PetscOptionsGetStringArray(PETSC_NULL,"-uefavg_files",uefavgOutFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
		if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate file name(s) for writing time averages with the -uefavg_files option");
		if (maxValsToRead != numTracers) {
		  SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of external forcing (uef) time average file names specified");
		}  
		ierr = PetscPrintf(PETSC_COMM_WORLD,"External forcing (uef) time averages will be written to:\n");CHKERRQ(ierr);
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,uefavgOutFile[itr]);CHKERRQ(ierr);
		}      
	  }
    }
    
  } else {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"No external forcing is being used\n");CHKERRQ(ierr);  
  }  

/* Prescribed BCs   */
  if (usePrescribedBC) {
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Prescribed BC's specified\n");CHKERRQ(ierr);    

	ierr = VecCreate(PETSC_COMM_WORLD,&bcTemplateVec);CHKERRQ(ierr);
    
    ierr = PetscOptionsHasName(PETSC_NULL,"-calc_bc",&doCalcBC);CHKERRQ(ierr);
    if (doCalcBC) {
      ierr = PetscPrintf(PETSC_COMM_WORLD,"BCs will be calculated\n");CHKERRQ(ierr);    

      if ((useProfiles) && (numProcessors>1)) {
        lBCSize = lNumProfiles;
        ierr = VecSetSizes(bcTemplateVec,lBCSize,PETSC_DECIDE);CHKERRQ(ierr);      
        ierr = VecSetFromOptions(bcTemplateVec);CHKERRQ(ierr);
        ierr = VecGetSize(bcTemplateVec,&gBCSize);CHKERRQ(ierr);
      } else {
        ierr = PetscOptionsGetInt(PETSC_NULL,"-bc_vec_size",&gBCSize,&flg1);CHKERRQ(ierr);
        if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate size of BC vector with the -bc_vec_size option");
        ierr = VecSetSizes(bcTemplateVec,PETSC_DECIDE,gBCSize);CHKERRQ(ierr);      
        ierr = VecSetFromOptions(bcTemplateVec);CHKERRQ(ierr);
        ierr = VecGetLocalSize(bcTemplateVec,&lBCSize);CHKERRQ(ierr);    
      }

	  ierr = VecGetOwnershipRange(bcTemplateVec,&gbcLow,&gbcHigh);CHKERRQ(ierr);
	  gbcHigh = gbcHigh - 1; /* Note: gbcHigh is one more than the last local element */
	  ierr = PetscMalloc(lBCSize*sizeof(PetscInt),&gBCIndices);CHKERRQ(ierr);  
	  for (il=0; il<lBCSize; il++) {
		gBCIndices[il] = il + gbcLow;
	  }
      
      ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcc);CHKERRQ(ierr);    
      ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcf);CHKERRQ(ierr);    

      ierr = iniCalcBC(time0,Iter0,time0+deltaTClock,Iter0+1,numTracers,v,bcc,bcf);CHKERRQ(ierr);
      
    } else { /* read from file */
      for (itr=0; itr<numTracers; itr++) {
        bcFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
      }
      maxValsToRead = numTracers;
      ierr = PetscOptionsGetStringArray(PETSC_NULL,"-bc_files",bcFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
      if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"MUST specify BC files with the -bc_files option");
      if (maxValsToRead != numTracers) {
        SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of BC file names specified");
      }    

/*    There are 3 possibilities: periodic, constant, and time-dependent BCs */
      ierr = PetscOptionsHasName(PETSC_NULL,"-periodic_bc",&periodicBC);CHKERRQ(ierr);
      if (periodicBC) {
/*      Read some info. BC is read in interpPeriodicVector */
        ierr=PetscPrintf(PETSC_COMM_WORLD,"Periodic BC from file(s) specified\n");CHKERRQ(ierr);
        for (itr=0; itr<numTracers; itr++) {
          ierr=PetscStrcat(bcFile[itr],"_");CHKERRQ(ierr);        
          ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d periodic BC basename is %s\n",itr,bcFile[itr]);CHKERRQ(ierr); 
          bcp[itr].firstTime = PETSC_TRUE; /* initialize periodic vector */        	    
        }      

/*      Load one vector here as a template */
        strcpy(tmpFile,"");
        sprintf(tmpFile,"%s%02d",bcFile[0],0);
        ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,tmpFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
        ierr = VecLoad(bcTemplateVec,fd);CHKERRQ(ierr);
        ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
        ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcc);CHKERRQ(ierr);    
        ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcf);CHKERRQ(ierr);    

/*      read time data */
        ierr = iniPeriodicTimer("bc_", &bcTimer);CHKERRQ(ierr);
//         ierr = PetscOptionsGetReal(PETSC_NULL,"-bc_cycle_period",&bcCyclePeriod,&flg2);CHKERRQ(ierr);
//         if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate BC cycling time with the -bc_cycle_period option");
//         ierr = PetscOptionsGetReal(PETSC_NULL,"-bc_cycle_step",&bcCycleStep,&flg2);CHKERRQ(ierr);
//         if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate cycling step with the -bc_cycle_step option");
//         numBCPeriods=bcCyclePeriod/bcCycleStep;
/*      array for holding extended time array */
//         PetscMalloc((numBCPeriods+2)*sizeof(PetscScalar), &tdpBC); 
//         ierr = PetscPrintf(PETSC_COMM_WORLD,"Periodic BC specified at times:\n");CHKERRQ(ierr);            
//         for (it=0; it<=numBCPeriods+1; it++) {
//           tdpBC[it]=(-bcCycleStep/2.0) + it*bcCycleStep;
//           ierr = PetscPrintf(PETSC_COMM_WORLD,"tdpBC=%10.5f\n", tdpBC[it]);CHKERRQ(ierr);        
//         }
      } else { /* constant or (nonperiodic) time dependent BC */
/*      Read info AND BC here */    
        ierr = PetscOptionsHasName(PETSC_NULL,"-time_dependent_bc",&timeDependentBC);CHKERRQ(ierr);
        if (timeDependentBC) {      
          ierr=PetscPrintf(PETSC_COMM_WORLD,"Time dependent BC specified\n");CHKERRQ(ierr);
          ierr = PetscOptionsGetInt(PETSC_NULL,"-number_bc_vecs",&numBC,&flg2);CHKERRQ(ierr);
          if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate number of BC vectors in file with the -number_bc_vecs option");
/*        Make sure we have all the time info         */
          ierr = PetscOptionsGetReal(PETSC_NULL,"-t0",&time0,&flg2);CHKERRQ(ierr);
          if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate initial time with the -t0 option");
          ierr = PetscOptionsGetReal(PETSC_NULL,"-deltat_clock",&deltaTClock,&flg2);CHKERRQ(ierr);
          if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate time step with the -deltat_clock option");      
          ierr = PetscOptionsGetReal(PETSC_NULL,"-tbcini",&tbc0,&flg2);CHKERRQ(ierr);
          if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate first BC time with the -tbcini option");
          ierr = PetscOptionsGetReal(PETSC_NULL,"-tbcend",&tbc1,&flg2);CHKERRQ(ierr);
          if (!flg2) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate last BC time with the -tbcend option");        

/*        Load one vector here as a template */
          ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcFile[0],FILE_MODE_READ,&fd);CHKERRQ(ierr);
          ierr = VecLoad(bcTemplateVec,fd);CHKERRQ(ierr);
          ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
          ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcc);CHKERRQ(ierr);    
          ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcf);CHKERRQ(ierr);    
        
          bctd = malloc(numTracers*sizeof(Vec *));
          for (itr=0; itr<numTracers; itr++) {   
            ierr = VecDuplicateVecs(bcTemplateVec,numBC,&bctd[itr]);CHKERRQ(ierr);
            ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading BC from file %s\n", itr,bcFile[itr]);CHKERRQ(ierr);
            ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
            for (it=0; it<numBC; it++) {
              ierr = VecLoad(bctd[itr][it],fd);CHKERRQ(ierr); /* IntoVector */
            }
            ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
            ierr = PetscPrintf(PETSC_COMM_WORLD,"   Read %d BC vectors\n", numBC);CHKERRQ(ierr);            
          }
          PetscMalloc(numBC*sizeof(PetscScalar), &tdbcT); 
          ierr = PetscPrintf(PETSC_COMM_WORLD,"Time dependent BC specified at times:\n");CHKERRQ(ierr);        
          for (it=0; it<numBC; it++) {
            tdbcT[it] = tbc0 + ((tbc1-tbc0)/(numBC-1.0))*it;
            ierr = PetscPrintf(PETSC_COMM_WORLD,"tdbcT=%10.5f\n", tdbcT[it]);CHKERRQ(ierr);        
          }
        } else { /* constant BC */
          ierr=PetscPrintf(PETSC_COMM_WORLD,"Constant BC specified\n");CHKERRQ(ierr);      
          constantBC = PETSC_TRUE;
          numBC=1;
/*        Load one vector here as a template */
          ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcFile[0],FILE_MODE_READ,&fd);CHKERRQ(ierr);
          ierr = VecLoad(bcTemplateVec,fd);CHKERRQ(ierr);
          ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
          ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcc);CHKERRQ(ierr);    
          ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcf);CHKERRQ(ierr);            
          for (itr=0; itr<numTracers; itr++) {   
            ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading BC from file %s\n", itr,bcFile[itr]);CHKERRQ(ierr);
            ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
            ierr = VecLoad(bcc[itr],fd);CHKERRQ(ierr); /* IntoVector */
            ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
            ierr = PetscPrintf(PETSC_COMM_WORLD,"   Read %d BC vectors\n", numBC);CHKERRQ(ierr);            
            ierr = VecCopy(bcc[itr],bcf[itr]);CHKERRQ(ierr);		  
          }
        }  /* TD/constant BC */
      }  /* periodic/nonperiodic BC */
    }

    ierr = VecGetLocalSize(bcTemplateVec,&lBCSize);CHKERRQ(ierr); /* just to be safe */

    if ((useProfiles) && (numProcessors>1)) {
      if (lBCSize != lNumProfiles) {
        SETERRQ(PETSC_COMM_WORLD,1,"Problem with partitioning of BC vectors! lNumProfiles must equal lBCSize");
      }
    }
    
    applyBC = PETSC_TRUE;

    ierr = PetscOptionsGetInt(PETSC_NULL,"-bc_cutoff_step",&bcCutOffStep,&flg1);CHKERRQ(ierr);
    if (bcCutOffStep>0) {
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Prescribed BC will be turned off after time step %d\n",bcCutOffStep);CHKERRQ(ierr);    
    }

/*  BC output file */
	for (itr=0; itr<numTracers; itr++) {
	  bcoutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
	}
	maxValsToRead = numTracers;
	ierr = PetscOptionsGetStringArray(PETSC_NULL,"-obc",bcoutFile,&maxValsToRead,&doWriteBC);CHKERRQ(ierr);
	if (doWriteBC) {
	  if (maxValsToRead != numTracers) {
		SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of BC output file names specified");
	  }  
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"BC output will be written to:\n");CHKERRQ(ierr);
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,bcoutFile[itr]);CHKERRQ(ierr);
	  }
      if (doTimeAverage) {
		for (itr=0; itr<numTracers; itr++) {
		  bcavgOutFile[itr] = (char *) malloc(PETSC_MAX_PATH_LEN*sizeof(char));
		}
		maxValsToRead = numTracers;
		ierr = PetscOptionsGetStringArray(PETSC_NULL,"-bcavg_files",bcavgOutFile,&maxValsToRead,&flg1);CHKERRQ(ierr);
		if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate file name(s) for writing time averages with the -bcavg_files option");
		if (maxValsToRead != numTracers) {
		  SETERRQ(PETSC_COMM_WORLD,1,"Insufficient number of BC time average file names specified");
		}  
		ierr = PetscPrintf(PETSC_COMM_WORLD,"BC time averages will be written to:\n");CHKERRQ(ierr);
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscPrintf(PETSC_COMM_WORLD,"   Tracer %d: %s\n", itr,bcavgOutFile[itr]);CHKERRQ(ierr);
		}      
	  }
    }
    
/*  Matrices */
	ierr = PetscOptionsGetString(PETSC_NULL,"-mbe",matbeFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
	if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate binary boundary matrix file name with the -mbe option");
	ierr = PetscOptionsGetString(PETSC_NULL,"-mbi",matbiFile,PETSC_MAX_PATH_LEN-1,&flg1);CHKERRQ(ierr);
	if (!flg1) SETERRQ(PETSC_COMM_WORLD,1,"Must indicate binary boundary matrix file name with the -mbi options");

	ierr = MatCreate(PETSC_COMM_WORLD,&Be);CHKERRQ(ierr);
	ierr = MatCreate(PETSC_COMM_WORLD,&Bi);CHKERRQ(ierr);	

/*  Set layout information */
	if ((useProfiles) && (numProcessors>1)) {
	  ierr = MatSetSizes(Be,lSize,lBCSize,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
	  ierr = MatSetSizes(Bi,lSize,lBCSize,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr);
	}		
	
	ierr = MatSetType(Be,MATMPIAIJ);CHKERRQ(ierr);      
	ierr = MatSetFromOptions(Be);CHKERRQ(ierr);  
	ierr = MatSetType(Bi,MATMPIAIJ);CHKERRQ(ierr);        
	ierr = MatSetFromOptions(Bi);CHKERRQ(ierr);
  
	if (periodicMatrix) {    
	  ierr=PetscPrintf(PETSC_COMM_WORLD,"Periodic boundary matrices specified\n");CHKERRQ(ierr);
	  ierr=PetscStrcat(matbeFile,"_");CHKERRQ(ierr);
	  ierr=PetscStrcat(matbiFile,"_");CHKERRQ(ierr);
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Be basename is %s\n", matbeFile);CHKERRQ(ierr); 
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Bi basename is %s\n", matbiFile);CHKERRQ(ierr);     

/*    Read here to set sparsity pattern */  
	  strcpy(tmpFile,"");
	  sprintf(tmpFile,"%s%02d",matbeFile,0);
	  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,tmpFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	  ierr = MatLoad(Be,fd);CHKERRQ(ierr);
	  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

	  strcpy(tmpFile,"");
	  sprintf(tmpFile,"%s%02d",matbiFile,0);
	  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,tmpFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	  ierr = MatLoad(Bi,fd);CHKERRQ(ierr);
	  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);    
    
	  Bep.firstTime = PETSC_TRUE;
	  Bip.firstTime = PETSC_TRUE;
    
    } else { /*  not periodic. read matrices here */

	  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,matbeFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Reading Be from file %s\n", matbeFile);CHKERRQ(ierr);  
	  ierr = MatLoad(Be,fd);CHKERRQ(ierr);
	  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

	  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,matbiFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Reading Bi from file %s\n", matbiFile);CHKERRQ(ierr);  
	  ierr = MatLoad(Bi,fd);CHKERRQ(ierr);    
	  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);      
	}
  } else {  /* no BC */
    numBC=0;
    ierr = PetscPrintf(PETSC_COMM_WORLD,"No prescribed BC's specified\n");CHKERRQ(ierr);  
  }  

  ierr = PetscOptionsGetString(PETSC_NULL,"-rescale_forcing_file",rfsFile,PETSC_MAX_PATH_LEN-1,&rescaleForcing);CHKERRQ(ierr);
  if (rescaleForcing) {  
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Forcing will be rescaled\n");CHKERRQ(ierr); 	    
    ierr = VecDuplicate(templateVec,&Rfs);CHKERRQ(ierr);    
	if (periodicMatrix) {    
	  ierr=PetscStrcat(rfsFile,"_");CHKERRQ(ierr);
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Rescale forcing factor file basename is %s\n", rfsFile);CHKERRQ(ierr); 	
	  Rfsp.firstTime = PETSC_TRUE;
	} else {
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Reading rescale forcing factor from file %s\n", rfsFile);CHKERRQ(ierr);  	
	  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,rfsFile,FILE_MODE_READ,&fd);CHKERRQ(ierr);
	  ierr = VecLoad(Rfs,fd);CHKERRQ(ierr);  
	  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);    
	}  
  }

/* initialize monitor */
  ierr = PetscOptionsHasName(PETSC_NULL,"-monitor",&useMonitor);CHKERRQ(ierr);
  if (useMonitor) {  
    ierr = iniMonitor(time0,Iter0,numTracers,v);CHKERRQ(ierr);
  }

/* initialize misfit */
  ierr = PetscOptionsHasName(PETSC_NULL,"-calc_misfit",&doMisfit);CHKERRQ(ierr);
  if (doMisfit) {  
    ierr = iniMisfit(time0,Iter0,numTracers,v);CHKERRQ(ierr);
  }

/* Open files for output and optionally write initial conditions */
#if !defined (FORSPINUP) && !defined (FORJACOBIAN)
  if (!appendOutput) {
    ierr = PetscFOpen(PETSC_COMM_WORLD,outTimeFile,"w",&fptime);CHKERRQ(ierr);  
    ierr = PetscFPrintf(PETSC_COMM_WORLD,fptime,"%d   %10.5f\n",Iter0,time0);CHKERRQ(ierr);     
    ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing output at time %10.5f, step %d\n", time0,Iter0);CHKERRQ(ierr);  
    for (itr=0; itr<numTracers; itr++) {       
      ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_WRITE,&fdout[itr]);CHKERRQ(ierr);
      ierr = VecView(v[itr],fdout[itr]);CHKERRQ(ierr);
    }

    if (doWriteUF) {
/*    We only open files here since uf may not yet have been updated */
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,ufoutFile[itr],FILE_MODE_WRITE,&fdufout[itr]);CHKERRQ(ierr);
	  }
    }

    if (doWriteUEF) {
/*    We only open files here since uef may not yet have been updated */
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,uefoutFile[itr],FILE_MODE_WRITE,&fduefout[itr]);CHKERRQ(ierr);
	  }
    }
    
    if (doWriteBC) {
/*    We only open files here since BCs may not yet have been computed */
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcoutFile[itr],FILE_MODE_WRITE,&fdbcout[itr]);CHKERRQ(ierr);
	  }
    }
  } else {
	  ierr = PetscFOpen(PETSC_COMM_WORLD,outTimeFile,"a",&fptime);CHKERRQ(ierr);  
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Opening file(s) for output. Initial condition will NOT be written\n");CHKERRQ(ierr);  
      for (itr=0; itr<numTracers; itr++) {       
        ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_APPEND,&fdout[itr]);CHKERRQ(ierr);
      }

      if (doWriteUF) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,ufoutFile[itr],FILE_MODE_APPEND,&fdufout[itr]);CHKERRQ(ierr);
		}
      }  

      if (doWriteUEF) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,uefoutFile[itr],FILE_MODE_APPEND,&fduefout[itr]);CHKERRQ(ierr);
		}
      }  
      
      if (doWriteBC) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcoutFile[itr],FILE_MODE_APPEND,&fdbcout[itr]);CHKERRQ(ierr);
		}
      }  
  }
#endif

  if (doTimeAverage) {  
    ierr = VecDuplicateVecs(templateVec,numTracers,&vavg);CHKERRQ(ierr);  
	for (itr=0; itr<numTracers; itr++) {
	  ierr = VecSet(vavg[itr],zero); CHKERRQ(ierr);
      ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,avgOutFile[itr],FILE_MODE_WRITE,&fdavgout[itr]);CHKERRQ(ierr);
    }
	if (doWriteUF) {
      ierr = VecDuplicateVecs(templateVec,numTracers,&ufavg);CHKERRQ(ierr);  	
	  for (itr=0; itr<numTracers; itr++) {
		ierr = VecSet(ufavg[itr],zero); CHKERRQ(ierr);
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,ufavgOutFile[itr],FILE_MODE_WRITE,&fdufavgout[itr]);CHKERRQ(ierr);
	  }
	}
	if (doWriteUEF) {
      ierr = VecDuplicateVecs(templateVec,numTracers,&uefavg);CHKERRQ(ierr);  	
	  for (itr=0; itr<numTracers; itr++) {
		ierr = VecSet(uefavg[itr],zero); CHKERRQ(ierr);
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,uefavgOutFile[itr],FILE_MODE_WRITE,&fduefavgout[itr]);CHKERRQ(ierr);
	  }
	}
	if (doWriteBC) {
      ierr = VecDuplicateVecs(bcTemplateVec,numTracers,&bcavg);CHKERRQ(ierr);  	
	  for (itr=0; itr<numTracers; itr++) {
		ierr = VecSet(bcavg[itr],zero); CHKERRQ(ierr);
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,bcavgOutFile[itr],FILE_MODE_WRITE,&fdbcavgout[itr]);CHKERRQ(ierr);
	  }
	}    
//     avgTimer.count=0;
  }

/* reinitialize forcing if required */
#ifdef FORSPINUP
  ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,"itjac.bin",FILE_MODE_READ,&fd);CHKERRQ(ierr);
  ierr = PetscViewerBinaryGetDescriptor(fd,&fp);CHKERRQ(ierr);
  ierr = PetscBinaryRead(fp,&itjac,1,PETSC_INT);CHKERRQ(ierr);  
  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

  ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting iteration number to: %d\n", itjac);CHKERRQ(ierr);

  tc=time0 + deltaTClock*(itjac-1);  /*  current time (time at beginning of step) */
  Iterc=Iter0+itjac-1;
  if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);      
  if (doCalcBC) ierr = reInitializeCalcBC(tc,Iterc,tc+deltaTClock,Iterc+1,numTracers,v,bcc,bcf);CHKERRQ(ierr);        
#endif

#ifdef FORJACOBIAN
  ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,"itjac.bin",FILE_MODE_READ,&fd);CHKERRQ(ierr);
  ierr = PetscViewerBinaryGetDescriptor(fd,&fp);CHKERRQ(ierr);
  ierr = PetscBinaryRead(fp,&itjac,1,PETSC_INT);CHKERRQ(ierr);  
  ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

  ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting iteration number to: %d\n", itjac);CHKERRQ(ierr);

  if (doTimeAverage) {  
    tc=time0 + deltaTClock*(itjac-1);  /*  current time (time at beginning of step) */
    Iterc=Iter0+itjac-1;
    if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);           
  } else {
    for (itr=0; itr<numTracers; itr++) {       
      ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_WRITE,&fdout[itr]);CHKERRQ(ierr);
      ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fdin[itr]);CHKERRQ(ierr);
    }
  }
#endif

/* Start time stepping loop */
  ierr = PetscTime(&t1);CHKERRQ(ierr); /* start counting wall clock time */  
  for (iLoop = 1; iLoop <= maxSteps; iLoop++) {
/*  iLoop -> iLoop+1 (convention) */  
#if !defined (FORSPINUP) && !defined (FORJACOBIAN)
    tc=time0 + deltaTClock*(iLoop-1);  /*  current time (time at beginning of step) */
    tf=time0 + deltaTClock*iLoop;  /*  future time (time at end of step) */
    Iterc=Iter0+iLoop-1;
#else
    tc=time0 + deltaTClock*(itjac-1);  /*  current time (time at beginning of step) */
    tf=time0 + deltaTClock*itjac;  /*  future time (time at end of step) */
    Iterc=Iter0+itjac-1;
    itjac++;    
#endif

#ifdef FORJACOBIAN
    if (!doTimeAverage) {
      for (itr=0; itr<numTracers; itr++) {
/* reread initial conditions (these were read once already above, but do it again since its easier to code) */    
        ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading initial condition from file %s\n", itr,iniFile[itr]);CHKERRQ(ierr);
        ierr = VecLoad(v[itr],fdin[itr]);CHKERRQ(ierr); /* IntoVector */
      } 
      if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);          
    }
#endif

#ifndef FORJACOBIAN
/*  interpolate Ae,Ai,uf,uef,bcc to current time (tc) and bcf to future time (tf) */
    if (periodicMatrix) {
      ierr = interpPeriodicMatrix(tc,&Ae,matrixTimer.cyclePeriod,matrixTimer.numPerPeriod,
                                  matrixTimer.tdp,&Aep,mateFile);
      ierr = interpPeriodicMatrix(tc,&Ai,matrixTimer.cyclePeriod,matrixTimer.numPerPeriod,
                                  matrixTimer.tdp,&Aip,matiFile);
      if (rescaleForcing) {
		ierr = interpPeriodicVector(tc,&Rfs,matrixTimer.cyclePeriod,matrixTimer.numPerPeriod,
                                  matrixTimer.tdp,&Rfsp,rfsFile);
      }
    }

/*  Forcing     */
    if (useForcingFromFile) {
	  if (periodicForcing) {
		for (itr=0; itr<numTracers; itr++) {    
		  ierr = interpPeriodicVector(tc,&uf[itr],forcingTimer.cyclePeriod,forcingTimer.numPerPeriod,forcingTimer.tdp,&up[itr],forcingFile[itr]);
		}    
	  } else if (timeDependentForcing) {
		ierr = interpTimeDependentVector(tc,uf,numTracers,numForcing,tdfT,utdf);CHKERRQ(ierr);
	  }
	  if (rescaleForcing) {
		for (itr=0; itr<numTracers; itr++) {    
          ierr = VecPointwiseMult(uf[itr],Rfs,uf[itr]);CHKERRQ(ierr);
        }  
	  }
	}
#endif

    if (useExternalForcing) {
      ierr = calcExternalForcing(tc,Iterc,iLoop,numTracers,v,uef);CHKERRQ(ierr); /* Compute external forcing in uef */
	  if (rescaleForcing) {
		for (itr=0; itr<numTracers; itr++) {    
          ierr = VecPointwiseMult(uef[itr],Rfs,uef[itr]);CHKERRQ(ierr);
        }  
	  }      
    }    

#ifndef FORJACOBIAN
    if (applyBC) {
      if ((bcCutOffStep>0) && (iLoop==(bcCutOffStep+1))) {
        applyBC = PETSC_FALSE;
        doCalcBC = PETSC_FALSE;
		for (itr=0; itr<numTracers; itr++) {
		  VecSet(bcc[itr],zero);
		  VecSet(bcf[itr],zero);
		}        
      } else {    
        if (periodicMatrix) {
          ierr = interpPeriodicMatrix(tc,&Be,matrixTimer.cyclePeriod,matrixTimer.numPerPeriod,
                                      matrixTimer.tdp,&Bep,matbeFile);
          ierr = interpPeriodicMatrix(tc,&Bi,matrixTimer.cyclePeriod,matrixTimer.numPerPeriod,
                                      matrixTimer.tdp,&Bip,matbiFile);
        }    
        if (periodicBC) {
          for (itr=0; itr<numTracers; itr++) {    
            ierr = interpPeriodicVector(tc,&bcc[itr],bcTimer.cyclePeriod,bcTimer.numPerPeriod,bcTimer.tdp,&bcp[itr],bcFile[itr]);
            ierr = interpPeriodicVector(tf,&bcf[itr],bcTimer.cyclePeriod,bcTimer.numPerPeriod,bcTimer.tdp,&bcp[itr],bcFile[itr]);
          }    
        } else if (timeDependentBC) {
          ierr = interpTimeDependentVector(tc,bcc,numTracers,numBC,tdbcT,bctd);CHKERRQ(ierr);
          ierr = interpTimeDependentVector(tf,bcf,numTracers,numBC,tdbcT,bctd);CHKERRQ(ierr);
        } else if (doCalcBC) {
          ierr = calcBC(tc,Iterc,tc+deltaTClock,Iterc+1,iLoop,numTracers,v,bcc,bcf);CHKERRQ(ierr); /* Compute BC in bcc and bcf */	  
        }
      }
	  
    }

/*  Write out BC at first time step */
	if (doWriteBC) {
	  if ((iLoop == 1) && (!appendOutput)) {	  
		for (itr=0; itr<numTracers; itr++) {
		  ierr = VecView(bcc[itr],fdbcout[itr]);CHKERRQ(ierr);
		}
	  }	
    }
        
    ierr = forwardStep(tc,Iterc,deltaTClock,numTracers,useForcingFromFile,useExternalForcing,applyBC,
                       v,Ae,Ai,Be,Bi,uf,uef,bcc,bcf,vtmp);CHKERRQ(ierr);
#endif    
    tc=time0 + deltaTClock*iLoop;  /*  time at end of step */    

    if (useMonitor) {
      ierr = updateMonitor(tc,iLoop,numTracers,v);CHKERRQ(ierr);
      ierr = writeMonitor(tc,iLoop,numTracers,v);CHKERRQ(ierr);
    }

    if (doMisfit) {
      ierr = calcMisfit(tc,iLoop,numTracers,v);CHKERRQ(ierr);
      ierr = writeMisfit(tc,iLoop,numTracers,v);CHKERRQ(ierr);
    }

/* write output */
#if !defined (FORSPINUP) && !defined (FORJACOBIAN)
    if (useExternalForcing) {
      ierr = writeExternalForcing(tc,iLoop,numTracers,v,uef);CHKERRQ(ierr);
    }
    if (doCalcBC) {
      ierr = writeBC(tc,iLoop,numTracers,v,bcc,bcf);CHKERRQ(ierr); 
    }
    if ((iLoop % writeSteps)==0) {  /*  time to write out */  /* ??? should this be Iter0+iLoop */
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing output at time %10.5f, step %d\n", tc, Iter0+iLoop);CHKERRQ(ierr);
      ierr = PetscFPrintf(PETSC_COMM_WORLD,fptime,"%d   %10.5f\n",Iter0+iLoop,tc);CHKERRQ(ierr);           
/*       ierr = PetscViewerASCIIPrintf(fdtime,"\n%d   %10.5f",Iter0+iLoop,tc);CHKERRQ(ierr);        */
      for (itr=0; itr<numTracers; itr++) {
        ierr = VecView(v[itr],fdout[itr]);CHKERRQ(ierr);
      }

	  if (doWriteUF) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = VecView(uf[itr],fdufout[itr]);CHKERRQ(ierr);
		}
	  }

	  if (doWriteUEF) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = VecView(uef[itr],fduefout[itr]);CHKERRQ(ierr);
		}
	  }
      
	  if (doWriteBC) {
		for (itr=0; itr<numTracers; itr++) {
		  ierr = VecView(bcf[itr],fdbcout[itr]);CHKERRQ(ierr);
		}
	  }
    }
#else
#ifdef FORSPINUP
    if ((iLoop % writeSteps)==0) {  /*  time to write out */  /* ??? should this be Iter0+iLoop */
	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing output at time %10.5f, step %d\n", tc, Iter0+iLoop);CHKERRQ(ierr);
	  for (itr=0; itr<numTracers; itr++) {       
		ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_WRITE,&fdout[itr]);CHKERRQ(ierr);
		ierr = VecView(v[itr],fdout[itr]);CHKERRQ(ierr);
        ierr = PetscViewerDestroy(&fdout[itr]);CHKERRQ(ierr);		
	  }

	  ierr = PetscPrintf(PETSC_COMM_WORLD,"Waiting for new initial condition ...\n");CHKERRQ(ierr);
      ierr = waitForSignal(10);CHKERRQ(ierr);

      for (itr=0; itr<numTracers; itr++) {
        ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading new initial condition from file %s\n", itr,iniFile[itr]);CHKERRQ(ierr);
        ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
        ierr = VecLoad(v[itr],fd);CHKERRQ(ierr); /* IntoVector */
        ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);          
      }        

      ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,"itjac.bin",FILE_MODE_READ,&fd);CHKERRQ(ierr);
      ierr = PetscViewerBinaryGetDescriptor(fd,&fp);CHKERRQ(ierr);
      ierr = PetscBinaryRead(fp,&itjac,1,PETSC_INT);CHKERRQ(ierr);  
      ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);

      ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting iteration number to: %d\n", itjac);CHKERRQ(ierr);

      tc=time0 + deltaTClock*(itjac-1);  /*  current time (time at beginning of step) */
      tf=time0 + deltaTClock*itjac;  /*  future time (time at end of step) */
      Iterc=Iter0+itjac-1;

      if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);      
      if (doCalcBC) ierr = reInitializeCalcBC(tc,Iterc,tc+deltaTClock,Iterc+1,numTracers,v,bcc,bcf);CHKERRQ(ierr);              
    }
#endif
#ifdef FORJACOBIAN
    if (doTimeAverage) {
      if ((iLoop % writeSteps)==0) {  /*  time to write out */  /* ??? should this be Iter0+iLoop */      
        if (Iter0+iLoop>=avgTimer.startTimeStep) { /* start time averaging (note: avgStartTimeStep is ABSOLUTE time step) */
          if (avgTimer.count<=avgTimer.numTimeSteps) { /* still within same averaging block so accumulate */
            for (itr=0; itr<numTracers; itr++) {
              ierr = VecAXPY(vavg[itr],one,uef[itr]);CHKERRQ(ierr);
            }          
            avgTimer.count++;
/*           ierr = PetscPrintf(PETSC_COMM_WORLD,"Accumulating: %d\n", iLoop);CHKERRQ(ierr);                       */
          }
          if (avgTimer.count==avgTimer.numTimeSteps) { /* time to write averages to file */
            ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing time average q at time %10.5f, step %d\n", tc, Iter0+iLoop);CHKERRQ(ierr);                      
            for (itr=0; itr<numTracers; itr++) {
              ierr = VecScale(vavg[itr],1.0/avgTimer.count);CHKERRQ(ierr);
              ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_WRITE,&fdout[itr]);CHKERRQ(ierr);            
              ierr = VecView(vavg[itr],fdout[itr]);CHKERRQ(ierr);              
              ierr = PetscViewerDestroy(&fdout[itr]);CHKERRQ(ierr);		              
              ierr = VecSet(vavg[itr],zero); CHKERRQ(ierr);
            }        
		    ierr = updateStepTimer("avg_", Iter0+iLoop, &avgTimer);CHKERRQ(ierr);              
//             avgTimer.count = 0;     

            ierr = PetscPrintf(PETSC_COMM_WORLD,"Waiting for new initial condition ...\n");CHKERRQ(ierr);
            ierr = waitForSignal(10);CHKERRQ(ierr);

            for (itr=0; itr<numTracers; itr++) {
              ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading new initial condition from file %s\n", itr,iniFile[itr]);CHKERRQ(ierr);
              ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
              ierr = VecLoad(v[itr],fd);CHKERRQ(ierr); /* IntoVector */
              ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);          
            }        
    
            ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,"itjac.bin",FILE_MODE_READ,&fd);CHKERRQ(ierr);
            ierr = PetscViewerBinaryGetDescriptor(fd,&fp);CHKERRQ(ierr);
            ierr = PetscBinaryRead(fp,&itjac,1,PETSC_INT);CHKERRQ(ierr);  
            ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);
      
            ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting iteration number to: %d\n", itjac);CHKERRQ(ierr);
      
            tc=time0 + deltaTClock*(itjac-1);  /*  current time (time at beginning of step) */
            tf=time0 + deltaTClock*itjac;  /*  future time (time at end of step) */
            Iterc=Iter0+itjac-1;
      
            if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);      
          
          } else {
          
            for (itr=0; itr<numTracers; itr++) {
              ierr = PetscPrintf(PETSC_COMM_WORLD,"Tracer %d: reading new initial condition from file %s\n", itr,iniFile[itr]);CHKERRQ(ierr);
              ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fd);CHKERRQ(ierr);
              ierr = VecLoad(v[itr],fd);CHKERRQ(ierr); /* IntoVector */
              ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);          
            }        

            tc=time0 + deltaTClock*(itjac-1);  /* this is now the time at end of time step */
            Iterc=Iter0+itjac-1;    
            if (useExternalForcing) ierr = reInitializeExternalForcing(tc,Iterc,numTracers,v,uef);CHKERRQ(ierr);                  
          }
        }
      }
    } else { /* no time averaging */
      ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing q at time %10.5f, step %d\n", tc, Iter0+iLoop);CHKERRQ(ierr);
      for (itr=0; itr<numTracers; itr++) {       
        ierr = VecView(uef[itr],fdout[itr]);CHKERRQ(ierr);
      }
      if ((iLoop % writeSteps)==0) {  /*  time to read new set of initial condition(s) */      
        for (itr=0; itr<numTracers; itr++) {       
          ierr = PetscViewerDestroy(&fdout[itr]);CHKERRQ(ierr);		
          ierr = PetscViewerDestroy(&fdin[itr]);CHKERRQ(ierr);          
        }
        ierr = PetscPrintf(PETSC_COMM_WORLD,"Waiting for new initial condition ...\n");CHKERRQ(ierr);
        ierr = waitForSignal(10);CHKERRQ(ierr);
/*      open files here for I/O */
        for (itr=0; itr<numTracers; itr++) {       
          ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,outFile[itr],FILE_MODE_WRITE,&fdout[itr]);CHKERRQ(ierr);
          ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,iniFile[itr],FILE_MODE_READ,&fdin[itr]);CHKERRQ(ierr);
        }
      }
      ierr = PetscViewerBinaryOpen(PETSC_COMM_SELF,"itjac.bin",FILE_MODE_READ,&fd);CHKERRQ(ierr);
      ierr = PetscViewerBinaryGetDescriptor(fd,&fp);CHKERRQ(ierr);
      ierr = PetscBinaryRead(fp,&itjac,1,PETSC_INT);CHKERRQ(ierr);  
      ierr = PetscViewerDestroy(&fd);CHKERRQ(ierr);          

      ierr = PetscPrintf(PETSC_COMM_WORLD,"Setting iteration number to: %d\n", itjac);CHKERRQ(ierr);              
    }	  
#endif
#endif
#ifndef FORJACOBIAN    
    if (doTimeAverage) {
      if (Iter0+iLoop>=avgTimer.startTimeStep) { /* start time averaging (note: avgStartTimeStep is ABSOLUTE time step) */
        if (avgTimer.count<=avgTimer.numTimeSteps) { /* still within same averaging block so accumulate */
/*           ierr = PetscPrintf(PETSC_COMM_WORLD,"Accumulating for time average\n");CHKERRQ(ierr);               */
		  for (itr=0; itr<numTracers; itr++) {
			ierr = VecAXPY(vavg[itr],one,v[itr]);CHKERRQ(ierr);
		  }   
		  if (doWriteUF) {
			for (itr=0; itr<numTracers; itr++) {
				ierr = VecAXPY(ufavg[itr],one,uf[itr]);CHKERRQ(ierr);
			}
		  }
		  if (doWriteUEF) {
			for (itr=0; itr<numTracers; itr++) {
				ierr = VecAXPY(uefavg[itr],one,uef[itr]);CHKERRQ(ierr);
			}
		  }
		  if (doWriteBC) {
			for (itr=0; itr<numTracers; itr++) {
				ierr = VecAXPY(bcavg[itr],one,bcf[itr]);CHKERRQ(ierr);
			}
		  }	
		  avgTimer.count++;
        }
        if (avgTimer.count==avgTimer.numTimeSteps) { /* time to write averages to file */
          ierr = PetscPrintf(PETSC_COMM_WORLD,"Writing time average at time %10.5f, step %d\n", tc, Iter0+iLoop);CHKERRQ(ierr);                      
		  for (itr=0; itr<numTracers; itr++) {
			ierr = VecScale(vavg[itr],1.0/avgTimer.count);CHKERRQ(ierr);
            ierr = VecView(vavg[itr],fdavgout[itr]);CHKERRQ(ierr);
            ierr = VecSet(vavg[itr],zero); CHKERRQ(ierr);
		  }
		  if (doWriteUF) {
			for (itr=0; itr<numTracers; itr++) {		  
			  ierr = VecScale(ufavg[itr],1.0/avgTimer.count);CHKERRQ(ierr);
			  ierr = VecView(ufavg[itr],fdufavgout[itr]);CHKERRQ(ierr);
			  ierr = VecSet(ufavg[itr],zero); CHKERRQ(ierr);
			}
		  }
		  if (doWriteUEF) {
			for (itr=0; itr<numTracers; itr++) {		  
			  ierr = VecScale(uefavg[itr],1.0/avgTimer.count);CHKERRQ(ierr);
			  ierr = VecView(uefavg[itr],fduefavgout[itr]);CHKERRQ(ierr);
			  ierr = VecSet(uefavg[itr],zero); CHKERRQ(ierr);
			}
		  }
		  if (doWriteBC) {
			for (itr=0; itr<numTracers; itr++) {		  
			  ierr = VecScale(bcavg[itr],1.0/avgTimer.count);CHKERRQ(ierr);
			  ierr = VecView(bcavg[itr],fdbcavgout[itr]);CHKERRQ(ierr);
			  ierr = VecSet(bcavg[itr],zero); CHKERRQ(ierr);
			}
		  }
		  ierr = updateStepTimer("avg_", Iter0+iLoop, &avgTimer);CHKERRQ(ierr);
//           avgTimer.count = 0;
        }
      }
    }
#endif    
  }  /* end of time-stepping loop */

#if !defined (FORSPINUP) && !defined (FORJACOBIAN)
  for (itr=0; itr<numTracers; itr++) {
    ierr = PetscViewerDestroy(&fdout[itr]);CHKERRQ(ierr);
  }
  ierr = PetscFClose(PETSC_COMM_WORLD,fptime);CHKERRQ(ierr);

  if (doWriteUF) {
	for (itr=0; itr<numTracers; itr++) {
	  ierr = PetscViewerDestroy(&fdufout[itr]);CHKERRQ(ierr);
	}  
  }

  if (doWriteUEF) {
	for (itr=0; itr<numTracers; itr++) {
	  ierr = PetscViewerDestroy(&fduefout[itr]);CHKERRQ(ierr);
	}  
  }
  
  if (doWriteBC) {
	for (itr=0; itr<numTracers; itr++) {
	  ierr = PetscViewerDestroy(&fdbcout[itr]);CHKERRQ(ierr);
	}  
  }
#endif

  if (doTimeAverage) {
	for (itr=0; itr<numTracers; itr++) {
	  ierr = PetscViewerDestroy(&fdavgout[itr]);CHKERRQ(ierr);
	}
	ierr = VecDestroyVecs(numTracers,&vavg);CHKERRQ(ierr);
	if (doWriteUF) {
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerDestroy(&fdufavgout[itr]);CHKERRQ(ierr);
	  }
	  ierr = VecDestroyVecs(numTracers,&ufavg);CHKERRQ(ierr);
	}
	if (doWriteUEF) {
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerDestroy(&fduefavgout[itr]);CHKERRQ(ierr);
	  }
	  ierr = VecDestroyVecs(numTracers,&uefavg);CHKERRQ(ierr);
	}
	if (doWriteBC) {
	  for (itr=0; itr<numTracers; itr++) {
		ierr = PetscViewerDestroy(&fdbcavgout[itr]);CHKERRQ(ierr);
	  }
	  ierr = VecDestroyVecs(numTracers,&bcavg);CHKERRQ(ierr);
	}
  }
  
/* write final pickup */  
  ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,pickupoutFile,FILE_MODE_WRITE,&fdp);CHKERRQ(ierr);
  for (itr=0; itr<numTracers; itr++) {
    ierr = VecView(v[itr],fdp);CHKERRQ(ierr);
  }
  ierr = PetscViewerDestroy(&fdp);CHKERRQ(ierr);      
  
  ierr=PetscTime(&t2); CHKERRQ(ierr); /* stop counting wall clock time */
  ierr = PetscPrintf(PETSC_COMM_WORLD,"Wall clock time: %10.5f\n", t2-t1);CHKERRQ(ierr); 
  
  /* Free data structures */
  ierr = VecDestroyVecs(numTracers,&v);CHKERRQ(ierr);  
  ierr = VecDestroyVecs(numTracers,&vtmp);CHKERRQ(ierr);
  ierr = MatDestroy(&Ae);CHKERRQ(ierr);
  ierr = MatDestroy(&Ai);CHKERRQ(ierr);

  if (periodicMatrix) {
    ierr = destroyPeriodicMat(&Aep);CHKERRQ(ierr);
    ierr = destroyPeriodicMat(&Aip);CHKERRQ(ierr);    
  }

  if (rescaleForcing) {
	ierr = VecDestroy(&Rfs);CHKERRQ(ierr);
	if (periodicMatrix) {
      ierr = destroyPeriodicVec(&Rfsp);CHKERRQ(ierr);
    }	
  }
  
  if (useMonitor) {
	ierr = finalizeMonitor(tc,maxSteps,numTracers);CHKERRQ(ierr);
  }

  if (doMisfit) {
	ierr = finalizeMisfit(tc,maxSteps,numTracers);CHKERRQ(ierr);
  }
  
  if (useExternalForcing) {
    ierr = VecDestroyVecs(numTracers,&uef);CHKERRQ(ierr);  
    ierr = finalizeExternalForcing(tc,maxSteps,numTracers);CHKERRQ(ierr);
  }  
  
  if (useForcingFromFile) {
    ierr = VecDestroyVecs(numTracers,&uf);CHKERRQ(ierr);  
	if (periodicForcing) {
	  for (itr=0; itr<numTracers; itr++) {  
		ierr = destroyPeriodicVec(&up[itr]);CHKERRQ(ierr);
	  }
	} else if (timeDependentForcing) {
	  for (itr=0; itr<numTracers; itr++) {
		ierr = VecDestroyVecs(numForcing,&utdf[itr]);CHKERRQ(ierr);
	  }  
	}
  }
  
  if (usePrescribedBC) {
    ierr = MatDestroy(&Be);CHKERRQ(ierr);
    ierr = MatDestroy(&Bi);CHKERRQ(ierr);
	if (periodicMatrix) {
	  ierr = destroyPeriodicMat(&Bep);CHKERRQ(ierr);
	  ierr = destroyPeriodicMat(&Bip);CHKERRQ(ierr);    
	}
    ierr = VecDestroyVecs(numTracers,&bcc);CHKERRQ(ierr);
    ierr = VecDestroyVecs(numTracers,&bcf);CHKERRQ(ierr);  
	if (periodicBC) {
	  for (itr=0; itr<numTracers; itr++) {  
		ierr = destroyPeriodicVec(&bcp[itr]);CHKERRQ(ierr);
	  }
	} else if (timeDependentBC) {
	  for (itr=0; itr<numTracers; itr++) {
		ierr = VecDestroyVecs(numBC,&bctd[itr]);CHKERRQ(ierr);
	  }  
	} else if (doCalcBC) {
      ierr = finalizeCalcBC(tc,maxSteps,numTracers);CHKERRQ(ierr);
      ierr = PetscFree(gBCIndices);CHKERRQ(ierr);
	}
  }

  ierr = PetscFree(gIndices);CHKERRQ(ierr);

  ierr = PetscFinalize();CHKERRQ(ierr);
  return 0;
}