//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This is an incredibly rudimentary function used to modify landslide raster
// It takes a few rasters from the
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDSoilHydroRaster::NaiveLandslide(LSDRaster& FilledElevation, int initiationPixels,
                                      int MinPixels, float landslide_thickness)
{
  // Get a flow info object
  // 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";


  // some values from the rasters
  float local_elev;
  float local_mask;

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

  // get the contributing pixels
  LSDIndexRaster ContributingPixels = FlowInfo.write_NContributingNodes_to_LSDIndexRaster();
  vector<int> sources = FlowInfo.get_sources_index_threshold(ContributingPixels, initiationPixels);

  // get a value vector for the landslides
  vector<float> landslide_thicknesses;
  for (int i = 0; i< int(sources.size()); i++)
  {
    landslide_thicknesses.push_back(landslide_thickness);
  }


  // get the mask
  LSDRaster Mask = FlowInfo.get_upslope_node_mask(sources,landslide_thicknesses);

  // now set all points that have elevation data but not landslide data to
  // the value of the landslide thickness, removing data that is below the minium
  // pixel area
  for (int row = 0; row<NRows; row++)
  {
    for (int col = 0; col<NCols; col++)
    {
      local_elev =  FilledElevation.get_data_element(row,col);
      local_mask =  Mask.get_data_element(row,col);

      RasterData[row][col] = local_mask;

      // Turn nodata points into 0s
      if( local_mask == NoDataValue)
      {
        RasterData[row][col] = 0.0;
      }

      // remove data where there is no topographic information
      if( local_elev == NoDataValue)
      {
        RasterData[row][col] = NoDataValue;
      }
    }
  }
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Calculate w, a hyrdological index, used in the factor of safety equation.
// Call with the ratio of recharge to transmissivity.
// SWDG 13/6/16
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
LSDSoilHydroRaster LSDSoilHydroRaster::Calculate_w(LSDRaster& Slope, LSDRaster& DrainageArea){

  Array2D<float> w(NRows, NCols, NoDataValue);

  for (int i = 1; i < NRows - 1; ++i){
    for (int j = 1; j < NCols - 1; ++j){

      if (RasterData[i][j] != NoDataValue){

        float value = RasterData[i][j] * (DrainageArea.get_data_element(i,j)/sin(Slope.get_data_element(i,j)));
        if (value < 1.0){
          w[i][j] = value;
        }
        else{
          w[i][j] = 1.0;
        }

      }
    }
  }

  LSDSoilHydroRaster output(NRows,NCols,XMinimum,YMinimum,DataResolution,NoDataValue,w,GeoReferencingStrings);
  return output;

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This prints a chi map to csv with an area threshold in m^2
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::chi_map_to_csv(LSDFlowInfo& FlowInfo, string chi_map_fname, 
                                 float A_0, float m_over_n, float area_threshold)
{
  
  ofstream chi_map_csv_out;
  chi_map_csv_out.open(chi_map_fname.c_str());
  
  chi_map_csv_out.precision(9);
  
  float chi_coord;
  double latitude,longitude;
  LSDCoordinateConverterLLandUTM Converter;
  
  chi_map_csv_out << "latitude,longitude,chi" << endl;
  
  LSDRaster Chi = FlowInfo.get_upslope_chi_from_all_baselevel_nodes(m_over_n, A_0, area_threshold);
  
  float NDV = Chi.get_NoDataValue();

  for(int row = 0; row<NRows; row++)
  {
    for(int col = 0; col<NCols; col++)
    {
      chi_coord =  Chi.get_data_element(row,col);
      
      if (chi_coord != NDV)
      {
        get_lat_and_long_locations(row, col, latitude, longitude, Converter);
        chi_map_csv_out << latitude << "," << longitude  << "," << chi_coord << endl;
      }
    }
  }
  
  chi_map_csv_out.close();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=-=-=-=-=-=-=-=-=-
// This function prints a chan file for assimilation into the chi analysis, 
// but in this cases uses a discharge rather than a drainage area
//
// the file format is
// channel_number node_index node_on_reciever row column flow_dist elevation drainage_area
//
// SMM 07/05/2015
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void LSDIndexChannelTree::print_LSDChannels_for_chi_network_ingestion(LSDFlowInfo& FlowInfo,
                             LSDRaster& Elevation_Raster, LSDRaster& FlowDistance, string fname,
                             LSDRaster& Discharge)
{
  if (organization_switch != 1)
  {
    cout << "LSDIndexChannelTree you can't run LSDIndexChannelTree::retrieve_LSDChannels_from_tree" << endl;
    cout << "with this channel organization, organization switch: " << organization_switch << endl;
    exit(EXIT_FAILURE);
  }

  // open the outfile
  ofstream channelfile_out;
  channelfile_out.open(fname.c_str());

  channelfile_out.precision(10);

  float m_over_n = 0.5;
  float A_0 = 1;

  // get the vector of channels
  vector<LSDChannel> vector_of_channels = retrieve_LSDChannels_from_tree(m_over_n, A_0, FlowInfo,Elevation_Raster);

  int n_channels = vector_of_channels.size();
  int n_nodes_in_channel;
  int node,row,col;
  float elev,chi,drain_area,flow_dist,this_discharge;

  // first print out some data about the dem
  channelfile_out << get_NRows() << endl;
  channelfile_out << get_NCols() << endl;
  channelfile_out << get_XMinimum() << endl;
  channelfile_out << get_YMinimum() << endl;
  channelfile_out << get_DataResolution() << endl;
  channelfile_out << get_NoDataValue() << endl;

  //loop through the channels
  for (int i = 0; i< n_channels; i++)
  {
    // get the number of nodes in the channel
    n_nodes_in_channel =IndexChannelVector[i].get_n_nodes_in_channel();

    // now loop through the channel, printing out the data.
    for(int ch_node= 0; ch_node<n_nodes_in_channel; ch_node++)
    {
      IndexChannelVector[i].get_node_row_col_in_channel(ch_node, node, row, col);
      vector_of_channels[i].retrieve_node_information(ch_node, elev, chi, drain_area);
      flow_dist = FlowDistance.get_data_element(row,col);
      this_discharge = Discharge.get_data_element(row,col);

      // print data to file
      channelfile_out << i << " " << receiver_channel[i] << " " << node_on_receiver_channel[i] << " "
                      << node << " " << row << " " << col << " " << flow_dist << " "
                      << " " << elev << " " << this_discharge << endl;
    }
  }

  channelfile_out.close();

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=-=-=-=-=-=-=-=-=-
// Same as above but also reports the discharge
//
// SMM 06/05/2015
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDIndexChannelTree::convert_chan_file_for_ArcMap_ingestion(string fname, LSDRaster& DrainageArea, LSDRaster& Discharge)
{

  // open the outfile
  ifstream channelfile_in;
  channelfile_in.open(fname.c_str());

  unsigned dot = fname.find_last_of(".");

  string prefix = fname.substr(0,dot);
  //string suffix = str.substr(dot);
    string insert = "_for_Arc.csv";
    string outfname = prefix+insert;

    cout << "the Arc channel filename is: " << outfname << endl;

    ofstream ArcChan_out;
    ArcChan_out.open(outfname.c_str());
    ArcChan_out.precision(10);

  // print the first line of the arcchan. This is going to be comma seperated!
  ArcChan_out << "id,x,y,channel,reciever_channel,node_on_reciever_channel,node,row,col,flow_distance_m,elevation_m,drainage_area_m2,discharge_m2_times_precipunits" << endl;

  // now go throught the file, collecting the data
  int id,ch,rc,norc,n,r,c;
  float fd,elev,da;
  float x,y;

  float xll;
  float yll;
  float datares;
  float ndv;
  int nrows;
  int ncols;
  float this_discharge;
  float this_da;

  // read in the first lines with DEM information
  channelfile_in >> nrows >> ncols >> xll >> yll >> datares >> ndv;
  id = 0;

  // now loop through the file, calculating x and y locations as you go
  while(channelfile_in >> ch >> rc >> norc >> n >> r >> c >> fd >> elev >> da)
  {
    id++;
    x = xll + float(c)*datares + 0.5*datares;
    y = yll + float(nrows-r)*datares - 0.5*datares;		// this is because the DEM starts from the top corner

    this_discharge = Discharge.get_data_element(r,c);
    this_da = DrainageArea.get_data_element(r,c);

    ArcChan_out << id << "," << x << "," << y << "," << ch << "," << rc 
                << "," << norc << "," << n << "," << r << "," << c << ","
                << fd << "," << elev << "," << this_da << "," << this_discharge << endl;
  }

  channelfile_in.close();
  ArcChan_out.close();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Create function that takes the dimensions and georeferencing of a raster
// but then sets all data to value, setting the NoDataValues to
// the NoData of the raster
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDSoilHydroRaster::create(LSDRaster& OtherRaster, float value)
{
  NRows = OtherRaster.get_NRows();
  NCols = OtherRaster.get_NCols();
  XMinimum = OtherRaster.get_XMinimum();
  YMinimum = OtherRaster.get_YMinimum();
  DataResolution = OtherRaster.get_DataResolution();
  NoDataValue = OtherRaster.get_NoDataValue();
  GeoReferencingStrings = OtherRaster.get_GeoReferencingStrings();

  // set the raster data to be a certain value
  Array2D<float> data(NRows,NCols,NoDataValue);

  for (int row = 0; row <NRows; row++)
  {
    for (int col = 0; col<NCols; col++)
    {

      if (OtherRaster.get_data_element(row,col) != NoDataValue)
      {
        data[row][col] = value;
        //cout << value << endl;
      }
    }
  }

  RasterData = data.copy();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Calculate the the sinmap Stability Index (SI).
// This is a wrapper around a lightly modified port of the original sinmap 2.0 implementation.
// call with any SoilHydroRaster, it's values are used for identification of NoDataValues.
//
// SWDG 15/6/16
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
LSDSoilHydroRaster LSDSoilHydroRaster::Calculate_sinmap_SI(LSDRaster Slope, LSDRaster DrainageArea, LSDSoilHydroRaster lo_C, LSDSoilHydroRaster hi_C, LSDSoilHydroRaster lo_phi, LSDSoilHydroRaster hi_phi, LSDSoilHydroRaster lo_RoverT, LSDSoilHydroRaster hi_RoverT, LSDSoilHydroRaster lo_r, LSDSoilHydroRaster hi_r, LSDSoilHydroRaster lo_FS, LSDSoilHydroRaster hi_FS){

  Array2D<float> SI(NRows, NCols, NoDataValue);

  for (int i = 1; i < NRows - 1; ++i){
    for (int j = 1; j < NCols - 1; ++j){

      if (RasterData[i][j] != NoDataValue){
        SI[i][j] = StabilityIndex(Slope.get_data_element(i, j), DrainageArea.get_data_element(i, j), lo_C.get_data_element(i, j), hi_C.get_data_element(i, j), lo_phi.get_data_element(i, j), hi_phi.get_data_element(i, j), lo_RoverT.get_data_element(i, j), hi_RoverT.get_data_element(i, j), lo_r.get_data_element(i, j), hi_r.get_data_element(i, j), lo_FS.get_data_element(i, j), hi_FS.get_data_element(i, j));
      }
    }
  }

  LSDSoilHydroRaster output(NRows,NCols,XMinimum,YMinimum,DataResolution,NoDataValue,SI,GeoReferencingStrings);
  return output;

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Create function that just copies a raster into the hydro raster
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDSoilHydroRaster::create(LSDRaster& OtherRaster)
{
  NRows = OtherRaster.get_NRows();
  NCols = OtherRaster.get_NCols();
  XMinimum = OtherRaster.get_XMinimum();
  YMinimum = OtherRaster.get_YMinimum();
  DataResolution = OtherRaster.get_DataResolution();
  NoDataValue = OtherRaster.get_NoDataValue();
  GeoReferencingStrings = OtherRaster.get_GeoReferencingStrings();
  RasterData = OtherRaster.get_RasterData();

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Creates an LSDChiTools from an LSDRaster 
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::create(LSDRaster& 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 a raster
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDRasterInfo::create(LSDRaster& Raster)
{
      ///Number of rows.
  NRows = Raster.get_NRows();
  NCols = Raster.get_NCols();
  XMinimum = Raster.get_XMinimum();
  YMinimum = Raster.get_YMinimum();
  DataResolution = Raster.get_DataResolution();
  NoDataValue = Raster.get_NoDataValue();
  GeoReferencingStrings = Raster.get_GeoReferencingStrings();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This function calculates a snow thickenss (effective, in g cm^-2 for cosmogenic
// applications)  based on a bilinear model such as that of P Kirchner: http://escholarship.org/uc/item/9zn1c1mk#page-8
// The paper is here: http://www.hydrol-earth-syst-sci.net/18/4261/2014/hess-18-4261-2014.html
// This paper also agrees withy this general trend:
// http://www.the-cryosphere.net/8/2381/2014/tc-8-2381-2014.pdf
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDSoilHydroRaster::SetSnowEffDepthBilinear(float SlopeAscend, float SlopeDescend,
                          float PeakElevation, float PeakSnowpack, LSDRaster& Elevation)
{
  float LocalElevation;
  float ascendEffDepth;
  float descendEffDepth;
  float thisEffDepth = 0;

  for (int row = 0; row <NRows; row++)
  {
    for (int col = 0; col<NCols; col++)
    {
      if (RasterData[row][col] != NoDataValue)
      {
        LocalElevation = Elevation.get_data_element(row,col);

        if (LocalElevation != NoDataValue)
        {
          // get the effective depth on both the ascending and descending limb
          ascendEffDepth = SlopeAscend*(LocalElevation-PeakElevation)+PeakSnowpack;
          descendEffDepth = SlopeDescend*(LocalElevation-PeakElevation)+PeakSnowpack;

          // the correct depth is the lesser of the two
          if (ascendEffDepth < descendEffDepth)
          {
            thisEffDepth =  ascendEffDepth;
          }
          else
          {
            thisEffDepth = descendEffDepth;
          }

          // if the depth is less than zero, then set to zero
          if(thisEffDepth <0)
          {
            thisEffDepth = 0;
          }

          RasterData[row][col] =  thisEffDepth;

        }
        else        // if there ins't any elevation data, set the snow data to NoData
        {
          RasterData[row][col] = NoDataValue;
        }
      }
    }
  }
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This prints a chi map to csv with an area threshold in m^2. You feed it the chi map
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::chi_map_to_csv(LSDFlowInfo& FlowInfo, string chi_map_fname, 
                                 LSDRaster& chi_coord)
{
  
  ofstream chi_map_csv_out;
  chi_map_csv_out.open(chi_map_fname.c_str());
  
  
  
  float this_chi_coord;
  double latitude,longitude;
  LSDCoordinateConverterLLandUTM Converter;
  
  chi_map_csv_out << "latitude,longitude,chi" << endl;

  float NDV = chi_coord.get_NoDataValue();

  for(int row = 0; row<NRows; row++)
  {
    for(int col = 0; col<NCols; col++)
    {
      this_chi_coord = chi_coord.get_data_element(row,col);
      
      if (this_chi_coord != NDV)
      {
        get_lat_and_long_locations(row, col, latitude, longitude, Converter);
        chi_map_csv_out.precision(9);
        chi_map_csv_out << latitude << "," << longitude  << ",";
        chi_map_csv_out.precision(5);
        chi_map_csv_out << this_chi_coord << endl;
      }
    }
  }
  
  chi_map_csv_out.close();
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This function calculates a snow thickenss (effective, in g cm^-2 for cosmogenic
// applications)  based on a richard's equsion sigmoidal growth model
// It was propoesd to represent peak SWE so we cruedly apply it to average annual SWE
// see
// http://onlinelibrary.wiley.com/doi/10.1002/2015GL063413/epdf
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDSoilHydroRaster::SetSnowEffDepthRichards(float MaximumEffDepth, float MaximumSlope, float v,
                          float lambda, LSDRaster& Elevation)
{
  // Don't let V be less than or equal to zero
  if (v <= 0)
  {
    v = 0.001;
  }

  // some variables to speed up compuation
  float exp_term;
  float thisEffDepth = 0;
  float elev_mulitplier = (MaximumSlope/MaximumEffDepth)*pow((1+v),1+(1/v));
  float LocalElevation;

  for (int row = 0; row <NRows; row++)
  {
    for (int col = 0; col<NCols; col++)
    {
      if (RasterData[row][col] != NoDataValue)
      {
        LocalElevation = Elevation.get_data_element(row,col);

        if (LocalElevation != NoDataValue)
        {
          // get the effective depth using the richards sigmoidal gorth function
          exp_term = 1+v*exp(elev_mulitplier*(lambda-LocalElevation));
          thisEffDepth = MaximumEffDepth*pow(exp_term,-(1/v));

          // if the depth is less than zero, then set to zero
          if(thisEffDepth <0)
          {
            thisEffDepth = 0;
          }

          // update the data
          RasterData[row][col] =  thisEffDepth;

        }
        else        // if there ins't any elevation data, set the snow data to NoData
        {
          RasterData[row][col] = NoDataValue;
        }
      }
    }
  }
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Calculate the factor of safety using the sinmap definition.
// Call with the dimensionless cohesion (C) raster.
// SWDG 13/6/16
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
LSDSoilHydroRaster LSDSoilHydroRaster::Calculate_sinmap_Fs(LSDRaster& Slope, LSDSoilHydroRaster& w, LSDSoilHydroRaster& r, LSDSoilHydroRaster& phi){

  Array2D<float> Fs(NRows, NCols, NoDataValue);

  for (int i = 1; i < NRows - 1; ++i){
    for (int j = 1; j < NCols - 1; ++j){

      if (RasterData[i][j] != NoDataValue){
        Fs[i][j] = ( RasterData[i][j] + cos(Slope.get_data_element(i,j)) * (1.0-w.get_data_element(i,j)*r.get_data_element(i,j)) * tan(phi.get_data_element(i,j)) ) / sin(Slope.get_data_element(i,j));
      }
    }
  }

  LSDSoilHydroRaster output(NRows,NCols,XMinimum,YMinimum,DataResolution,NoDataValue,Fs,GeoReferencingStrings);
  return output;

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Calculate h, the soil depth normal to the slope, used in the factor of safety equation.
// Call with the soil thickness raster.
// SWDG 13/6/16
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
LSDSoilHydroRaster LSDSoilHydroRaster::Calculate_h(LSDRaster& Slope){

  Array2D<float> h(NRows, NCols, NoDataValue);

  for (int i = 1; i < NRows - 1; ++i){
    for (int j = 1; j < NCols - 1; ++j){

      if (RasterData[i][j] != NoDataValue){
        h[i][j] = RasterData[i][j] * cos(Slope.get_data_element(i,j));

      }
    }
  }

  LSDSoilHydroRaster output(NRows,NCols,XMinimum,YMinimum,DataResolution,NoDataValue,h,GeoReferencingStrings);
  return output;

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// this function prints chi values. It is used on the channel tree when channels are organized by links
// (that is organization switch == 0
//
// SMM 01/09/2012
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void LSDIndexChannelTree::print_chi_vs_elevation_from_channel_tree(LSDRaster& Elevation, LSDFlowInfo& FlowInfo, LSDJunctionNetwork& ChannelNetwork,
                                                     float m_over_n, float A_0, string chi_vs_elev_fname)
{

	if(organization_switch != 0)
	{
		cout << "LSDIndexChannelTree you can't run LSDIndexChannelTree::print_chi_vs_elevation_from_channel_tree with this channel organization" << endl;
		exit(EXIT_FAILURE);
	}

	int n_channels = IndexChannelVector.size();
	int n_nodes_in_link,current_node_index;
	vector< vector<float> > chi_vectors = calculate_chi_from_channel_tree(FlowInfo, ChannelNetwork,
                                                     m_over_n, A_0);

	// the chi iterator
  	vector< vector<float> >::iterator chi_iter;
    chi_iter =  chi_vectors.begin();
	float current_chi;
	float current_elev;
	int curr_row,curr_col;

	ofstream chi_elev_out;
	chi_elev_out.open(chi_vs_elev_fname.c_str());

	for (int i = 0; i<n_channels; i++)
	{
		n_nodes_in_link = IndexChannelVector[i].get_n_nodes_in_channel();

	  	for (int this_node = 0; this_node<n_nodes_in_link; this_node++)
		{
			current_node_index = IndexChannelVector[i].get_node_in_channel(this_node);
			current_chi  =  (*chi_iter)[this_node];
			FlowInfo.retrieve_current_row_and_col(current_node_index,curr_row,curr_col);
			current_elev = Elevation.get_data_element(curr_row,curr_col);

			//cout << "current_node: " << current_node_index << " and chi: " << current_chi << endl;
			//chi_elev_out << current_chi << " " << current_elev << endl;
		}
		chi_iter++;
	}
	chi_elev_out.close();

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=---=-=-=-=-=-=-=-=-=-=-=-=-
// this function prints chi and elevation, along with flow distance and the 
// number of the tributary it all goes to one file
//
// the file format is
// channel_number node_index row column flow_dist chi elevation drainage_area
//
// SMM 01/09/2012
//
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDIndexChannelTree::print_LSDChannels_from_tree(float m_over_n, float A_0, LSDFlowInfo& FlowInfo,
                             LSDRaster& Elevation_Raster, LSDRaster& FlowDistance, string fname)
{
  if (organization_switch != 1)
  {
    cout << "LSDIndexChannelTree you can't run LSDIndexChannelTree::retrieve_LSDChannels_from_tree" << endl;
    cout << "with this channel organization, organization switch: " << organization_switch << endl;
    exit(EXIT_FAILURE);
  }

  // open the outfile
  ofstream channelfile_out;
  channelfile_out.open(fname.c_str());

  // get the vector of channels
  vector<LSDChannel> vector_of_channels = retrieve_LSDChannels_from_tree(m_over_n, A_0, FlowInfo,Elevation_Raster);

  int n_channels = vector_of_channels.size();
  int n_nodes_in_channel;
  int node,row,col;
  float elev,chi,drain_area,flow_dist;
  //loop through the channels
  for (int i = 0; i< n_channels; i++)
  {
    // get the number of nodes in the channel
    n_nodes_in_channel =IndexChannelVector[i].get_n_nodes_in_channel();

    // now loop through the channel, printing out the data.
    for(int ch_node= 0; ch_node<n_nodes_in_channel; ch_node++)
    {
      IndexChannelVector[i].get_node_row_col_in_channel(ch_node, node, row, col);
      vector_of_channels[i].retrieve_node_information(ch_node, elev, chi, drain_area);
      flow_dist = FlowDistance.get_data_element(row,col);

      // print data to file
      channelfile_out << i << " " << node << " " << row << " " << col << " " << flow_dist << " "
                      << chi << " " << elev << " " << drain_area << endl;
    }
  }

  channelfile_out.close();

}
Beispiel #18
0
int main(int nNumberofArgs, char *argv[])
{
  //Test for correct input arguments
	if (nNumberofArgs!=5)
	{
		cout << "FATAL ERROR: wrong number of inputs. The program needs the path (with trailing slash), the filename prefix, the DEM file format, the window size in spatial units.";
		exit(EXIT_FAILURE);
	}

  //get input args
  string path = argv[1];
  string Prefix = argv[2];
  string DEM_Format = argv[3];
  int WindowSize = atoi(argv[4]);

  //surface fitting
  vector<int> raster_selection;
  raster_selection.push_back(0);
  raster_selection.push_back(1); //slope
  raster_selection.push_back(0);
	raster_selection.push_back(1); //curvature

  //set up a writer to write the output data
  ofstream WriteData;

  //create an output filename based on the dem name
  stringstream ss;

  ss << path << Prefix << "_ChtResData.txt";
  WriteData.open(ss.str().c_str());

  //write headers
  WriteData << "resoulution 2pc 25pc median mean 75pc 98pc minimum maximum" << endl;

  //array of resolutions to load
  int Resolutions[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

  // vectors to hold the stats about the fitted surface
  vector<float> Curv_vec;

	//set boundary conditions
  vector<string> BoundaryConditions(4, "No Flux");

  for (int a = 0; a < 10; ++a){

	  cout << "Processing DEM " << a+1 << " of " << "10" << endl;

		//load the DEM
    //build the string of the filename to load
		stringstream ss2;
		ss2 << path << Prefix << "_" << Resolutions[a] << "_DEM";
		LSDRaster DEM(ss2.str(), DEM_Format);

		//Fill
		float MinSlope = 0.0001;
		LSDRaster FilledDEM = DEM.fill(MinSlope);

	  int CurrentWindowSize = WindowSize;
	  vector<LSDRaster> Surfaces = FilledDEM.calculate_polyfit_surface_metrics(CurrentWindowSize, raster_selection);

		// get a flow info object
	  LSDFlowInfo FlowInfo(BoundaryConditions,FilledDEM);

	  //get stream net from channel heads
	  vector<int> sources = FlowInfo.Ingest_Channel_Heads((path+Prefix+"_CH"), "csv", 2);

	  LSDJunctionNetwork ChanNetwork(sources, FlowInfo);

		// extract hilltops
    LSDRaster hilltops = ChanNetwork.ExtractRidges(FlowInfo);
    LSDRaster Hilltops = ChanNetwork.ExtractHilltops(hilltops, Surfaces[1], 0.4);


    //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);

	  //go through the landscape and get every curvature value into a 1D vector
    Curv_vec = Flatten_Without_Nodata(CHT.get_RasterData(), CHT.get_NoDataValue());

    stringstream ss3;
    ss3 << path << Prefix << "_" << Resolutions[a] << "_Hist_CHT.txt";

    print_histogram(Curv_vec, 0.01, ss3.str());

    vector<float> Boxplot = BoxPlot(Curv_vec);

	  //write the values to the output file
	  WriteData << Resolutions[a] << " " << Boxplot[0] << " " << Boxplot[1] << " " << Boxplot[2] << " " << Boxplot[3] << " " << Boxplot[4] << " " << Boxplot[5] << " " << Boxplot[6] << " " << Boxplot[7];

		WriteData << endl;

  }
  WriteData.close();

}
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, the DEM file format, the window radius, ";
    cout << "basin order, and a switch to write rasters if desired." << endl;
		exit(EXIT_SUCCESS);
	}

  //load input arguments
  string Path = argv[1];
	string Prefix = argv[2];
  string DEM_Format = argv[3];
  float window_radius = atof(argv[4]); //6
  int BasinOrder = atoi(argv[5]);  //2
  int WriteRasters = atoi(argv[6]);  //0 (do not write rasters) or 1 (write rasters)

  //set up writers to write the output data
  stringstream ssLH;
  stringstream ssR;
  ssLH << Path << Prefix << "_LHResData_variable.txt";
  ssR << Path << Prefix << "_RResData_variable.txt";

  ofstream WriteLHData;
  WriteLHData.open(ssLH.str().c_str());
  ofstream WriteRData;
  WriteRData.open(ssR.str().c_str());

  //write headers
  WriteLHData << "resolution 2pc 25pc median mean 75pc 98pc minimum maximum" << endl;
  WriteRData << "resolution 2pc 25pc median mean 75pc 98pc minimum maximum" << endl;

  //set boundary conditions
  vector<string> BoundaryConditions(4, "No Flux");

  //array of resolutions to load
  int Resolutions[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30};

  for (int a = 0; a < 19; ++a){
	  cout << "Processing DEM " << a+1 << " of " << "19" << endl;

    //create an output filename based on the dem name and the resolution
    stringstream ss;
    ss << Path << Prefix << "_" << Resolutions[a];
    string Filename = ss.str();

    //load dem
    LSDRaster DEM((Filename + "_DEM"), DEM_Format);

    stringstream ssa;
    ssa << Path << Prefix << "_" << Resolutions[a] << "_variable";
    string Filename_variable = ssa.str();

    //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);

    int CurrentWindowSize = window_radius;

    vector<LSDRaster> Surfaces = FilledDEM.calculate_polyfit_surface_metrics(CurrentWindowSize, 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
    stringstream ss_ch;
    ss_ch << Path << "Pelletier/" << Prefix << "_" << Resolutions[a] << "_CH";

    vector<int> sources = FlowInfo.Ingest_Channel_Heads(ss_ch.str(), "bil");
    LSDJunctionNetwork ChanNetwork(sources, FlowInfo);
    LSDIndexRaster StreamNetwork = ChanNetwork.StreamOrderArray_to_LSDIndexRaster();

    //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);

    cout << "Starting hilltop flow routing\n" << endl;

    // 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, StreamNetwork, aspect, Filename_variable, 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 relief = hilltops.LSDRasterTemplate(HFR_Arrays[3]);

    //Filter Relief and LH data to remove any values < 2 pixels, as in Grieve et al (2015)
    LSDRaster LH1 = HFR_LH.RemoveBelow(2.0*Resolutions[a]);
    LSDRaster Relief1 = relief.RemoveBelow(2.0*Resolutions[a]);

    //Filter Relief and LH data to remove any values > 10000
    //These are created due to using 1m channel heads on low res data, and inadvertantly
    //sampling nodata values, which gives us massive relief values
    LSDRaster LH = LH1.RemoveAbove(10000);
    LSDRaster Relief = Relief1.RemoveAbove(10000);

    //go through the lh raster and get every value into a 1D vector
    vector<float> LH_vec = Flatten_Without_Nodata(LH.get_RasterData(), LH.get_NoDataValue());
    vector<float> Boxplot = BoxPlot(LH_vec);

    //write the values to the output file
    WriteLHData << Resolutions[a] << " " << Boxplot[0] << " " << Boxplot[1] << " " << Boxplot[2] << " " << Boxplot[3] << " " << Boxplot[4] << " " << Boxplot[5] << " " << Boxplot[6] << " " << Boxplot[7];

    WriteLHData << endl;

    stringstream ss3;
    ss3 << Path << Prefix << "_" << Resolutions[a] << "_Hist_LH_variable.txt";
    print_histogram(LH_vec, 1, ss3.str());

    //go through the relief raster and get every value into a 1D vector
    vector<float> R_vec = Flatten_Without_Nodata(Relief.get_RasterData(), Relief.get_NoDataValue());
    vector<float> Boxplot_R = BoxPlot(R_vec);

    //write the values to the output file
    WriteRData << Resolutions[a] << " " << Boxplot_R[0] << " " << Boxplot_R[1] << " " << Boxplot_R[2] << " " << Boxplot_R[3] << " " << Boxplot_R[4] << " " << Boxplot_R[5] << " " << Boxplot_R[6] << " " << Boxplot_R[7];

    WriteRData << endl;

    stringstream ss4;
    ss4 << Path << Prefix << "_" << Resolutions[a] << "_Hist_R_variable.txt";
    print_histogram(R_vec, 1, ss4.str());

    //if the user requests the rasters to be written, write the rasters
    if (WriteRasters == 1){
      cout << "Writing Rasters\n" << endl;

      Surfaces[1].write_raster((Filename + "_Slope_variable"), DEM_Format);
      CHT.write_raster((Filename + "_CHT_variable"), DEM_Format);
      LH.write_raster((Filename + "_HFR_LH_variable"), DEM_Format);
      Relief.write_raster((Filename + "_Relief_variable"), DEM_Format);

    }
  }
    WriteLHData.close();
    WriteRData.close();
}
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];
  
  // 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;
  
  cout << "=================================================================" << endl
       << "You are also loading a precipitation raster to get the discharge" << endl
       << "The precipitation raster should: " << endl
       << "1) Have units of m/yr" << endl
       << "Have the same prefix as the DEM, but will have the extension _PRECIP"<< endl
       << "For example, if the DEM is my_DEM.bil, the precip file will be" << endl
       << "my_DEM_precip.bil" << endl
       << "=================================================================" << 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";
  
  string precip_ext = "_PRECIP";
  string Precip_f_name = path_name+DEM_name+precip_ext;

  // 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();

  // calculate the discharge
  // note: not discharge yet, need to multiply by cell area
  LSDRaster VolumePrecipitation(Precip_f_name, DEM_bil_extension);
  float dx = VolumePrecipitation.get_DataResolution();
  
  // volume precipitation per time precipitation times the cell areas
  VolumePrecipitation.raster_multiplier(dx*dx);
  
  // discharge accumulates this precipitation
  LSDRaster Discharge = FlowInfo.upslope_variable_accumulator(VolumePrecipitation);

  string Q_ext = "_Q";
  string Q_f_name = path_name+DEM_name+Q_ext;
  Discharge.write_raster(Q_f_name,DEM_bil_extension);

  // 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);

  LSDRaster DrainageArea = FlowInfo.write_DrainageArea_to_LSDRaster();

  // print a file that can be ingested by 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,
                             Discharge);
  ChannelTree.convert_chan_file_for_ArcMap_ingestion(Chan_for_chi_ingestion_fname,DrainageArea,Discharge);

}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This function is a much more rudimentary version that mimics the
// channel steepness caluclations.
// chi needs tobe calculated outside of the function 
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::chi_map_automator_rudimentary(LSDFlowInfo& FlowInfo, 
                                    vector<int> source_nodes,
                                    vector<int> outlet_nodes,
                                    LSDRaster& Elevation, LSDRaster& FlowDistance, 
                                    LSDRaster& DrainageArea, LSDRaster& chi_coordinate, 
                                    int regression_nodes)
{

  // the data is stored in maps, for easier testing if a node has been
  // visited. 
  // You might consider having these as data elements in the object so you don't 
  // have to pass them
  map<int,float> gradient_data_map;
  map<int,float> intercept_data_map;
  map<int,float> R2_data_map;
  map<int,float> chi_coordinate_data_map;
  map<int,float> elevation_data_map;
  map<int,float> flow_distance_map;
  map<int,float> area_map;
  vector<int> node_order;
  
  // check if the number of nodes are odd .If not add 1
  if (regression_nodes % 2 == 0)
  {
    cout << "Hello user. You need an odd number of regression nodes." << endl;
    regression_nodes = regression_nodes+1;
    cout << " Changing your regression nodes to " << regression_nodes << endl;
  }
  
  // now get the midpoint
  int mp_nodes = (regression_nodes-1)/2;
  
  //cout << "The number of mp nodes is: " << mp_nodes << endl;
  
  // these keep track of the beginning and ending nodes of a given channel
  int channel_start_node;
  int channel_end_node;
  float channel_end_elevation;
  
  // vectors for holding the chi elevation data
  vector<float> chi_vec;
  vector<float> elev_vec;
  vector<float> empty_vec;
  
  // these are extracted from the channel segments using linear regression
  float intercept,gradient,R_squared;
  
  //float this_chi;
  //float this_elev;
  int this_mp_node;
  int this_end_node;
  int this_start_node;
  
  // these are for getting information out of the FlowInfo object
  int row,col, this_node;
  int r_node, r_row,r_col;          // reciever row and column. 

  // The way this works is that it starts at the top of a channel. It then works 
  // its way down and find the node that is the midpoint and the node that is the
  // end point. The midpoint node is where the data will be recorded.
  // It then puts the data from the start node to the end node into a vector 
  // and performs a linear regression of this vector. The regression data from these
  // vectors are recorded at the nodes.
  // We then want to cover all the nodes with data so what happens if some nodes
  // do not become midpoints? 
  // We could start at the top and get the first midpoint. 
  // From there we can work our way down checking if the top of the regression segment
  // is more than one node down from the end point...

  // get the number of channels
  int n_channels = int(source_nodes.size());
  // now loop through the channels
  for(int chan = 0; chan<n_channels; chan++)
  {
    channel_start_node = source_nodes[chan];
    channel_end_node = outlet_nodes[chan];
    
    // Get the elevation of the end node as a secondary check of the ending of the channel
    // segment
    FlowInfo.retrieve_current_row_and_col(channel_end_node,row,col);
    channel_end_elevation = Elevation.get_data_element(row,col);
    
    // reset the flag for ending the channel
    bool is_end_of_channel = false;

    // set the segment start node to the channel start node
    this_start_node = channel_start_node;

    // now retrieve the midpoint node
    this_node = channel_start_node;
    for(int n = 0; n<mp_nodes; n++)
    {
      FlowInfo.retrieve_receiver_information(this_node,r_node,r_row,r_col);
      this_node = r_node;
    }
    this_mp_node = this_node;
    this_node = r_node;
    
    // now go down one step
    FlowInfo.retrieve_receiver_information(this_node,r_node,r_row,r_col);
    this_node = r_node;
    
    // now get the end node
    for(int n = 0; n<mp_nodes; n++)
    {
      FlowInfo.retrieve_receiver_information(this_node,r_node,r_row,r_col);
      this_node = r_node;
    }
    this_end_node = this_node;
    
    //================================================
    // This loop is for bug checking
    //this_node = this_start_node;
    //do
    //{
    //  // get the elevation and chi vectors by following the flow
    //  cout << "This node is: " << this_node << endl;
    //  FlowInfo.retrieve_current_row_and_col(this_node,row,col);
    //  FlowInfo.retrieve_receiver_information(this_node,r_node,r_row,r_col);
    //  this_node = r_node;
    //}
    //while(this_node != this_end_node);
    //
    //cout << "And the midpoint node was: " << this_mp_node << endl;
    //================================================  
      
    // we search down the channel, collecting linear regressions at the 
    // midpoint of the intervals
    while (not is_end_of_channel)
    {
      // get a vector of chi and elevation from the start node to the end node
      chi_vec = empty_vec;
      elev_vec = empty_vec;
      
      // copy the data elements into the vecotrs. This is a little stupid
      // because one might just use a deque to pop the first element
      // and push the last, but the linear regression takes vectors, 
      // not deques so you would have to copy the deque element-wise anyway
      // If you wanted, you could speed this up by implementing a linear regression
      // of deques, but that will need to wait for another day. 
      this_node = this_start_node;
      do
      {
        // get the elevation and chi vectors by following the flow
        FlowInfo.retrieve_current_row_and_col(this_node,row,col);
        chi_vec.push_back(chi_coordinate.get_data_element(row,col));
        elev_vec.push_back(Elevation.get_data_element(row,col));
        
        FlowInfo.retrieve_receiver_information(this_node,r_node,r_row,r_col);
        this_node = r_node;
      } while(this_node != this_end_node);
      
      // do a linear regression on the segment
      least_squares_linear_regression(chi_vec,elev_vec, intercept, gradient, R_squared);
      
      // now add the intercept and gradient data to the correct node
      // only take data that has not been calculated before
      // The channels are in order of descending length so data from
      // longer channels take precidence. 
      if (gradient_data_map.find(this_mp_node) == gradient_data_map.end() )
      {
        FlowInfo.retrieve_current_row_and_col(this_mp_node,row,col);
        gradient_data_map[this_mp_node] = gradient; 
        intercept_data_map[this_mp_node] = intercept;
        R2_data_map[this_mp_node] = R_squared;
        chi_coordinate_data_map[this_mp_node] = chi_coordinate.get_data_element(row,col);
        elevation_data_map[this_mp_node] = Elevation.get_data_element(row,col);
        flow_distance_map[this_mp_node] = FlowDistance.get_data_element(row,col);
        area_map[this_mp_node] = DrainageArea.get_data_element(row,col);
        node_order.push_back(this_mp_node);
      }
      else
      {
        is_end_of_channel = true;
      }
      
      // now move all the nodes down one
      FlowInfo.retrieve_receiver_information(this_start_node,r_node,r_row,r_col);
      this_start_node = r_node;
      
      FlowInfo.retrieve_receiver_information(this_mp_node,r_node,r_row,r_col);
      this_mp_node = r_node;
      
      FlowInfo.retrieve_receiver_information(this_end_node,r_node,r_row,r_col);
      this_end_node = r_node;
      
      // check if we are at the end of the channel
      if (this_end_node == channel_end_node)
      {
        is_end_of_channel = true;
      }
      // also check if the end node is lower elevation than the end node,
      // just to try and stop the channel passing the end node
      FlowInfo.retrieve_current_row_and_col(this_end_node,row,col);
      if (channel_end_elevation > Elevation.get_data_element(row,col))
      {
        is_end_of_channel = true;
      }
    }          // This finishes the regression segment loop
  }            // This finishes the channel and resets channel start and end nodes
  
  // set the data objects
  M_chi_data_map = gradient_data_map; 
  b_chi_data_map = intercept_data_map;
  elev_data_map = elevation_data_map;
  chi_data_map = chi_coordinate_data_map;
  flow_distance_data_map = flow_distance_map;
  drainage_area_data_map = area_map;
  node_sequence = node_order;

  
}
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// This function is for calculating segments from all sources in a DEM
// The sources and their outlets are supplied by the source and outlet nodes
// vectors. These are generated from the LSDJunctionNetwork function
// get_overlapping_channels
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
void LSDChiTools::chi_map_automator(LSDFlowInfo& FlowInfo, 
                                    vector<int> source_nodes,
                                    vector<int> outlet_nodes,
                                    LSDRaster& Elevation, LSDRaster& FlowDistance, 
                                    LSDRaster& DrainageArea, LSDRaster& chi_coordinate, 
                                    int target_nodes, 
                                    int n_iterations, int skip,
                                    int minimum_segment_length, float sigma)
{
  
  // IMPORTANT THESE PARAMETERS ARE NOT USED BECAUSE CHI IS CALUCALTED SEPARATELY
  // However we need to give something to pass to the Monte carlo functions
  // even through they are not used (they are inherited)
  float A_0 = 1;
  float m_over_n = 0.5;

  // These elements access the chi data
  vector< vector<float> > chi_m_means;
  vector< vector<float> > chi_b_means;
  vector< vector<float> > chi_coordinates;
  vector< vector<int> > chi_node_indices;
  
  // these are for the individual channels
  vector<float> these_chi_m_means;
  vector<float> these_chi_b_means;
  vector<float> these_chi_coordinates;
  vector<int> these_chi_node_indices;
  
  // these are maps that will store the data
  map<int,float> m_means_map;
  map<int,float> b_means_map;
  map<int,float> chi_coord_map;
  map<int,float> elev_map;
  map<int,float> area_map;
  map<int,float> flow_distance_map;
  vector<int> node_sequence_vec;

  // these are for working with the FlowInfo object
  int this_node,row,col;

  // get the number of channels
  int n_channels = int(source_nodes.size());
  
  for(int chan = 0; chan<n_channels; chan++)
  {
    cout << "Sampling channel " << chan+1 << " of " << n_channels << endl;
    
    // get this particualr channel (it is a chi network with only one channel)
    LSDChiNetwork ThisChiChannel(FlowInfo, source_nodes[chan], outlet_nodes[chan], 
                                Elevation, FlowDistance, DrainageArea,chi_coordinate);
    
    // split the channel
    //cout << "Splitting channels" << endl;
    ThisChiChannel.split_all_channels(A_0, m_over_n, n_iterations, skip, target_nodes, minimum_segment_length, sigma);
    
    // monte carlo sample all channels
    //cout << "Entering the monte carlo sampling" << endl;
    ThisChiChannel.monte_carlo_sample_river_network_for_best_fit_after_breaks(A_0, m_over_n, n_iterations, skip, minimum_segment_length, sigma);
  
    // okay the ChiNetwork has all the data about the m vales at this stage. 
    // Get these vales and print them to a raster
    chi_m_means = ThisChiChannel.get_m_means();
    chi_b_means = ThisChiChannel.get_b_means();
    chi_coordinates = ThisChiChannel.get_chis();
    chi_node_indices = ThisChiChannel.get_node_indices();
    
    // now get the number of channels. This should be 1!
    int n_channels = int(chi_m_means.size());
    if (n_channels != 1)
    {
      cout << "Whoa there, I am trying to make a chi map but something seems to have gone wrong with the channel extraction."  << endl;
      cout << "I should only have one channel per look but I have " << n_channels << " channels." << endl;
    }
    
    // now get the m_means out
    these_chi_m_means = chi_m_means[0];
    these_chi_b_means = chi_b_means[0];
    these_chi_coordinates = chi_coordinates[0];
    these_chi_node_indices = chi_node_indices[0];
    
    //cout << "I have " << these_chi_m_means.size() << " nodes." << endl;
    
    int n_nodes_in_channel = int(these_chi_m_means.size());
    for (int node = 0; node< n_nodes_in_channel; node++)
    {
      
      this_node =  these_chi_node_indices[node];
      //cout << "This node is " << this_node << endl;
      
      // only take the nodes that have not been found
      if (m_means_map.find(this_node) == m_means_map.end() )
      {
        FlowInfo.retrieve_current_row_and_col(this_node,row,col);
      
        //cout << "This is a new node; " << this_node << endl;
        m_means_map[this_node] = these_chi_m_means[node];
        b_means_map[this_node] = these_chi_b_means[node];
        chi_coord_map[this_node] = these_chi_coordinates[node];
        elev_map[this_node] = Elevation.get_data_element(row,col);
        area_map[this_node] = DrainageArea.get_data_element(row,col);
        flow_distance_map[this_node] = FlowDistance.get_data_element(row,col);
        node_sequence_vec.push_back(this_node);
      }
      else
      {
        //cout << "I already have node: " << this_node << endl;
      }
    }
  }
  
  // set the opject data members
  M_chi_data_map =m_means_map; 
  b_chi_data_map = b_means_map;
  elev_data_map = elev_map;
  chi_data_map = chi_coord_map;
  flow_distance_data_map = flow_distance_map;
  drainage_area_data_map = area_map;
  node_sequence = node_sequence_vec;
  
}
void LSDSoilHydroRaster::create(LSDRaster& DEM, LSDRaster& OtherRaster, int min_max)
{
  NRows = OtherRaster.get_NRows();
  NCols = OtherRaster.get_NCols();
  XMinimum = OtherRaster.get_XMinimum();
  YMinimum = OtherRaster.get_YMinimum();
  DataResolution = OtherRaster.get_DataResolution();
  NoDataValue = OtherRaster.get_NoDataValue();
  GeoReferencingStrings = OtherRaster.get_GeoReferencingStrings();

  // set the raster data to be a certain value
  Array2D<float> data(NRows,NCols,NoDataValue);

  float min_max_val = NoDataValue;

  if (min_max == 0){
    // get the minimum value of OtherRaster
    Array2D<float> tmp = OtherRaster.get_RasterData();
    min_max_val = Get_Minimum(tmp, NoDataValue);
  }
  else if (min_max == 1){
    // get the maximum value of OtherRaster
    Array2D<float> tmp = OtherRaster.get_RasterData();
    min_max_val = Get_Maximum(tmp, NoDataValue);
  }

  // for each cell, if there is no paramter data but there is topo, fill in the data with the minimum/maximum value
  // otherwise, just keep the minimum value.
  for (int i = 0; i < NRows; ++i){
    for (int j = 0; j < NCols; ++j){
      if (DEM.get_data_element(i, j) != NoDataValue && OtherRaster.get_data_element(i,j) == NoDataValue){
        data[i][j] = min_max_val;
      }
      else if (DEM.get_data_element(i, j) != NoDataValue && OtherRaster.get_data_element(i, j) != NoDataValue){
        data[i][j] = OtherRaster.get_data_element(i,j);
      }
    }
  }

  RasterData = data.copy();
}
int main (int nNumberofArgs,char *argv[])
{
    // the driver version
    string driver_version = "Driver_version: 0.01";

    // some paramters
    //Test for correct input arguments
    if (nNumberofArgs!=5)
    {
        cout << endl;
        cout << "=====================================================================" << endl;
        cout << "|| Welcome to the Topographic Shielding tool!                      ||" << endl;
        cout << "|| This program is used to calculate topographic shielding_driver  ||" << endl;
        cout << "|| rasters following the method of Codilean (2006).                ||" << endl;
        cout << "=====================================================================" << endl;
        cout << "This program requires four inputs: " << endl;
        cout << "* First the path to the DEM files." << endl;
        cout << "   The path must have a slash at the end." << endl;
        cout << "  (Either \\ or / depending on your operating system.)" << endl;
        cout << "* Second the prefix of the DEM (that is, without the .bil)." << endl;
        cout << "   For example if you DEM is Ladakh.bil, you should enter Ladakh" << endl;
        cout << "   (Note that the DEM should be in *.bil format)" << endl;
        cout << "* Third the increment in azimuth (in degrees) over which you" << endl;
        cout << "   want shielding calculated. Recommended values is 5" << endl;
        cout << "* Fourth the increment in inclination (in degrees) over which you" << endl;
        cout << "   want shielding calculated. Recommended values is 5" << endl;
        cout << "=====================================================================" << endl;
        cout << "For more documentation, see readme and online documentation" << endl;
        cout << "=====================================================================" << endl;
        cout << endl;
        exit(EXIT_SUCCESS);
    }

    cout << endl;
    cout << "===============================================================" << endl;
    cout << "Welcome to the Topographic Shielding tool" << endl;
    cout << "This software was developed at the University of Edinburgh," << endl;
    cout << "by the Land Surface Dynamics group. For questions email" << endl;
    cout << "simon.m.mudd _at_ ed.ac.uk" << endl;
    cout << "This software is released under a GNU public license." << endl;
    cout << "You are using " << driver_version << endl;
    cout << "================================================================" << endl;
    cout << "++IMPORTANT++ The DEM must be an ENVI bil format file" << endl;
    cout << "ENVI bil files are required because, unlike asc or flt files, " << endl;
    cout << "they use georeferencing information." << endl;
    cout << "For more information about changing DEM formatting, see: " << endl;
    cout << "http://lsdtopotools.github.io/LSDTT_book/#_gdal_2" << endl;
    cout << "================================================================" << endl;


    //Assign values from input arguments
    string path_name = argv[1];
    string file_name = argv[2];
    string azimuth_str = argv[3];
    string inclination_str = argv[4];

    //Set the DEM filename
    file_name = path_name+file_name;

    //Convert the angle increments to integers
    int azimuth_step =  atoi(azimuth_str.c_str());
    int inclination_step =  atoi(inclination_str.c_str());

    // check the parameter values
    check_azimuth_and_inclination(azimuth_step,inclination_step);

    //load dem
    LSDRaster DEM(file_name, "bil");

    //launch toposhielding
    LSDRaster TopoShielding = DEM.TopographicShielding(azimuth_step,inclination_step);
    TopoShielding.write_raster(file_name+"_TopoShield","bil");

    cout << "Done!" << endl << endl;
}