//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Creates an LSDChiTools from an LSDRaster 
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::create(LSDIndexRaster& ThisRaster)
{
  NRows = ThisRaster.get_NRows();
  NCols = ThisRaster.get_NCols();
  XMinimum = ThisRaster.get_XMinimum();
  YMinimum = ThisRaster.get_YMinimum();
  DataResolution = ThisRaster.get_DataResolution();
  NoDataValue = ThisRaster.get_NoDataValue();
  GeoReferencingStrings = ThisRaster.get_GeoReferencingStrings();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
//
// Create function that reads from an index raster
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDRasterInfo::create(LSDIndexRaster& IRaster)
{
      ///Number of rows.
  NRows = IRaster.get_NRows();
  NCols = IRaster.get_NCols();
  XMinimum = IRaster.get_XMinimum();
  YMinimum = IRaster.get_YMinimum();
  DataResolution = IRaster.get_DataResolution();
  NoDataValue = IRaster.get_NoDataValue();
  GeoReferencingStrings = IRaster.get_GeoReferencingStrings();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// this appends the channel onto an index raster. Used to test where the channel is.
//
// SMM 2012
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void LSDIndexChannel::append_index_channel_to_index_raster(LSDIndexRaster& old_raster)
{
	int n_nodes_in_channel = int(NodeSequence.size());
	cout << "NRows: " << NRows << " NCols: " << NCols << endl;

	Array2D<int> Channel_array= old_raster.get_RasterData();
	for(int i = 0; i<n_nodes_in_channel; i++)
	{
		//cout << "row: " << RowSequence[i] << " col: " << ColSequence[i] << endl;
		Channel_array[RowSequence[i]][ColSequence[i]]= 1;
	}

	LSDIndexRaster Channel_loc(NRows,NCols, XMinimum, YMinimum, DataResolution, NoDataValue, Channel_array,GeoReferencingStrings);
	old_raster = Channel_loc;
}
int main (int nNumberofArgs,char *argv[])
{
  //Test for correct input arguments
  if (nNumberofArgs!=3)
  {
    cout << "FATAL ERROR: wrong number inputs. The program needs the path name and the file name" << endl;
    exit(EXIT_SUCCESS);
  }

  string path_name = argv[1];
  
  // make sure there is a slash on the end of the file
  string lchar = path_name.substr(path_name.length()-2,1);
  string slash = "/";      
  if (lchar != slash)
  {
    cout << "You forgot the frontslash at the end of the path. Appending." << endl; 
    path_name = path_name+slash;
  } 		
  
  string f_name = argv[2];

  cout << "\nYou are running the write junctions driver." << endl
       <<"IMPORTANT: this has been updated to load an ENVI DEM, whith extension .bil" << endl
       <<"You can convert your DEM to this file format using gdal_translate, with -of ENVI" << endl
       <<"See documentation at: http://www.geos.ed.ac.uk/~smudd/LSDTT_docs/html/gdal_notes.html" << endl << endl;
       
  cout << "The path is: " << path_name << " and the filename is: " << f_name << endl;

  string full_name = path_name+f_name;

  ifstream file_info_in;
  file_info_in.open(full_name.c_str());
  if( file_info_in.fail() )
  {
    cout << "\nFATAL ERROR: the header file \"" << full_name
         << "\" doesn't exist" << endl;
    exit(EXIT_FAILURE);
  }

  string DEM_name;
  string fill_ext = "_fill";
  file_info_in >> DEM_name;
  int junction_number;
  float pruning_threshold;
  int threshold;
  float A_0;
  int minimum_segment_length;
  float sigma;
  float start_movern;
  float d_movern;
  float Minimum_Slope;
  int n_movern;
  int target_nodes;
  int n_iterations;
  float fraction_dchi_for_variation;
  float vertical_interval;
  float horizontal_interval;
  float area_thin_frac;
  int target_skip;

  file_info_in >> Minimum_Slope >> threshold >> junction_number
        >> pruning_threshold >> A_0 >> minimum_segment_length >> sigma >> start_movern
        >> d_movern >> n_movern >> target_nodes >> n_iterations >> fraction_dchi_for_variation
        >> vertical_interval >> horizontal_interval >> area_thin_frac >> target_skip;


  cout << "Paramters of this run: " << endl
       << "junction number: " << junction_number << endl
       << "pruning_threshold: " << pruning_threshold << endl
       << "threshold: " << threshold << endl
       << "A_0: " << A_0 << endl
       << "minimum_segment_length: " << minimum_segment_length << endl
       << "sigma: " << sigma << endl
       << "start_movern " << start_movern << endl
       << "d_movern: " << d_movern << endl
       << "n_movern: " << n_movern << endl
       << "target_nodes: " << target_nodes << endl
       << "n_iterarions: " << n_iterations << endl
       << "fraction_dchi_for_variation: " << fraction_dchi_for_variation << endl
       << "vertical interval: " << vertical_interval << endl
       << "horizontal interval: " << horizontal_interval << endl
       << "area thinning fraction for SA analysis: " << area_thin_frac << endl
       << "target_skip is: " << target_skip << endl;


  string jn_name = itoa(junction_number);
  string uscore = "_";
  jn_name = uscore+jn_name;
  file_info_in.close();

  string DEM_f_name = path_name+DEM_name+fill_ext;
  string DEM_bil_extension = "bil";

  // set no flux boundary conditions
  vector<string> boundary_conditions(4);
  boundary_conditions[0] = "No";
  boundary_conditions[1] = "no flux";
  boundary_conditions[2] = "no flux";
  boundary_conditions[3] = "No flux";


  // load the filled DEM
  LSDRaster filled_topo_test((path_name+DEM_name+fill_ext), DEM_bil_extension);

  // get a flow info object
  LSDFlowInfo FlowInfo(boundary_conditions,filled_topo_test);

  // calcualte the distance from outlet
  LSDRaster DistanceFromOutlet = FlowInfo.distance_from_outlet();
  LSDIndexRaster ContributingPixels = FlowInfo.write_NContributingNodes_to_LSDIndexRaster();

  // get the sources
  vector<int> sources;
  sources = FlowInfo.get_sources_index_threshold(ContributingPixels, threshold);

  // now get the junction network
  LSDJunctionNetwork ChanNetwork(sources, FlowInfo);

  // now get a junction and look for the longest channel upstream
  cout << "creating main stem" << endl;
  LSDIndexChannel main_stem = ChanNetwork.generate_longest_index_channel_in_basin(junction_number, FlowInfo, DistanceFromOutlet);
        cout << "got main stem channel, with n_nodes " << main_stem.get_n_nodes_in_channel() <<  endl;

  string Basin_name = "_basin";
  LSDIndexRaster BasinArray = ChanNetwork.extract_basin_from_junction(junction_number,junction_number,FlowInfo);
  BasinArray.write_raster((path_name+DEM_name+Basin_name+jn_name),DEM_bil_extension);

  // now get the best fit m over n for all the tributaries
  int organization_switch = 1;
  int pruning_switch = 1;
  LSDIndexChannelTree ChannelTree(FlowInfo, ChanNetwork, junction_number, organization_switch,
                                        DistanceFromOutlet, pruning_switch, pruning_threshold);

  // print a file that can be ingested bt the chi fitting algorithm
  string Chan_fname = "_ChanNet";
  string Chan_ext = ".chan";
  string Chan_for_chi_ingestion_fname = path_name+DEM_name+Chan_fname+jn_name+Chan_ext;
  ChannelTree.print_LSDChannels_for_chi_network_ingestion(FlowInfo,
                             filled_topo_test, DistanceFromOutlet, Chan_for_chi_ingestion_fname);
  ChannelTree.convert_chan_file_for_ArcMap_ingestion(Chan_for_chi_ingestion_fname);

}
int main (int nNumberofArgs,char *argv[])
{
  
  //Test for correct input arguments
	if (nNumberofArgs!=7)
	{
		cout << "FATAL ERROR: wrong number of inputs. The program needs the path (with trailing slash), the filename prefix, window radius, "; 
    cout << "basin order, a switch to use or exclude floodplains and a switch to write rasters if desired." << endl;
		exit(EXIT_SUCCESS);
	}
  
  //load input arguments
  string path = argv[1];
	string filename = argv[2];
  float window_radius = atof(argv[3]); //6
  int BasinOrder = atoi(argv[4]);  //2
  int FloodplainSwitch = atoi(argv[5]);
  int WriteRasters = atoi(argv[6]);  //0 (do not write rasters) or 1 (write rasters) 
  
  //set boundary conditions
  vector<string> BoundaryConditions(4, "No Flux");

  //load dem
  LSDRaster DEM((path+filename+"_dem"), "flt");  
  
  //Fill 
  float MinSlope = 0.0001;
  LSDRaster FilledDEM = DEM.fill(MinSlope);
  
  //surface fitting
  vector<int> raster_selection;
  
  raster_selection.push_back(0);
  raster_selection.push_back(1); //slope 
  raster_selection.push_back(1); //aspect
  raster_selection.push_back(1); //curvature
  raster_selection.push_back(1); //plan curvature
  raster_selection.push_back(0); 
  raster_selection.push_back(0);
  raster_selection.push_back(0);

  vector<LSDRaster> Surfaces = FilledDEM.calculate_polyfit_surface_metrics(window_radius, raster_selection);
  LSDRaster slope = Surfaces[1];
  LSDRaster aspect = Surfaces[2];   
  
  cout << "\nGetting drainage network and basins\n" << endl;

  // get a flow info object
	LSDFlowInfo FlowInfo(BoundaryConditions,FilledDEM);
  
  //get stream net from channel heads
  vector<int> sources = FlowInfo.Ingest_Channel_Heads((path+filename+"_dem_CH"), "flt"); //swap to csv? 
  LSDJunctionNetwork ChanNetwork(sources, FlowInfo);
  LSDIndexRaster StreamNetwork = ChanNetwork.StreamOrderArray_to_LSDIndexRaster();

  //load floodplain and merge with the channel network if required, otherwise the 
  //floodplain mask will only contain the channel data
  LSDIndexRaster ChannelAndFloodplain;

  if (FloodplainSwitch == 1){
    LSDIndexRaster Floodplains((path+filename+"_FloodPlain"), "flt");
    ChannelAndFloodplain = StreamNetwork.MergeChannelWithFloodplain(Floodplains);
  }
  else{
    ChannelAndFloodplain = StreamNetwork;
  }
                                                         
  //Extract basins based on input stream order
  vector< int > basin_junctions = ChanNetwork.ExtractBasinJunctionOrder(BasinOrder, FlowInfo);
  LSDIndexRaster Basin_Raster = ChanNetwork.extract_basins_from_junction_vector(basin_junctions, FlowInfo);
  
  cout << "\nExtracting hilltops and hilltop curvature" << endl;
  
  // extract hilltops - no critical slope filtering is performed here
  LSDRaster hilltops = ChanNetwork.ExtractRidges(FlowInfo);   
     
  //get hilltop curvature using filter to remove positive curvatures         
  LSDRaster cht_raster = FilledDEM.get_hilltop_curvature(Surfaces[3], hilltops);
  LSDRaster CHT = FilledDEM.remove_positive_hilltop_curvature(cht_raster);  
  
  //get d infinity flowdirection and flow area
  Array2D<float> dinf = FilledDEM.D_inf_FlowDir();
  LSDRaster dinf_rast = FilledDEM.LSDRasterTemplate(dinf);
  LSDRaster DinfArea = FilledDEM.D_inf_units();
  
  cout << "Starting hilltop flow routing\n" << endl;
  
  //start of Hilltop flow routing
  string prefix = (path+filename+"_dreich_");  //set a path to write the hillslope length data to, based on the input path and filename given by the user
  
  // these params do not need changed during normal use of the HFR algorithm
  bool print_paths_switch = false;
  int thinning = 1;
  string trace_path = "";
  bool basin_filter_switch = false;                          
  vector<int> Target_Basin_Vector;

  //run HFR    
  vector< Array2D<float> > HFR_Arrays = FlowInfo.HilltopFlowRouting(FilledDEM, hilltops, slope, ChannelAndFloodplain, aspect, prefix, Basin_Raster, Surfaces[4], print_paths_switch, thinning, trace_path, basin_filter_switch, Target_Basin_Vector);
   
  LSDRaster HFR_LH = hilltops.LSDRasterTemplate(HFR_Arrays[1]);
  LSDRaster HFR_Slope = hilltops.LSDRasterTemplate(HFR_Arrays[2]);
  LSDRaster relief = hilltops.LSDRasterTemplate(HFR_Arrays[3]);
  //end of HFR 

  //create lsdbasin objects in a loop over each junction number
  vector< LSDBasin > Basins;

  //slope area plotting parameters - these defaults are usually fine
  float log_bin_width = 0.1;
  int SplineResolution = 10000;
  int bin_threshold = 0;
  float CriticalSlope = 1.2; //this needs modified to generate proper E*R* data
  
  cout << "\nCreating each LSDBasin" << endl;
  
  //loop over each basin, generating an LSDBasin object which contains that basin's measurements
  for (int w = 0; w < int(basin_junctions.size()); ++w){
    
    cout << (w+1) << " / " << basin_junctions.size() << endl;
    
    LSDBasin Basin(basin_junctions[w], FlowInfo, ChanNetwork);
    Basin.set_FlowLength(StreamNetwork, FlowInfo);
    Basin.set_DrainageDensity();
    Basin.set_all_HillslopeLengths(FlowInfo, HFR_LH, slope, DinfArea, log_bin_width, SplineResolution, bin_threshold);
    Basin.set_SlopeMean(FlowInfo, slope);
    Basin.set_AspectMean(FlowInfo, aspect);
    Basin.set_ElevationMean(FlowInfo, FilledDEM);
    Basin.set_ReliefMean(FlowInfo, relief);
    Basin.set_CHTMean(FlowInfo, CHT);
    Basin.set_EStar_RStar(CriticalSlope);
    
    Basins.push_back(Basin);
                             
  }
 
  //create a filestream to write the output data
  // use the input arguments to generate a path and filename for the output file
  ofstream WriteData;                 
  stringstream ss;
  ss << path << filename << "_dreich_PaperData.txt";                
  WriteData.open(ss.str().c_str());

  //write headers
  WriteData << "BasinID HFR_mean HFR_median HFR_stddev HFR_stderr HFR_Nvalues HFR_range HFR_min HFR_max SA_binned_LH SA_Spline_LH LH_Density Area Basin_Slope_mean Basin_Slope_median Basin_Slope_stddev Basin_Slope_stderr Basin_Slope_Nvalues Basin_Slope_range Basin_Slope_min Basin_Slope_max Basin_elev_mean Basin_elev_median Basin_elev_stddev Basin_elev_stderr Basin_elev_Nvalues Basin_elev_Range Basin_elev_min Basin_elev_max Aspect_mean CHT_mean CHT_median CHT_stddev CHT_stderr CHT_Nvalues CHT_range CHT_min CHT_max EStar RStar HT_Slope_mean HT_Slope_median HT_Slope_stddev HT_Slope_stderr HT_Slope_Nvalues HT_Slope_range HT_Slope_min HT_Slope_max HT_relief_mean HT_relief_median HT_relief_stddev HT_relief_stderr HT_relief_Nvalues HT_relief_range HT_relief_min HT_relief_max" << endl;

  cout << "\nWriting data to file\n" << endl;

  //write all data to the opened file, ensuring that there are data points to be written in each basin                                         
  for (int q = 0; q < int(Basins.size()); ++q){
    // only work where we have data points
    if (Basins[q].CalculateNumDataPoints(FlowInfo, HFR_LH) != 0 && Basins[q].CalculateNumDataPoints(FlowInfo, slope) != 0 && Basins[q].CalculateNumDataPoints(FlowInfo, FilledDEM) != 0 && Basins[q].CalculateNumDataPoints(FlowInfo, CHT) != 0 && Basins[q].CalculateNumDataPoints(FlowInfo, HFR_Slope) != 0 && Basins[q].CalculateNumDataPoints(FlowInfo, relief) != 0){
      
      // BasinID
      WriteData << Basins[q].get_Junction()<< " ";
      
      //HFR
      WriteData << Basins[q].get_HillslopeLength_HFR() << " " << Basins[q].CalculateBasinMedian(FlowInfo, HFR_LH) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, HFR_LH) << " " << Basins[q].CalculateBasinStdError(FlowInfo, HFR_LH) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, HFR_LH) << " " << Basins[q].CalculateBasinRange(FlowInfo, HFR_LH) << " " << Basins[q].CalculateBasinMin(FlowInfo, HFR_LH) << " " << Basins[q].CalculateBasinMax(FlowInfo, HFR_LH)<< " ";         
      
      //SA_Bins
      WriteData << Basins[q].get_HillslopeLength_Binned()<< " ";
      
      //SA_Spline
      WriteData << Basins[q].get_HillslopeLength_Spline()<< " ";
      
      //Density
      WriteData << Basins[q].get_HillslopeLength_Density()<< " ";
      
      //Area
      WriteData << Basins[q].get_Area()<< " ";
      
      //Slope_Basin
      WriteData << Basins[q].get_SlopeMean() << " " << Basins[q].CalculateBasinMedian(FlowInfo, slope) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, slope) << " " << Basins[q].CalculateBasinStdError(FlowInfo, slope) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, slope) << " " << Basins[q].CalculateBasinRange(FlowInfo, slope) << " " << Basins[q].CalculateBasinMin(FlowInfo, slope) << " " << Basins[q].CalculateBasinMax(FlowInfo, slope)<< " ";
      
      //Elev_Basin
      WriteData << Basins[q].get_ElevationMean() << " " << Basins[q].CalculateBasinMedian(FlowInfo, FilledDEM) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, FilledDEM) << " " << Basins[q].CalculateBasinStdError(FlowInfo, FilledDEM) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, FilledDEM) << " " << Basins[q].CalculateBasinRange(FlowInfo, FilledDEM) << " " << Basins[q].CalculateBasinMin(FlowInfo, FilledDEM) << " " << Basins[q].CalculateBasinMax(FlowInfo, FilledDEM)<< " ";
      
      //Aspect_Basin
      WriteData << Basins[q].get_AspectMean()<< " ";
      
      //CHT
      WriteData << Basins[q].get_CHTMean() << " " << Basins[q].CalculateBasinMedian(FlowInfo, CHT) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, CHT) << " " << Basins[q].CalculateBasinStdError(FlowInfo, CHT) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, CHT) << " " << Basins[q].CalculateBasinRange(FlowInfo, CHT) << " " << Basins[q].CalculateBasinMin(FlowInfo, CHT) << " " << Basins[q].CalculateBasinMax(FlowInfo, CHT) << " ";
      
      //EStar
      WriteData << Basins[q].get_EStar()<< " ";
      
      //RStar
      WriteData << Basins[q].get_RStar()<< " ";
      
      //Slope_mean
      WriteData << Basins[q].CalculateBasinMean(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinMedian(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinStdError(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinRange(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinMin(FlowInfo, HFR_Slope) << " " << Basins[q].CalculateBasinMax(FlowInfo, HFR_Slope)<< " ";
      
      //Relief_mean
      WriteData << Basins[q].get_ReliefMean() << " " << Basins[q].CalculateBasinMedian(FlowInfo, relief) << " " << Basins[q].CalculateBasinStdDev(FlowInfo, relief) << " " << Basins[q].CalculateBasinStdError(FlowInfo, relief) << " " << Basins[q].CalculateNumDataPoints(FlowInfo, relief) << " " << Basins[q].CalculateBasinRange(FlowInfo, relief) << " " << Basins[q].CalculateBasinMin(FlowInfo, relief) << " " << Basins[q].CalculateBasinMax(FlowInfo, relief)<< "\n";
  
    }    
  } 
   
  // close the output file
  WriteData.close();

  //if the user requests the raster to be written, write the rasters
  if (WriteRasters == 1){
    cout << "Writing Rasters\n" << endl;                                   
   // FilledDEM.write_raster((path+filename+"_Fill"), "flt");
    Surfaces[1].write_raster((path+filename+"_dreich_Slope"),"flt");
    //Surfaces[2].write_raster((path+filename+"_Aspect"),"flt");
    //Surfaces[3].write_raster((path+filename+"_Curvature"),"flt");
    //StreamNetwork.write_raster((path+filename+"_STNET"), "flt"); 
    //Basin_Raster.write_raster((path+filename+"_Basins"), "flt"); 
    CHT.write_raster((path+filename+"_dreich_CHT"),"flt");
    HFR_LH.write_raster((path+filename+"_dreich_HFR_LH"),"flt"); 
    HFR_Slope.write_raster((path+filename+"_dreich_HFR_SLP"),"flt");
    relief.write_raster((path+filename+"_dreich_Relief"),"flt");
    
    //perform a hillshade
    //LSDRaster Hillshade = FilledDEM.hillshade(45.0,315.0,1.0);
    //Hillshade.write_raster((path+filename+"_HS"),"flt");
  
  }
}
int main (int nNumberofArgs,char *argv[])
{
	//Test for correct input arguments
	if (nNumberofArgs!=3)
	{
		cout << "FATAL ERROR: wrong number inputs. The program needs the path name and the file name" << endl;
		exit(EXIT_SUCCESS);
	}

	string path_name = argv[1];
	string f_name = argv[2];

	cout << "The path is: " << path_name << " and the filename is: " << f_name << endl;

	string full_name = path_name+f_name;

	ifstream file_info_in;
	file_info_in.open(full_name.c_str());
	if( file_info_in.fail() )
	{
		cout << "\nFATAL ERROR: the header file \"" << full_name
		     << "\" doesn't exist" << endl;
		exit(EXIT_FAILURE);
	}

	string DEM_name;
	string fill_ext = "_fill";
	file_info_in >> DEM_name;
	int threshold;
	float Minimum_Slope;
	float curv_threshold;
	float minimum_catchment_area;

	file_info_in >> Minimum_Slope >> threshold >> curv_threshold >> minimum_catchment_area;

	// get some file names
	string DEM_f_name = path_name+DEM_name+fill_ext;
	string DEM_flt_extension = "bil";

	// load the DEM
	LSDRaster topo_test((path_name+DEM_name), DEM_flt_extension);
  LSDRasterSpectral SpectralRaster(topo_test);                        
//   int FilterType = 2;
//   float FLow = 0.01;
//   float FHigh = 0.1;
//   LSDRaster topo_test_filtered = SpectralRaster.fftw2D_filter(FilterType, FLow, FHigh);
  LSDRaster topo_test_wiener = SpectralRaster.fftw2D_wiener();
  int border_width = 100;	
//   topo_test_filtered = topo_test_filtered.border_with_nodata(border_width);
	topo_test_wiener = topo_test_wiener.border_with_nodata(border_width);       
	
	// Set the no flux boundary conditions
  vector<string> boundary_conditions(4);
	boundary_conditions[0] = "No";
	boundary_conditions[1] = "no flux";
	boundary_conditions[2] = "no flux";
	boundary_conditions[3] = "No flux";
	
		// get the filled file
	cout << "Filling the DEM" << endl;
// 	LSDRaster filled_topo_test = topo_test_filtered.fill(Minimum_Slope);
	LSDRaster filled_topo_test = topo_test_wiener.fill(Minimum_Slope);
	filled_topo_test.write_raster((DEM_f_name),DEM_flt_extension);
  
  //get a FlowInfo object
	LSDFlowInfo FlowInfo(boundary_conditions,filled_topo_test); 
	LSDIndexRaster ContributingPixels = FlowInfo.write_NContributingNodes_to_LSDIndexRaster();	
	vector<int> sources;
	sources = FlowInfo.get_sources_index_threshold(ContributingPixels, threshold); 

  // now get the junction network
	LSDJunctionNetwork ChanNetwork(sources, FlowInfo);
	
	// Get the valleys using the contour curvature
	
  int surface_fitting_window_radius = 7;
  int surface_fitting_window_radius_LW = 25;
  vector<LSDRaster> surface_fitting, surface_fitting_LW;
  LSDRaster tan_curvature;
  LSDRaster tan_curvature_LW;
  string curv_name = "_tan_curv";
  vector<int> raster_selection(8, 0);
  raster_selection[6] = 1;
  surface_fitting = topo_test_wiener.calculate_polyfit_surface_metrics(surface_fitting_window_radius, raster_selection);
  surface_fitting_LW = topo_test_wiener.calculate_polyfit_surface_metrics(surface_fitting_window_radius_LW, raster_selection);
  
  for(int i = 0; i<int(raster_selection.size()); ++i)
	{
		if(raster_selection[i]==1)
		{
      tan_curvature = surface_fitting[i];
      tan_curvature.write_raster((path_name+DEM_name+curv_name), DEM_flt_extension);
      tan_curvature_LW = surface_fitting[i];
      tan_curvature_LW.write_raster((path_name+DEM_name+curv_name+"_LW"), DEM_flt_extension);
    }
  }

	string CH_name = "_CH_Pelletier";
	Array2D<float> topography = filled_topo_test.get_RasterData();
	Array2D<float> curvature = tan_curvature.get_RasterData();
	Array2D<float> curvature_LW = tan_curvature_LW.get_RasterData();
	cout << "\tLocating channel heads..." << endl;
  vector<int> ChannelHeadNodes = ChanNetwork.calculate_pelletier_channel_heads_DTM(FlowInfo, topography, curv_threshold, curvature,curvature_LW);
  
  // Now filter out false positives along channel according to a threshold 
  // catchment area
  cout << "\tFiltering out false positives..." << endl;
  LSDJunctionNetwork ChanNetworkNew(ChannelHeadNodes, FlowInfo);
	vector<int> ChannelHeadNodesFilt;
  int count = 0;
  for(int i = 0; i<int(ChannelHeadNodes.size()); ++i)
	{
    int upstream_junc = ChanNetworkNew.get_Junction_of_Node(ChannelHeadNodes[i], FlowInfo);
    int test_node = ChanNetworkNew.get_penultimate_node_from_stream_link(upstream_junc, FlowInfo);
    float catchment_area = float(FlowInfo.retrieve_contributing_pixels_of_node(test_node)) * FlowInfo.get_DataResolution();
    if (catchment_area >= minimum_catchment_area) ChannelHeadNodesFilt.push_back(ChannelHeadNodes[i]);
    else ++count;
  }
  cout << "\t...removed " << count << " nodes out of " << ChannelHeadNodes.size() << endl;
  FlowInfo.print_vector_of_nodeindices_to_csv_file(ChannelHeadNodesFilt,(path_name+DEM_name+CH_name));
  //LSDIndexRaster Channel_heads_raster = FlowInfo.write_NodeIndexVector_to_LSDIndexRaster(ChannelHeadNodesFilt);
  //Channel_heads_raster.write_raster((path_name+DEM_name+CH_name),DEM_flt_extension);
	
	//create a channel network based on these channel heads
	LSDJunctionNetwork NewChanNetwork(ChannelHeadNodesFilt, FlowInfo);
  LSDIndexRaster SOArrayNew = NewChanNetwork.StreamOrderArray_to_LSDIndexRaster();
	string SO_name_new = "_SO_Pelletier";
	
	SOArrayNew.write_raster((path_name+DEM_name+SO_name_new),DEM_flt_extension);	
                              
}