예제 #1
0
int main(int argc, char *argv[]) {
/*
DRIVER_01 is a FLOW-MOTION LIMITED flow scheme! The flow will end when all vents
          have no more lava to effuse AND when the flow is no longer innundating
          new grid cells.
*/
/*DRIVER for a lava flow code ALGORITHM:
         Read in a Configuration File with INITIALIZE
         Load a DEM Raster with DEM_LOADER and assign parameters to a data grid
         Create Cellular Automata lists and assign source vents with INIT_FLOW
         
         Main Flow Loop:
           If there is more volume to erupt at source vents, call PULSE
           Move lava from cells to neighbors with DISTRIBUTE
           If flow is still moving, keep looping to call DISTRIBUTE
         
         After flow is completely erupted:
           Check for Conservation of Mass
           Write out requested Model Output to user-defined file paths
*/
	
	/*VARIABLES******************************************************************/
	/*Files*/
	char     *configFilename = argv[1]; /*configuration file path               */
	char     **Filenames;               /*A list of file paths for model output */
	char     tempFilename[15];          /*A temporary file path for whatever use*/
	
	/*Main Arrays*/
	DataCell **dataGrid;                /*Global Data Grid                      */
	Automata **CAList;                  /*Cellular Automata Lists (Active Cells)*/
	VentArr  *Vents;                    /*Source Vent List                      */
	unsigned *ActiveCounter;            /*Number of Active Cells in CA List     */
	
	/*Model Parameters*/
	int      i,j, ret;                  /*loop variables, function return value */
	unsigned CAListCount = 0;           /*Number of CA Lists, def in INIT_FLOW  */
	unsigned CAListSize  = 0;           /*Size of each CA List, def in INIT_FLOW*/
	unsigned ventCount   = 0;           /*Number of Src Vents, def in INITIALIZE*/
	int      pulseCount  = 0;           /*Current number of Main PULSE loops    */
	
	/*Physical Parameters*/
	double   residualThickness;         /*Residual Flow Thickness               */
	double   *DEMmetadata;              /*Geographic Coordinates of DEM Raster  */
	double   elevationUncertainty;      /*DEM Raster Elevation Uncertainty      */
	double   volumeToErupt;             /*Total Volume to deliver to vent cells */
	double   volumeErupted = 0;         /*Total Volume in All Active Cells      */
	double   volumeRemaining;           /*Volume Remaining to be Erupted        */
	int      volumeRemainingBool = 0;   /*0 if volume left to erupt, otherwise 1*/
	
	/*Post Flow Motion Detection Variables*/
	double   TotalMotion = 0;           /*Summed thickness change in all cells  */
	double   MinTotalMotion = 1e-11;    /*Threshold: below it flow is "stagnant"*/
	unsigned lastmotionCounter = 0;     /*Number of loops since last motion     */
	unsigned maxLastMotionCount = 10;   /*Max loops allowed since last motion   */
	unsigned lastActiveCounter = 0;     /*Number of active cells in prev. loop  */
	time_t   LastInundationTime;        /*Timestamp of last active cell creation*/
	double   maxLastInundationTime=10.0;/*Max time allowed since last cell cretn*/
	
	
	/*TIME AND RANDOM NUMBER GEN*************************************************/
	startTime = time(NULL); /*Define Start Time*/
	srand(time(NULL));      /*Seed random number generator*/
	
	/*WELCOME USER TO SIMULATION AND CHECK FOR CORRECT USAGE*********************/
	printf("\n\n               MOLASSES is a lava flow simulator.\n\n");
	
	/*User must supply the name of the executable and a configuration file*/
	if(argc<2) {
		printf("Usage: %s config-filename\n",argv[0]);
		return(-1);
	}
	
	printf("Beginning flow simulation...\n");
	
	/*MODULE: INITIALIZE*********************************************************/
	/*        Assigns several empty variables based on a user-defined 
	            configuration file.                                             */
	/*        File Name List output in this order:
	            [0] - DEM
	            [1] - Residual Flow Thickness
	            [2] - Elevation Uncertainty
	            [3] - Output file: ASCII X,Y,Thickness
	            [4] - Output file: Hit Map
	            [5] - Output file: Raster Thickness
	            [6] - Output file: Raster Elevation
	            [7] - Output file: Raster Elevation + Flow Thickness            */
	
	ret = INITIALIZE(configFilename,        /*chr Configuration File Name       */
	                 &Filenames,            /*chr File Name List                */
	                 &residualThickness,    /*dbl Global Residual Flow Thickness*/
	                 &elevationUncertainty, /*dbl Global Elevation Uncertainty  */
	                 &Vents,                /*ventarr Vent Structure Array      */
	                 &ventCount             /*unsignd Number of Vents           */
	                );
	
	/*Check for Error flag (INITIALIZE returns <0 value)*/
	if(ret<0){
		printf("\nERROR [MAIN]: Error flag returned from [INITIALIZE].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	
	/*MODULE: DEM_LOADER*********************************************************/
	/*        Loads Raster into Global Data Grid based on code:
	            TOPOG - Loads a DEM raster into the data grid's dem_elev value
	            RESID - Loads a raster into the data grid's residual value
	            T_UNC - Loads a raster into the data grid's elev_uncert value
	          Returns a metadata list of geographic coordinates of the raster   */
	/*        DEMmetadata format:
		          [0] lower left x
		          [1] w-e pixel resolution
		          [2] number of cols, assigned manually
		          [3] lower left y
		          [4] number of lines, assigned manually
		          [5] n-s pixel resolution (negative value)                       */
	
	/*Assign Topography to Data Grid Locations*/
	DEMmetadata = DEM_LOADER(Filenames[0], /*char            DEM file name   */
	                         &dataGrid,    /*DataCell        Global Data Grid*/
	                         "TOPOG"       /*DEM_LOADER Code Topography      */
	                        );
	
	/*Check for Error flag (DEM_LOADER returns a null metadata list)*/
	if(DEMmetadata==NULL){
		printf("\nError [MAIN]: Error flag returned from DEM_LOADER[TOPOG].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	
	/*Assign Residual Thickness to Data Grid Locations*/
	/*If residualThickness is -1, user input a Residual Thickness Map*/
	if(residualThickness==-1) {
		DEMmetadata = DEM_LOADER(Filenames[1], /*char            Residual filename*/
			                       &dataGrid,    /*DataCell        Global Data Grid */
			                       "RESID"       /*DEM_LOADER Code Resid Thickness  */
			                      );
	
		/*Check for Error flag (DEM_LOADER returns a null metadata list)*/
		if(DEMmetadata==NULL){
			printf("\nError [MAIN]: Error flag returned from DEM_LOADER[RESID].\n");
			printf("Exiting.\n");
			return(-1);
		}
	}
	/*If residualThickness is not -1, it is constant globally.*/
	else {
		/*Write residual flow thickness into 2D Global Data Array*/
		for(i=0;i<DEMmetadata[4];i++) {
			for(j=0;j<DEMmetadata[2];j++) {
				dataGrid[i][j].residual = residualThickness;
			}
		}
	}
	
	
	/*Assign Elevation Uncertainty to Data Grid Locations*/
	/*If elevationUncertainty is -1, user input an elevation uncertainty map*/
	if(elevationUncertainty==-1) {
		DEMmetadata = DEM_LOADER(Filenames[2], /*char            uncertny filename*/
			                       &dataGrid,    /*DataCell        Global Data Grid */
			                       "T_UNC"       /*DEM_LOADER Code elev uncertainty */
			                      );
	
		/*Check for Error flag (DEM_LOADER returns a null metadata list)*/
		if(DEMmetadata==NULL){
			printf("\nError [MAIN]: Error flag returned from DEM_LOADER[T_UNC].\n");
			printf("Exiting.\n");
			return(-1);
		}
	}
	/*If elevationUncertainty is not -1, it is constant globally.*/
	else {
		/*Write elevation uncertainty values into 2D Global Data Array*/
		for(i=0;i<DEMmetadata[4];i++) {
			for(j=0;j<DEMmetadata[2];j++) {
				dataGrid[i][j].elev_uncert = elevationUncertainty;
			}
		}
	}
	
	
	/*MODULE: INIT_FLOW**********************************************************/
	/*        Creates Active Cellular Automata lists and activates vents in them.
	          Also creates bookkeeper variables: 
	            total size of CA lists
	            total number of CA lists
	            total number of active automata in the CA list
	            total volume to erupt (combined volumes to erupt at vents)      */
	
	ret = INIT_FLOW(dataGrid,      /*DataCell  Global Data Grid                 */
	               &CAList,        /*Automaton Active Cells List                */
	               Vents,          /*VentArr   Vent Data Array                  */
	               &CAListCount,   /*unsigned  Number of CA Lists created       */
	               &CAListSize,    /*unsigned  Size of each empty CA List       */
	               ventCount,      /*unsigned  Number of Vents                  */
	               &ActiveCounter, /*unsigned  Number of active cells in CA List*/
	               DEMmetadata,    /*double    Geographic Metadata              */
	               &volumeToErupt  /*double    Volume that the model will expel */
	              );
	
	/*Check for Error flag (INIT_FLOW returns <0 value)*/
	if(ret<0) {
		printf("\nError [MAIN]: Error flag returned from [INIT_FLOW].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	
	
	
	/****************************************************************************/
	/*MAIN FLOW LOOP: PULSE LAVA AND DISTRIBUTE TO CELLS*************************/
	/****************************************************************************/
	volumeRemaining = volumeToErupt; /*set countdown bookkeeper volumeRemaining*/
	
	printf("\n                         Running Flow\n");
	
	
	/*Loop to call PULSE and DISTRIBUTE only if volume remains to be erupted
	  OR if flow has not stopped moving*/
	while((volumeRemaining > 0)||(lastmotionCounter<maxLastMotionCount)) {
		
		if(volumeRemaining > 0) { /*If there is more lava to erupt, call PULSE*/
		/*MODULE: PULSE************************************************************/
		/*        Delivers lava to vents based on information in Vent Data Array.
		          Returns total volume remaining to be erupted.                   */
	
		ret = PULSE(CAList[1],        /*Automaton Active Cells List               */
		            &Vents,           /*VentArr   Vent Data Array                 */
		            ActiveCounter[1], /*unsigned  Number of activ cells in CA List*/
		            &volumeRemaining, /*double    Countdown Lava Volume bookkeeper*/
		            ventCount,        /*unsigned  Number of vents                 */
		            DEMmetadata       /*double    Geographic Metadata             */
		           );
	
		/*Check for Error flags (PULSE returns <0 or 0 value)*/
		if(ret<0) {
			printf("\nERROR [MAIN]: Error flag returned from [PULSE].\n");
			printf("Exiting.\n");
			return(-1);
		}
		else if (ret==0) {
			if (volumeRemaining) {
				/*This return should not be possible, 
				  Pulse should return 0 if no volume remains*/
				printf("\nERROR [MAIN]: Error between [PULSE] return and lava vol.\n");
				printf("Exiting.\n");
				return(-1);
			}
			/*If ret==0, PULSE was called even though there was no lava to distribute.
			  Do not call Pulse or Distribute anymore! Break out of While loop.     */
			break;
		}
		/*if Pulse module successfully updated vents, ret will > 0.
		  Continue, call Distribute module.*/
		
		/*Update status message on screen*/
		printf("\rInundated Cells: %-7d; Volume Remaining: %10.2f",ActiveCounter[1],
		       volumeRemaining);
		}
		else { /*if no more volume to erupt, but flow still moving*/
		/*Update status message on screen to show flow motion*/
			printf("\rInundated Cells: %-7d; total dZ in flow: %10.2e",ActiveCounter[1],
		       TotalMotion);
		}
		
		
		/*MODULE: DISTRIBUTE*******************************************************/
		/*        Distributes lava from cells to neighboring cells depending on
		          module specific algorithm (e.g. slope-proportional sharing).
		          Updates a Cellular Automata List and the active cell counter.*/
		
		ret = DISTRIBUTE(dataGrid,          /*DataCell  Global Data Grid       */
		                 CAList[1],         /*Automaton Active Cells List      */
		                 &ActiveCounter[1], /*unsigned  Number of active cells */
		                 DEMmetadata        /*double    Geographic Metadata    */
		                );
		
		/*Check for Error flag (DISTRIBUTE returns <0 value)*/
		if(ret<0) {
			printf("\nERROR [MAIN]: Error flag returned from [DISTRIBUTE].\n");
			printf("Exiting.\n");
			return(-1);
		}
		
		/*If you want to output the flow at EVERY Pulse, here is a good place to do
		  it. A temporary file name variable is declared using the number of times 
		  this Pulse loop has been completed, then the OUTPUT module is called.
		  Uncomment the lines below if you want this. Commenting out the file name
		  declaration creates warnings since the variables won't later be used, so
		  I've left it uncommented out. (It only runs once per pulse, so it doesn't
		  slow the code down).*/
		
		/*increment pulse count, then rename the temporary file path.*/
		snprintf(tempFilename,15,"pulse_%04d.xyz",(++pulseCount));
		/*MODULE: OUTPUT**************************************/
		/*        writes out a file. Arguments:
		            DataCell  Global Data Grid
		            Automaton Active Cells List
		            unsigned  Number of active cells
		            string    Output Filename
		            OUTPUT Code: 0 = ASCII X,Y,Thickness File
		            double    Geographic Metadata
		            string    Original Raster Projection     */
		/*
		ret = OUTPUT(dataGrid,
		             CAList[1],
		             ActiveCounter[1],
		             tempFilename,
		             0,
		             DEMmetadata,
		             ""
		            );
		*/
		/*Check for Error flag (OUTPUT returns <0 value)*/
		/*
		if(ret<0){
			printf("\nERROR [MAIN]: Error flag returned from [OUTPUT].\n");
			printf("Exiting.\n");
			return(-1);
		}
		*/
		
		
		
		
		
		
		/*TEST TO SEE IF FLOW IS STILL PROGRESSING, IF VOLUME HAS RUN OUT*/
		/*This Driver Module continues to call the DISTRIBUTE Module if there is
		  significant flow within the lava flow, even after all lava has been 
		  delivered to the vents via the PULSE Module.
		  
		  Flow will continue to distribute if:
		    1) There is still volume to deliver to vent
		    2) The summed change in flow thickness across all cells is > than 
		       a pre-defined MinTotalMotion variable.
		    3) The time elapsed in seconds since the last active cell was created
		       is < than a pre-defined maxLastInundationTime.
		  
		  If the summed change in flow thickness (dz) is negligable, 
		    lastmotionCounter is incremented. If lastmotionCounter==pre-defined 
		    maxLastMotionCount, flow will stop.
		  If the time elapsed since the last cell creation is significant,
		    lastmotionCounter will be set at maxLastMotionCount, flow will stop.
		  */
		
		/*Only test for remaining flow IF eruption volume has run out*/
		if(volumeRemaining<=0) {
			/*If this is the first time volume is 0, start new screen output line*/
			if((volumeRemainingBool++)==0) printf("\n");
			
			/*MOTION TEST - If movement has stopped, end the flow*/
			TotalMotion=0.0; /*Reset TotalMotion to 0*/
			for(i=1;i<=ActiveCounter[1];i++) {
				/*Add change in volume of all active cells
				  CA List[2] is a copy of the Active CA List of the last Pulse Loop*/
				TotalMotion += fabs(CAList[1][i].elev - CAList[2][i].elev);
			}
			
			/*If flow has not changed, increment lastmotionCounter*/
			if(TotalMotion <= MinTotalMotion) ++lastmotionCounter;
			/*If flow has changed, reset lastmotionCounter and store flow values
			    in spare CA List.*/
			else{
				lastmotionCounter=0;                     /*reset*/
				for(i=1;i<=ActiveCounter[1];i++) {       /*For all Active Cells*/
					CAList[2][i].elev = CAList[1][i].elev; /*Copy CA List[1] to List[2]*/
				}
			}
			
			/*POPCORN RULE - If a new cell hasn't been created in X secs, end flow*/
			if(lastActiveCounter!=ActiveCounter[1]) { /*If there's a new cell*/
				LastInundationTime = time(NULL);        /*Reset Last inundation time*/
				lastActiveCounter=ActiveCounter[1];     /*Reset lastActiveCounter*/
			}
			/*If there are no new cells, check that X secs have not gone by.*/
			else {
				/*If max time to wait for a new cell HAS been reached, end the flow*/
				if(((unsigned) (time(NULL)-LastInundationTime))>=maxLastInundationTime) {
					printf("\n Ending Flow because last cell to be inundated was ");
					printf(">%u secs ago.", (unsigned) (time(NULL)-LastInundationTime));
					lastmotionCounter=maxLastMotionCount;
				}
			}
		} /*End of Remaining Detectable Flow Check*/
		
		
	} /*End while main flow loop: (while(volumeRemaining>0)and Flow Motion)*/
	
	
	/*POST FLOW WRAP UP**********************************************************/
	
	printf("\n\n                     Single Flow Complete!\n");
	
	/*Print out final number of inundated cells*/
	printf("Final Count: %d cells inundated.\n\n", ActiveCounter[1]);
	
	
	/*POST FLOW WRAP UP: CONSERVATION OF MASS CHECK******************************/
	/*ALL DRIVER MODULES MUST HAVE THIS. In order to do unit testing during
	  code compilation, makefile searches for the string "SUCCESS: MASS CONSERVED"
	  to conclude that the code is Verified (though not validated).*/
	
	volumeErupted = 0;
	/*For each Active Flow Cell, add cell lava volume to volumeErupted*/
	for(i=1;i<=ActiveCounter[1];i++)
		volumeErupted += (CAList[1][i].thickness + 
		               dataGrid[CAList[1][i].row][CAList[1][i].col].residual) *
		               DEMmetadata[1] * DEMmetadata[5];
	
	/*print out volume delivered to vents and total volume now in cells*/
	printf("Conservation of mass check\n");
	printf(" Total (IN) volume pulsed from vents:   %0.3f\n",volumeToErupt);
	printf(" Total (OUT) volume found in cells:     %0.3f\n",volumeErupted);
	/*Double data types are precise to 1e-8, so make sure that volume IN and
	  volume OUT are within this precision.*/
	if(abs(volumeErupted-volumeToErupt)<=1e-8)
		printf(" SUCCESS: MASS CONSERVED\n");
	/*If volumes are significantly different (are more than Double Precision diff.
	  then mass is NOT conserved!!*/
	else 
		/*Print the mass excess*/
		printf(" ERROR: MASS NOT CONSERVED! Excess: %0.2e m^3",
		       volumeErupted-volumeToErupt);
	
	
	/*MODULE: OUTPUT*************************************************************/
	/*        Writes out model output to a file path.
	          File Output types available, and their codes:
	            0: X,Y,Thickness ascii flow list
	            1: Hit Raster (1 = Hit, 0 = Not Hit)
	            2: Thickness Raster
	            3: Elevation Raster
	            4: Elevation + Lava Raster (code 2 + code 3)
	          
	          Filename Index output from INITIALIZE:
	            Filenames[3] - Output file: ASCII X,Y,Thickness
	            Filenames[4] - Output file: Hit Map
	            Filenames[5] - Output file: Raster Thickness
	            Filenames[6] - Output file: Raster Elevation
	            Filenames[7] - Output file: Raster Elevation + Flow Thickness   */
	
	/*Check Filenames Array to see if a filename was given (so model output is
	  requested).*/
	for(i=0;i<4;i++){
		/*Check to see if the File Path is not empty (the following test will !=0)*/
		if(strlen(Filenames[i+3]) > 1) {
		/*If there's a file path given, write model output to it.*/
			ret = OUTPUT(dataGrid,         /*DataCell  Global Data Grid           */
			             CAList[1],        /*Automaton Active Cells List          */
			             ActiveCounter[1], /*unsigned  Number of active cells     */
			             Filenames[i+3],   /*string    Output File Path           */
			             i,                /*OUTPUT Code, see above               */
			             DEMmetadata,""    /*string    Original Raster Projection */
			            );
			
			/*Check for Error flag (OUTPUT returns <0 value)*/
			if(ret<0){
				printf("\nERROR [MAIN]: Error flag returned from [OUTPUT].\n");
				printf("Exiting.\n");
				return(-1);
			}
		}
	}
	
	/*Calculate simulation time elapsed, and print it.*/
	endTime = time(NULL);
	printf("\nElapsed Time of simulation approximately %u seconds.\n\n",
	       (unsigned)(endTime - startTime));
	
	return(0);
}
예제 #2
0
/*int CHOOSE_NEW_VENT(SpatialDensity *grid,
	unsigned num_grids,
	unsigned num_vents, 
	double grid_spacing,
	unsigned *new_east,
	unsigned *new_north) {

	 Parameters
	In->spdfilespatial_density = $_[0];
	num_vents = $_[1];
 	spd_spacing = $_[2];
  my @lambda;
  my $sum;
  my $random;
  my $sum_lambda = 0;
*/
int CHOOSE_NEW_VENT(Inputs *In, DataCell ***SpDens ,VentArr *Vent) {
	double sum_lambda = 0, sum = 0, random;
	unsigned i,j;
	
	//If the Spatial Density Grid is NULL, declare it by loading in the SPD FILE
	if (*SpDens==NULL) {
		fprintf(stdout, "\nLoading Vent Spatial Density file...\n");
		In->spd_grid_data = DEM_LOADER(In->spd_file,
		                        SpDens,
		                        "DENSITY"
		                       );
		if ((In->spd_grid_data == NULL) || (*SpDens == NULL)) {
			fprintf(stderr, "\nError [CHOOSE_NEW_VENT]: ");
			fprintf(stderr, "Error flag returned from DEM_LOADER[DENSITY].\n");
			return 1;
		}
	}
	
	/*Metadata:
	  In->spd_grid_data[0] lower left x
	  In->spd_grid_data[1] w-e pixel resolution
	  In->spd_grid_data[2] number of cols
	  In->spd_grid_data[3] lower left y
	  In->spd_grid_data[4] number of lines
	  In->spd_grid_data[5] n-s pixel resolution */
	
	//Integrate the spatial density within the grid
	for(i=0; i < In->spd_grid_data[4]; i++) {
		for(j=0; j < In->spd_grid_data[2]; j++) {
			sum_lambda += (*(*SpDens+i)+j)->prob;
		}
	}
	if (sum_lambda <=0 ) {
		fprintf(stderr, "\nError [CHOOSE_NEW_VENT]: Spatial Density sums to <= 0!!\n");
		return 1;
	}
	
	
	//fprintf(stderr,"New Vent Location:");
	
	//Choose a random number (0 to integrated density) to match to a grid cell
	random = (double) genunf ( (float) 0, (float) sum_lambda );
	
	j=i=0;
	while (sum < random) {
		sum += (*(*SpDens+i)+(j++))->prob;
		if (j == (In->spd_grid_data[2])){
			i++;
			j=0;
		}
	}
	//j will be one step too far after this loop, so let's take 1 step back.
	if(j==0) {
		j=In->spd_grid_data[2];
		i--;
	}
	j--;
	
	Vent->northing = In->spd_grid_data[3] + (i * In->spd_grid_data[5]);
	Vent->easting = In->spd_grid_data[0] + (j * In->spd_grid_data[1]);
	
	//Choose a random location within the cell
	Vent->northing += ((double) genunf ( (float) 0, (float) 1)) * 
	                   In->spd_grid_data[5];
	Vent->easting  += ((double) genunf ( (float) 0, (float) 1)) * 
	                   In->spd_grid_data[1];
	
	
	//fprintf(stderr,"  %0.3f e, %0.3f n\n",Vent->easting,Vent->northing);
	
	
  	return 0;
	
}
예제 #3
0
int main(int argc, char *argv[]) {
	
	/*VARIABLES******************************************************************/
	/*Files*/
	char     *configFilename = argv[1]; /*configuration file path               */
	char     **Filenames;               /*A list of file paths for model output */
	
	point *DEMvals;
	point *RDRvals;
	point *shftRDRvals;
	point *cropDEMvals;
	point  origin;
	point  translate;
	point  rotate;
	double scale;
	
	point dist;
	double hypotenuse;
	double curangle;
	point *RDRinterp;
	point RDRUL;
	point RDRLR;
	point DEMUL;
	point DEMLR;	
	point expandedDEMUL;
	point expandedDEMLR;
	unsigned RDRinboundsct=0;
	unsigned DEMinboundsct=0;
	
	double NNdist[4];
	double NNelev[4];
	double NNwt[4];
	double curdistance;
	
	double DEMnoDATA;
	double RDRnoDATA;
	unsigned demmax;
	unsigned rdrmax;
	
	double *DEMmetadata;
	double *RDRmetadata;
	
	FILE *DEMfile;
	FILE *RDRfile;
	
	int ret, i, j;
	
	/*TIME **********************************************************************/
	startTime = time(NULL); /*Define Start Time*/
	
	/*WELCOME USER AND CHECK FOR CORRECT USAGE***********************************/
	printf("\n\n               This will shift ur data.\n\n");
	
	/*User must supply the name of the executable and a configuration file*/
	if(argc<2) {
		printf("Usage: %s config-filename\n",argv[0]);
		return(-1);
	}
	
	printf("Reading Configuration File...\n");
	
	/*MODULE: INITIALIZE*********************************************************/
	/*        Assigns several empty variables based on a user-defined 
	            configuration file.                                             */
	/*        File Name List output in this order:
	            [0] - DEM
	            [1] - Residual Flow Thickness
	            [2] - Elevation Uncertainty
	            [3] - Output file: ASCII X,Y,Thickness
	            [4] - Output file: Hit Map
	            [5] - Output file: Raster Thickness
	            [6] - Output file: Raster Elevation
	            [7] - Output file: Raster Elevation + Flow Thickness            */
	
	ret = INITIALIZE(configFilename,        /*chr Configuration File Name       */
	                 &Filenames,            /*chr File Name List                */
	                 &origin.easting,       /*point  origin location            */
	                 &origin.northing,       /*point  origin location            */
	                 &origin.elevation,       /*point  origin location            */
	                 &translate.easting,       /*point  origin location            */
	                 &translate.northing,       /*point  origin location            */
	                 &translate.elevation,       /*point  origin location            */
	                 &rotate.easting,       /*point  origin location            */
	                 &rotate.northing,       /*point  origin location            */
	                 &rotate.elevation,       /*point  origin location            */
	                 &scale,                /*double scale                      */
	                 &DEMnoDATA,            /*DEM raster No Data                */
	                 &RDRnoDATA             /*RDR raster No Data                */
	                );

	/*Check for Error flag (INITIALIZE returns <0 value)*/
	if(ret<0){
		printf("\nERROR [MAIN]: Error flag returned from [INITIALIZE].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	printf("Loading Digital Elevation Model...");
	/*MODULE: DEM_LOADER*********************************************************/
	/*        Loads Raster into a list and reports range values*/
	
	/*Load topography from "Expected" DEM*/
	DEMmetadata = DEM_LOADER(Filenames[0], /*char         DEM file name */
	                         &DEMvals      /*point        DEM x,y,z list*/
	                        );
	/*Check for Error flag (DEM_LOADER returns a null metadata list)*/
	if(DEMmetadata==NULL){
		printf("\nError [MAIN]: Error flag returned from DEM_LOADER [DEM].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	demmax = DEMmetadata[2]*DEMmetadata[4];
	
	/*DEMGeoTransform[0] lower left x
	  DEMGeoTransform[1] w-e pixel resolution
	  DEMGeoTransform[2] number of cols, assigned manually in this module 
	  DEMGeoTransform[3] lower left y
	  DEMGeoTransform[4] number of lines, assigned manually in this module
	  DEMGeoTransform[5] n-s pixel resolution (negative value) */
	
	DEMUL.easting = DEMmetadata[0];
	DEMUL.northing =DEMmetadata[3] + (DEMmetadata[4]*DEMmetadata[5]);
	DEMLR.easting = DEMmetadata[0] + (DEMmetadata[2]*DEMmetadata[1]);
	DEMLR.northing = DEMmetadata[3];
	expandedDEMUL.easting = DEMUL.easting - (2*DEMmetadata[1]);
	expandedDEMUL.northing = DEMUL.northing + (2*DEMmetadata[5]);
	expandedDEMLR.easting = DEMLR.easting + (2*DEMmetadata[1]);
	expandedDEMLR.northing = DEMLR.northing - (2*DEMmetadata[5]);

	printf("Loading Radar Elevation Model...");
	/*Load topography from "observed" Radar DEM*/
	RDRmetadata = DEM_LOADER(Filenames[1], /*char         RDR file name */
	                         &RDRvals      /*point        RDR x,y,z list*/
	                        );
	/*Check for Error flag (DEM_LOADER returns a null metadata list)*/
	if(RDRmetadata==NULL){
		printf("\nError [MAIN]: Error flag returned from DEM_LOADER [RDR].\n");
		printf("Exiting.\n");
		return(-1);
	}
	
	rdrmax = RDRmetadata[2]*RDRmetadata[4];
	
	RDRUL.easting = RDRmetadata[0];
	RDRUL.northing =RDRmetadata[3] + (RDRmetadata[4]*RDRmetadata[5]);
	RDRLR.easting = RDRmetadata[0] + (RDRmetadata[2]*RDRmetadata[1]);
	RDRLR.northing = RDRmetadata[3];
	
	
	/*Print range of DEM and RADAR coordinates, pre-shift.*/
	printf("DEM (Lab)    Range is:   %0.3f\n",   DEMUL.northing);
	printf("                  %0.3f    %0.3f\n", DEMUL.easting, DEMLR.easting);
	printf("                         %0.3f\n\n",   DEMLR.northing);
	
	printf("Radar (Body) Range is:   %0.3f\n",   RDRUL.northing);
	printf("                  %0.3f    %0.3f\n", RDRUL.easting, RDRLR.easting);
	printf("                         %0.3f\n\n",   RDRLR.northing);
	
	
	
	
	/*****DOF-SHIFT******/
	printf("\n\nAPPLYING ROTATIONS AND TRANSFORMATIONS TO THE LAB DATA SET\n\n");
	printf("Origin Location:\n");
	printf("         easting:   %0.3f\n" , rotate.easting);
	printf("         northing:  %0.3f\n" , rotate.northing);
	printf("         elevation: %0.3f\n" , rotate.elevation);
	
	
	/*Change Rotation from degrees to radians*/
	printf("\nRotating (CCW)...\n");
	printf("         about the Z-axis,  %0.3f° " , rotate.elevation);
	rotate.elevation *= M_PI / 180.0;
	printf("(%0.3f radians)\n", rotate.elevation);
	
	printf("         about the NS-axis, %0.3f° " , rotate.northing);
	rotate.northing   *= M_PI / 180.0;
	printf("(%0.3f radians)\n", rotate.northing);
	
	printf("         about the EW-axis, %0.3f° " , rotate.easting);
	rotate.easting  *= M_PI / 180.0;
	printf("(%0.3f radians)\n", rotate.easting);
	
	
	printf("\nTranslating...\n");
	printf("         %0.3f m to the East\n",translate.easting);
	printf("         %0.3f m to the North\n",translate.northing);
	printf("         %0.3f m        Up\n",translate.elevation);
	printf("\nScaling...\n");
	printf("         %0.3f%% of original size\n\n",(scale*100.0));
	
	for(i=0;i<rdrmax;i++){
		if (RDRvals[i].elevation != RDRnoDATA) { /*only shift if this location has a value*/
		
			/*Remove origin from locations*/
			RDRvals[i].easting   -= origin.easting;
			RDRvals[i].northing  -= origin.northing;
			RDRvals[i].elevation -= origin.elevation;
			if(i==0) {
				printf("pre-rot:  %0.3fE\t%0.3fN\t%0.3fElev\n",RDRvals[i].easting,RDRvals[i].northing,RDRvals[i].elevation);
			}
		
			/*ROTATE RDR locations**********************/
			/*ABOUT Z AXIS*/
			hypotenuse = pow((pow(RDRvals[i].easting,2.0) + pow(RDRvals[i].northing,2.0)),0.5);
			if(RDRvals[i].easting    == 0.0) {
				curangle = M_PI/2.0;
				if(RDRvals[i].northing  < 0.0) curangle *= -1.0;
			}
			else {
				curangle = atan(RDRvals[i].northing / RDRvals[i].easting);
				if(RDRvals[i].easting < 0.0) curangle += M_PI;
			}
		
			/*apply rotation*/
			RDRvals[i].easting  = cos(rotate.elevation + curangle) * hypotenuse;
			RDRvals[i].northing = sin(rotate.elevation + curangle) * hypotenuse;
		
			if(i==0) {
				printf("postrotZ: %0.3fE\t%0.3fN\t%0.3fElev\n",RDRvals[i].easting,RDRvals[i].northing,RDRvals[i].elevation);
			}
		
			/*ABOUT Y AXIS*/		
			hypotenuse = pow((pow(RDRvals[i].easting,2.0) + pow(RDRvals[i].elevation,2.0)),0.5);
			if(RDRvals[i].elevation    == 0.0) {
				curangle = M_PI/2.0;
				if(RDRvals[i].easting < 0.0) curangle *= -1.0;
			}
			else {
				curangle = atan(RDRvals[i].easting / RDRvals[i].elevation);
				if(RDRvals[i].elevation < 0.0) curangle += M_PI;
			}
		
			/*apply rotation*/
			RDRvals[i].elevation = cos(rotate.northing + curangle) * hypotenuse;
			RDRvals[i].easting   = sin(rotate.northing + curangle) * hypotenuse;
		
			if(i==0) {
				printf("postrotY: %0.3fE\t%0.3fN\t%0.3fElev\n",RDRvals[i].easting,RDRvals[i].northing,RDRvals[i].elevation);
			}
		
			/*ABOUT X AXIS*/
			hypotenuse = pow((pow(RDRvals[i].elevation,2.0) + pow(RDRvals[i].northing,2.0)),0.5);
			if(RDRvals[i].northing    == 0.0) {
				curangle = M_PI/2.0;
				if(RDRvals[i].elevation < 0.0) curangle *= -1.0;
			}
			else {
				curangle = atan(RDRvals[i].elevation / RDRvals[i].northing);
				if(RDRvals[i].northing < 0.0) curangle += M_PI;
			}
		
			/*apply rotation*/
			RDRvals[i].northing  =  cos(rotate.easting + curangle) * hypotenuse;
			RDRvals[i].elevation =  sin(rotate.easting + curangle) * hypotenuse;
		
			if(i==0) {
				printf("postrotX: %0.3fE\t%0.3fN\t%0.3fElev\n",RDRvals[i].easting,RDRvals[i].northing,RDRvals[i].elevation);
			}
		
		
			/*find distance from origin (0,0)*/
			dist.easting   = RDRvals[i].easting;
			dist.northing  = RDRvals[i].northing;
			dist.elevation = RDRvals[i].elevation;
		
			/*scale RDR locations (scale before translation)*/
			dist.easting   *= scale - 1.0; /*This is the scale shift*/
			dist.northing  *= scale - 1.0;
			dist.elevation *= scale - 1.0;
		
			/*Add translation, scale, and readd origin at same time*/
			RDRvals[i].easting   += translate.easting   + dist.easting   + origin.easting;
			RDRvals[i].northing  += translate.northing  + dist.northing  + origin.northing;
			RDRvals[i].elevation += translate.elevation + dist.elevation + origin.elevation;
		
			if(i==0) {
				printf("post-trn: %0.3fE\t%0.3fN\t%0.3fElev\n",RDRvals[i].easting,RDRvals[i].northing,RDRvals[i].elevation);
			}
		}
	}
	
	j=0;
	for(i=0;i<rdrmax;i++) {
		if (RDRvals[i].elevation != RDRnoDATA) { /*only count if this location has a value*/
			/*Find New Range*/
			if((j++)==0) {
				RDRUL.easting  = RDRvals[i].easting;
				RDRUL.northing = RDRvals[i].northing;
				RDRLR.easting  = RDRvals[i].easting;
				RDRLR.northing = RDRvals[i].northing;
			}
			else {
				if (RDRUL.easting > RDRvals[i].easting) RDRUL.easting = RDRvals[i].easting;
				else if (RDRLR.easting < RDRvals[i].easting) RDRLR.easting = RDRvals[i].easting;
				if (RDRUL.northing < RDRvals[i].northing) RDRUL.northing = RDRvals[i].northing;
				else if (RDRLR.northing > RDRvals[i].northing) RDRLR.northing = RDRvals[i].northing;
			}
		
			/*Count number of RADAR points now in or near DEM*/
			if ((RDRvals[i].easting >= expandedDEMUL.easting) && (RDRvals[i].easting <= expandedDEMLR.easting)){
				if ((RDRvals[i].northing <= expandedDEMUL.northing) && (RDRvals[i].northing >= expandedDEMLR.northing)) {
					++RDRinboundsct; /*Increment count of points within the expanded DEM boundaries*/
				}
			}
		}
	}
	
	/*Print new range of RADAR coordinates, post shift.*/
	printf("\nNew Radar Range is:   %0.3f\n",   RDRUL.northing);
	printf("               %0.3f    %0.3f\n", RDRUL.easting, RDRLR.easting);
	printf("                      %0.3f\n",   RDRLR.northing);
	printf("%u radar locations with data are within 2 pixels of the DEM\n\n", RDRinboundsct);
	
	if(RDRinboundsct==0){
		printf("NO shifted radar points lie within the DEM region!! unable to fit.\nexiting.\n");
		return(-1);
	}
	
	/*CROP ALL THE DATA*************************************************************************/
	printf("Cropping the BODY data to the LAB data extent\n");
	
	/*move Radar values to new, potentially smaller list, for speed*/
	if((shftRDRvals = malloc (sizeof (point) * (RDRinboundsct)))==NULL) {
		printf("ERROR [MAIN]: Out of Memory creating Shifted RADAR Values List!\n");
		return(-1);
	}
	
	j=0;
	for(i=0;i<rdrmax;i++){
		if((RDRvals[i].easting >= expandedDEMUL.easting) && (RDRvals[i].easting <= expandedDEMLR.easting)){
			if((RDRvals[i].northing <= expandedDEMUL.northing) && (RDRvals[i].northing >= expandedDEMLR.northing)) {
				if (RDRvals[i].elevation != RDRnoDATA) { /*only copy if there's data*/
					shftRDRvals[j] = RDRvals[i];
					j++;
				}
			}
		}
	}
	
	free(RDRvals); /*free memory of old array*/
	printf("                      copied %u values to cropped BODY array\n",(j+1));
	
	printf("Cropping the LAB data to the BODY data extent\n");
	
	/*Now find new range of DEM and scrap values outside of the Radar range*/
	if(DEMUL.easting < RDRUL.easting) DEMUL.easting = RDRUL.easting;
	if(DEMLR.easting > RDRLR.easting) DEMLR.easting = RDRLR.easting;
	if(DEMUL.northing > RDRUL.northing) DEMUL.northing = RDRUL.northing;
	if(DEMLR.northing < RDRLR.northing) DEMLR.northing = RDRLR.northing;
	
	DEMinboundsct=0;
	for(i=0;i<demmax;i++){
		if (DEMvals[i].easting >= DEMUL.easting && DEMvals[i].easting <= DEMLR.easting){
			if (DEMvals[i].northing <= DEMUL.northing && DEMvals[i].northing >= DEMLR.northing) {
				DEMinboundsct++;
			}
		}
	}
	
		/*DEMGeoTransform[0] lower left x
	  DEMGeoTransform[1] w-e pixel resolution
	  DEMGeoTransform[2] number of cols, assigned manually in this module 
	  DEMGeoTransform[3] lower left y
	  DEMGeoTransform[4] number of lines, assigned manually in this module
	  DEMGeoTransform[5] n-s pixel resolution (negative value) */

	/*move DEM values to new, potentially smaller list, for speed*/
	if((cropDEMvals = malloc (sizeof (point) * (DEMinboundsct)))==NULL) {
		printf("ERROR [MAIN]: Out of Memory creating Cropped DEM Values List!\n");
		return(-1);
	}
	
	j=0;
	for(i=0;i<demmax;i++){
		if (DEMvals[i].easting >= DEMUL.easting && DEMvals[i].easting <= DEMLR.easting){
			if (DEMvals[i].northing <= DEMUL.northing && DEMvals[i].northing >= DEMLR.northing) {
				cropDEMvals[j] = DEMvals[i];
				j++;
			}
		}
	}
	
	free(DEMvals); /*free memory of old array*/
	printf("                      copied %u values to cropped LAB array\n",(j+1));
	
	
	if((RDRinterp = malloc (sizeof (point) * (DEMinboundsct)))==NULL) {
		printf("ERROR [MAIN]: Out of Memory creating Interpolated RADAR Array!\n");
		return(-1);
	}
	
	/*Interpolate RDR onto SRTM***************************************************/
	printf("\n\nInterpolating shifted points at DEM locations\n");
	
	/*initialize NNelevs to avoid make warning.*/
	NNelev[0] = NNelev[1] = NNelev[2] = NNelev[3] = 0.0;
	
	for(i=0;i<DEMinboundsct;i++){
		/*printf("\r%u/%u",i,DEMinboundsct);*/
		
		RDRinterp[i].easting  = cropDEMvals[i].easting;
		RDRinterp[i].northing = cropDEMvals[i].northing;
		RDRinterp[i].elevation = -9999; /*starting elevation in case no value can be assigned*/
		
		/*if DEM is not NoDATA*/
		if (cropDEMvals[i].elevation != DEMnoDATA) {
		
			/*use near neighbor to find elevation
				loop through all, if in a quadrant, check if it's the closest point.
				after loop, closest 4 points get averaged, weighted by distance.
				must have all 4 points. All that is needed is to preserve a distance
				and an elevation for 4 quadrants. double[4] distance, double[4] elev*/
		
			for(j=0;j<=3;j++) {
				/*reset distance*/
				NNdist[j] = DBL_MAX;
			}
		
		
			for(j=0;j<RDRinboundsct;j++){
				if (abs(shftRDRvals[j].easting-RDRinterp[i].easting) < (2.0*DEMmetadata[1])) {
				if (abs(shftRDRvals[j].northing-RDRinterp[i].northing) < (2.0*DEMmetadata[1])) {
					curdistance = pow(pow((shftRDRvals[j].easting  - RDRinterp[i].easting ),2.0) +
					              pow((shftRDRvals[j].northing - RDRinterp[i].northing),2.0),0.5);
					
					/*First quadrant*/
					if((shftRDRvals[j].easting  >= RDRinterp[i].easting) && 
						 (shftRDRvals[j].northing >= RDRinterp[i].northing)) {
						/*is distance smallest?*/
						if (curdistance < NNdist[0]) {
							NNdist[0]  = curdistance;
							NNelev[0]  = shftRDRvals[j].elevation;
						}
					}
					/*Second quadrant*/
					else if((shftRDRvals[j].easting   < RDRinterp[i].easting) && 
						 (shftRDRvals[j].northing >= RDRinterp[i].northing)) {
						if (curdistance < NNdist[1]) {
							NNdist[1]  = curdistance;
							NNelev[1] = shftRDRvals[j].elevation;
						}
					}
					/*Third quadrant*/
					else if((shftRDRvals[j].easting  < RDRinterp[i].easting) && 
						 (shftRDRvals[j].northing < RDRinterp[i].northing)) {
						if (curdistance < NNdist[2]) {
							NNdist[2]  = curdistance;
							NNelev[2] = shftRDRvals[j].elevation;
						}
					}
					/*Fourth quadrant*/
					else {
						if (curdistance < NNdist[3]) {
							NNdist[3]  = curdistance;
							NNelev[3] = shftRDRvals[j].elevation;
						}
					}
				}} /*If the point is within 2 pixels of the point*/
			} /*For all radar values*/
		
			/*if all distances are assigned*/
			if (((NNdist[0]<DBL_MAX)&&(NNdist[1]<DBL_MAX))&&
				  ((NNdist[2]<DBL_MAX)&&(NNdist[3]<DBL_MAX))) {
				/*interpolate elevation*/
				if (NNdist[0]==0) RDRinterp[i].elevation = NNelev[0];
				else if (NNdist[1]==0) RDRinterp[i].elevation = NNelev[1];
				else if (NNdist[2]==0) RDRinterp[i].elevation = NNelev[2];
				else if (NNdist[3]==0) RDRinterp[i].elevation = NNelev[3];
				else {
					NNwt[0] = pow((1.0/NNdist[0]),2.0);
					NNwt[1] = pow((1.0/NNdist[1]),2.0);
					NNwt[2] = pow((1.0/NNdist[2]),2.0);
					NNwt[3] = pow((1.0/NNdist[3]),2.0);
					RDRinterp[i].elevation = 	(NNwt[0]*NNelev[0] + NNwt[1]*NNelev[1] + 
					                           NNwt[2]*NNelev[2] + NNwt[3]*NNelev[3]) /
					                          (NNwt[0] + NNwt[1] + NNwt[2] + NNwt[3]);
				}
			} /*end interpolate this point*/
		} /*end only do this point if there's a DEM value*/
	} /*end for all points to be interpolated*/
	
	printf("  Done!\n\n");
	
	/*WRITE DEM and RDR elevations to output, if both have values!*/
	/*X,Y,Z ASCII Lists**********************************************/
	DEMfile = fopen(Filenames[2], "w");
	RDRfile = fopen(Filenames[3], "w");
	
	if (DEMfile == NULL) {
		printf("Cannot open DEM output file=[%s]:[%s]! Exiting.\n",
		Filenames[2], strerror(errno));
		return(-1);
	}
	if (RDRfile == NULL) {
		printf("Cannot open Radar output file=[%s]:[%s]! Exiting.\n",
		Filenames[3], strerror(errno));
		return(-1);
	}

	j=0;
	for (i=0;i<DEMinboundsct;i++){
		if (RDRinterp[i].elevation!=-9999) {
			j++;
			fprintf(DEMfile, "%0.3f\t%0.3f\t%0.6f\n", 
				               cropDEMvals[i].easting,
				               cropDEMvals[i].northing,
				               cropDEMvals[i].elevation);
			fprintf(RDRfile, "%0.3f\t%0.3f\t%0.6f\n", 
				               RDRinterp[i].easting,
				               RDRinterp[i].northing,
				               RDRinterp[i].elevation);
				               
		}
	}

	fclose(RDRfile);
	fclose(DEMfile);
	printf("%u points written to ASCII Output files:\n  %s (DEM)\n  %s (RDR)\n",
	       j, Filenames[2],Filenames[3]);
	
	/*Calculate simulation time elapsed, and print it.*/
	endTime = time(NULL);
	printf("\nElapsed Time approximately %u seconds.\n\n",
	       (unsigned)(endTime - startTime));
	
	return(0);
}