<commit_before>// soil.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "soil.h"
#include "alist.h"
#include "syntax.h"
#include "mathlib.h"
#include "submodel.h"
#include "log.h"
#include "check.h"
#include "plf.h"
#include "tmpstream.h"
#include <iomanip>
#include <iostream>

struct Soil::Implementation
{
  // Layers.
  struct Layer
  {
    // Content.
    const double end;
    Horizon& horizon;

    // Simulation.
    void output (Log& log) const
    { output_derived (horizon, "horizon", log); }

    // Create and Destroy.
    static void load_syntax (Syntax& syntax, AttributeList& alist)
    {
      alist.add ("description", "\
A location and content of a soil layer.");
      syntax.add ("end", "cm", Check::negative (), Syntax::Const,
		  "End point of this layer (a negative number).");
      syntax.add ("horizon", Librarian<Horizon>::library (),
		  "Soil properties of this layer.");
      syntax.order ("end", "horizon");
    }
    Layer (const AttributeList& al)
      : end (al.number ("end")),
	horizon (Librarian<Horizon>::create (al.alist ("horizon")))
    { }
    ~Layer ()
    { delete &horizon; }
  };
  const vector<Layer*> layers;

  // Parameters
  const double MaxRootingDepth;
  const double dispersivity;

  bool has_attribute (const string& name) const
  {
    bool missing = false;
    for (unsigned int i = 0; i < layers.size (); i++)
      if (!layers[i]->horizon.has_attribute (name))
	missing = true;
    return !missing;
  }

  // Create and Destroy.
  Implementation (const AttributeList& al)
    : layers (map_construct<Layer> (al.alist_sequence ("horizons"))),
      MaxRootingDepth (al.number ("MaxRootingDepth")),
      dispersivity (al.number ("dispersivity"))
  { }
  ~Implementation ()
  { sequence_delete (layers.begin (), layers.end ()); }
};

double
Soil::K (int i, double h, double h_ice, double T) const
{
  static struct ViscosityFactor : public PLF
  {
    ViscosityFactor ()
    {
      add ( 0.0, 1002.0 / 1786.0);
      add ( 5.0, 1002.0 / 1519.0);
      add (10.0, 1002.0 / 1307.0);
      add (15.0, 1002.0 / 1139.0);
      add (20.0, 1002.0 / 1002.0);
      add (25.0, 1002.0 /  890.0);
      add (30.0, 1002.0 /  798.0);
      add (35.0, 1002.0 /  719.0);
      add (40.0, 1002.0 /  658.0);
    }
  } viscosity_factor;

  const double T_factor = viscosity_factor (T);
  if (h < h_ice)
    return horizon_[i]->hydraulic.K (h) * T_factor;
  else
    return horizon_[i]->hydraulic.K (h_ice) * T_factor;
}

double Soil::Theta (int i, double h, double h_ice) const
{
  if (h < h_ice)
    return horizon_[i]->hydraulic.Theta (h);
  else
    return horizon_[i]->hydraulic.Theta (h_ice);
}

double
Soil::Cw2 (int i, double h) const
{
  const double answer = horizon_[i]->hydraulic.Cw2 (h);
  if (answer > 0.0)
    return answer;
  // We divide with this.
  return 1.0e-8;
}

double
Soil::dispersivity (int) const
{ return impl.dispersivity; }

bool
Soil::has_attribute (const string& name) const
{ return impl.has_attribute (name); }

void
Soil::output (Log& log) const
{ output_vector (impl.layers, "horizons", log); }

double
Soil::MaxRootingDepth () const
{
  return max (-impl.MaxRootingDepth, z (size () - 1));
}

double
Soil::end_of_first_horizon () const
{
  daisy_assert (impl.layers.size () > 0);
  return impl.layers[0]->end;
}

bool
Soil::check (int som_size, Treelog& err) const
{
  bool ok = Geometry::check (err);

  if (som_size >= 0)
    {
      Treelog::Open nest (err, "horizons");
      for (unsigned int i = 0; i < impl.layers.size (); i++)
	{
	  const Horizon& horizon = impl.layers[i]->horizon;
	  Treelog::Open nest (err, horizon.name);
	  const int f_size = horizon.SOM_fractions ().size ();
	  if (f_size > 0 && f_size != som_size)
	    {
	      Treelog::Open nest (err, "SOM_fractions");
	      TmpStream tmp;
	      tmp () << "Need " << som_size << " fractions, got " << f_size;
	      err.error (tmp.str ());
	      ok = false;
	    }
	  const int n_size = horizon.SOM_C_per_N ().size ();
	  if (n_size != som_size)
	    {
	      Treelog::Open nest (err, "SOM_C_per_N");
	      TmpStream tmp;
	      tmp () << "Need " << som_size << " C/N numbers, got " << n_size;
	      err.error (tmp.str ());
	      ok = false;
	    }
	}
    }
  return ok;
}

static bool
check_alist (const AttributeList& al, Treelog& err)
{
  bool ok = true;

  const vector<AttributeList*>& layers = al.alist_sequence ("horizons");

  if (layers.size () < 1U)
    {
      err.entry ("You need at least one horizon");
      ok = false;
    }
  double last = 0.0;

  for (unsigned int i = 0; i < layers.size (); i++)
    {
      double end = layers[i]->number ("end");
      if (end >= last)
	{
	  err.entry ("Horizon endpoints must be monotonically decreasing");
	  ok = false;
	  break;
	}
      last = end;
    }

  if (ok && al.check ("zplus"))
    {
      // This check is only meaningful if zplus and layers are ok.
      const vector<double> zplus = al.number_sequence ("zplus");

      if (last != zplus[zplus.size() - 1])
	{
	  err.entry ("The last horizon must end the same place as the "
		     "last interval");
	  ok = false;
	}
    }
  return ok;
}

void
Soil::make_table (int i)
{
  cout << "pF   Theta   Cw2           K           (depth " << z (i) << ").\n";
  for (double pF = 0.00; pF <= 5.0; pF += 0.01)
    {
      const double h = pF2h (pF);
      cout << setw (4) << setprecision (3) << pF << " "
	   << setw (6) << setprecision (5) << Theta (i, h, 0.0) << " "
	   << setw (12) << setprecision (11) << Cw2 (i, h) * 100.0 << " "
	   << setw (12) << setprecision (11) << K (i, h, 0.0, 20.0) / 3.6e5
	   << "\n";
    }
}

void
Soil::load_syntax (Syntax& syntax, AttributeList& alist)
{
  Geometry::load_syntax (syntax, alist);
  syntax.add_check (check_alist);
  alist.add ("submodel", "Soil");
  alist.add ("description", "\
The soil component provides the numeric and physical properties of the soil.");
  syntax.add_submodule_sequence ("horizons", Syntax::State, "\
Layered description of the soil properties.",
				 Implementation::Layer::load_syntax);
  syntax.add ("MaxRootingDepth", "cm", Check::positive (), Syntax::Const,
	      "Depth at the end of the root zone (a positive number).");
  syntax.add ("dispersivity", "cm", Check::positive (),
	      Syntax::Const, "Dispersion length.");
  alist.add ("dispersivity", 5.0);
}

Soil::Soil (const AttributeList& al)
  : Geometry (al),
    impl (*new Implementation (al))
{ }

void
Soil::initialize (const Groundwater& groundwater, Treelog& msg)
{
  Treelog::Open nest (msg, "Soil");

  const vector<Implementation::Layer*>::const_iterator begin
    = impl.layers.begin ();
  const vector<Implementation::Layer*>::const_iterator end
    = impl.layers.end ();
  daisy_assert (begin != end);
  vector<Implementation::Layer*>::const_iterator layer;

  // Initialize geometry.
  vector<double> fixed;
  {
    Treelog::Open nest (msg, "Horizons");
    double last = 0.0;
    for (layer = begin; layer != end; layer++)
      {
	double current = (*layer)->end;
	daisy_assert (current < last);

	const bool top_soil = (layer == begin);
	(*layer)->horizon.initialize (top_soil, msg);

	// We always have a layer limit at 1 m.
	if (last > -100.0 && current < -100.0)
	  fixed.push_back (-100.0);

	last = current;
	fixed.push_back (last);
      }
  }
  initialize_zplus (groundwater, fixed, -impl.MaxRootingDepth, msg);

  // Initialize horizons.
  layer = begin;
  for (unsigned int i = 0; i < size (); i++)
    {
      if (zplus (i) < (*layer)->end)
	{
	  layer++;
	  daisy_assert (layer != end);
	}
      horizon_.push_back (&((*layer)->horizon));
    }
}

Soil::~Soil ()
{ delete &impl; }

static Submodel::Register
soil_submodel ("Soil", Soil::load_syntax);
<commit_msg>sync<commit_after>// soil.C
//
// Copyright 1996-2001 Per Abrahamsen and Sren Hansen
// Copyright 2000-2001 KVL.
//
// This file is part of Daisy.
//
// Daisy is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// Daisy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser Public License for more details.
//
// You should have received a copy of the GNU Lesser Public License
// along with Daisy; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "soil.h"
#include "alist.h"
#include "syntax.h"
#include "mathlib.h"
#include "submodel.h"
#include "log.h"
#include "check.h"
#include "plf.h"
#include "tmpstream.h"
#if !(defined (__BORLANDC__) && __BORLANDC__ < 0x0550)
#include <iomanip>
#endif
#include <iostream>

struct Soil::Implementation
{
  // Layers.
  struct Layer
  {
    // Content.
    const double end;
    Horizon& horizon;

    // Simulation.
    void output (Log& log) const
    { output_derived (horizon, "horizon", log); }

    // Create and Destroy.
    static void load_syntax (Syntax& syntax, AttributeList& alist)
    {
      alist.add ("description", "\
A location and content of a soil layer.");
      syntax.add ("end", "cm", Check::negative (), Syntax::Const,
		  "End point of this layer (a negative number).");
      syntax.add ("horizon", Librarian<Horizon>::library (),
		  "Soil properties of this layer.");
      syntax.order ("end", "horizon");
    }
    Layer (const AttributeList& al)
      : end (al.number ("end")),
	horizon (Librarian<Horizon>::create (al.alist ("horizon")))
    { }
    ~Layer ()
    { delete &horizon; }
  };
  const vector<Layer*> layers;

  // Parameters
  const double MaxRootingDepth;
  const double dispersivity;

  bool has_attribute (const string& name) const
  {
    bool missing = false;
    for (unsigned int i = 0; i < layers.size (); i++)
      if (!layers[i]->horizon.has_attribute (name))
	missing = true;
    return !missing;
  }

  // Create and Destroy.
  Implementation (const AttributeList& al)
    : layers (map_construct<Layer> (al.alist_sequence ("horizons"))),
      MaxRootingDepth (al.number ("MaxRootingDepth")),
      dispersivity (al.number ("dispersivity"))
  { }
  ~Implementation ()
  { sequence_delete (layers.begin (), layers.end ()); }
};

double
Soil::K (int i, double h, double h_ice, double T) const
{
  static struct ViscosityFactor : public PLF
  {
    ViscosityFactor ()
    {
      add ( 0.0, 1002.0 / 1786.0);
      add ( 5.0, 1002.0 / 1519.0);
      add (10.0, 1002.0 / 1307.0);
      add (15.0, 1002.0 / 1139.0);
      add (20.0, 1002.0 / 1002.0);
      add (25.0, 1002.0 /  890.0);
      add (30.0, 1002.0 /  798.0);
      add (35.0, 1002.0 /  719.0);
      add (40.0, 1002.0 /  658.0);
    }
  } viscosity_factor;

  const double T_factor = viscosity_factor (T);
  if (h < h_ice)
    return horizon_[i]->hydraulic.K (h) * T_factor;
  else
    return horizon_[i]->hydraulic.K (h_ice) * T_factor;
}

double Soil::Theta (int i, double h, double h_ice) const
{
  if (h < h_ice)
    return horizon_[i]->hydraulic.Theta (h);
  else
    return horizon_[i]->hydraulic.Theta (h_ice);
}

double
Soil::Cw2 (int i, double h) const
{
  const double answer = horizon_[i]->hydraulic.Cw2 (h);
  if (answer > 0.0)
    return answer;
  // We divide with this.
  return 1.0e-8;
}

double
Soil::dispersivity (int) const
{ return impl.dispersivity; }

bool
Soil::has_attribute (const string& name) const
{ return impl.has_attribute (name); }

void
Soil::output (Log& log) const
{ output_vector (impl.layers, "horizons", log); }

double
Soil::MaxRootingDepth () const
{
  return max (-impl.MaxRootingDepth, z (size () - 1));
}

double
Soil::end_of_first_horizon () const
{
  daisy_assert (impl.layers.size () > 0);
  return impl.layers[0]->end;
}

bool
Soil::check (int som_size, Treelog& err) const
{
  bool ok = Geometry::check (err);

  if (som_size >= 0)
    {
      Treelog::Open nest (err, "horizons");
      for (unsigned int i = 0; i < impl.layers.size (); i++)
	{
	  const Horizon& horizon = impl.layers[i]->horizon;
	  Treelog::Open nest (err, horizon.name);
	  const int f_size = horizon.SOM_fractions ().size ();
	  if (f_size > 0 && f_size != som_size)
	    {
	      Treelog::Open nest (err, "SOM_fractions");
	      TmpStream tmp;
	      tmp () << "Need " << som_size << " fractions, got " << f_size;
	      err.error (tmp.str ());
	      ok = false;
	    }
	  const int n_size = horizon.SOM_C_per_N ().size ();
	  if (n_size != som_size)
	    {
	      Treelog::Open nest (err, "SOM_C_per_N");
	      TmpStream tmp;
	      tmp () << "Need " << som_size << " C/N numbers, got " << n_size;
	      err.error (tmp.str ());
	      ok = false;
	    }
	}
    }
  return ok;
}

static bool
check_alist (const AttributeList& al, Treelog& err)
{
  bool ok = true;

  const vector<AttributeList*>& layers = al.alist_sequence ("horizons");

  if (layers.size () < 1U)
    {
      err.entry ("You need at least one horizon");
      ok = false;
    }
  double last = 0.0;

  for (unsigned int i = 0; i < layers.size (); i++)
    {
      double end = layers[i]->number ("end");
      if (end >= last)
	{
	  err.entry ("Horizon endpoints must be monotonically decreasing");
	  ok = false;
	  break;
	}
      last = end;
    }

  if (ok && al.check ("zplus"))
    {
      // This check is only meaningful if zplus and layers are ok.
      const vector<double> zplus = al.number_sequence ("zplus");

      if (last != zplus[zplus.size() - 1])
	{
	  err.entry ("The last horizon must end the same place as the "
		     "last interval");
	  ok = false;
	}
    }
  return ok;
}

void
Soil::make_table (int i)
{
  cout << "pF   Theta   Cw2           K           (depth " << z (i) << ").\n";
#if !(defined (__BORLANDC__) && __BORLANDC__ < 0x0550)
  for (double pF = 0.00; pF <= 5.0; pF += 0.01)
    {
      const double h = pF2h (pF);
      cout << setw (4) << setprecision (3) << pF << " "
	   << setw (6) << setprecision (5) << Theta (i, h, 0.0) << " "
	   << setw (12) << setprecision (11) << Cw2 (i, h) * 100.0 << " "
	   << setw (12) << setprecision (11) << K (i, h, 0.0, 20.0) / 3.6e5
	   << "\n";
    }
#endif
}

void
Soil::load_syntax (Syntax& syntax, AttributeList& alist)
{
  Geometry::load_syntax (syntax, alist);
  syntax.add_check (check_alist);
  alist.add ("submodel", "Soil");
  alist.add ("description", "\
The soil component provides the numeric and physical properties of the soil.");
  syntax.add_submodule_sequence ("horizons", Syntax::State, "\
Layered description of the soil properties.",
				 Implementation::Layer::load_syntax);
  syntax.add ("MaxRootingDepth", "cm", Check::positive (), Syntax::Const,
	      "Depth at the end of the root zone (a positive number).");
  syntax.add ("dispersivity", "cm", Check::positive (),
	      Syntax::Const, "Dispersion length.");
  alist.add ("dispersivity", 5.0);
}

Soil::Soil (const AttributeList& al)
  : Geometry (al),
    impl (*new Implementation (al))
{ }

void
Soil::initialize (const Groundwater& groundwater, Treelog& msg)
{
  Treelog::Open nest (msg, "Soil");

  const vector<Implementation::Layer*>::const_iterator begin
    = impl.layers.begin ();
  const vector<Implementation::Layer*>::const_iterator end
    = impl.layers.end ();
  daisy_assert (begin != end);
  vector<Implementation::Layer*>::const_iterator layer;

  // Initialize geometry.
  vector<double> fixed;
  {
    Treelog::Open nest (msg, "Horizons");
    double last = 0.0;
    for (layer = begin; layer != end; layer++)
      {
	double current = (*layer)->end;
	daisy_assert (current < last);

	const bool top_soil = (layer == begin);
	(*layer)->horizon.initialize (top_soil, msg);

	// We always have a layer limit at 1 m.
	if (last > -100.0 && current < -100.0)
	  fixed.push_back (-100.0);

	last = current;
	fixed.push_back (last);
      }
  }
  initialize_zplus (groundwater, fixed, -impl.MaxRootingDepth, msg);

  // Initialize horizons.
  layer = begin;
  for (unsigned int i = 0; i < size (); i++)
    {
      if (zplus (i) < (*layer)->end)
	{
	  layer++;
	  daisy_assert (layer != end);
	}
      horizon_.push_back (&((*layer)->horizon));
    }
}

Soil::~Soil ()
{ delete &impl; }

static Submodel::Register
soil_submodel ("Soil", Soil::load_syntax);
<|endoftext|>


<commit_before>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file		g_fileinputstream.cpp
* @version
* @brief
* @author   ylh
* @date     2014-07-11
* @note
*
*  1. 2014-07-11 ylh Created this file
*
*/

#include <g_fileinputstream.h>
#include <g_private_define.h>

using namespace std;
using namespace GCommon;

FileInputStream::FileInputStream(shared_ptr<GFile> file)
	: m_file(file)
{
	if (m_file == NULL)
	{
		throw invalid_argument(EXCEPTION_DESCRIPTION("invalid_argument"));
	}
}

FileInputStream::FileInputStream(const string filepath)
	: m_file((shared_ptr<GFile>(new GFile(filepath.c_str()))))
{
	if (m_file->open(G_OPEN_READ) == G_NO)
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
}

FileInputStream::~FileInputStream()
{
}

GInt32 FileInputStream::available() throw(std::ios_base::failure)
{
	// TODO: GFile
	return 0;
}

void FileInputStream::close() throw(std::ios_base::failure)
{
	// m_file->close();
	// do nothing
}

GInt32 FileInputStream::read() throw(std::ios_base::failure, std::logic_error)
{
	GInt8 pBuffer[1] = {0};
	return  this->read(pBuffer, 1);
}

GInt32 FileInputStream::read(GInt8 * pBuffer, GInt32 iBufferLen, GInt32 iOffset, GInt32 iLen) throw(std::ios_base::failure, std::logic_error)
{
	if (!pBuffer)
	{
		throw invalid_argument(EXCEPTION_DESCRIPTION("invalid_argument"));
	}
	else if (iOffset < 0 || iLen < 0 ||iBufferLen < iOffset + iLen)
	{
		throw out_of_range(EXCEPTION_DESCRIPTION("out_of_range"));
	}
	else if (iLen == 0)
	{
		return 0;
	}

	GInt32 ret = m_file->read(pBuffer + iOffset, iLen);
	if (ret < 0)
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
	if (ret == 0)
	{
		ret = -1;
	}

	return ret;
}

GInt64 FileInputStream::skip(GInt64 lNum) throw(std::ios_base::failure)
{
	if (lNum == 0)
	{
		return 0;
	}
	if (lNum  < 0)
	{
		throw out_of_range("");
	}

	// TODO: GFile
	if (m_file->seek(lNum, G_SEEK_CUR))
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
	return 0;
}

shared_ptr<GFile> FileInputStream::GetFile()
{
	return m_file;
}
<commit_msg>Update g_fileinputstream.cpp<commit_after>/************************************************************************************
**
* @copyright (c) 2013-2100, ChengDu Duyer Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file		g_fileinputstream.cpp
* @version
* @brief
* @author   ylh
* @date     2014-07-11
* @note
*
*  1. 2014-07-11 ylh Created this file
*
*/

#include <g_fileinputstream.h>
#include <g_private_define.h>

using namespace std;
using namespace GCommon;

FileInputStream::FileInputStream(shared_ptr<GFile> file)
	: m_file(file)
{
	if (m_file == NULL)
	{
		throw invalid_argument(EXCEPTION_DESCRIPTION("invalid_argument"));
	}
}

FileInputStream::FileInputStream(const string filepath)
	: m_file((shared_ptr<GFile>(new GFile(filepath.c_str()))))
{
	if (m_file->open(G_OPEN_READ) == G_NO)
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
}

FileInputStream::~FileInputStream()
{
}

GInt32 FileInputStream::available() throw(std::ios_base::failure)
{
	// TODO: GFile
	return 0;
}

void FileInputStream::close() throw(std::ios_base::failure)
{
	// m_file->close();
	// do nothing
}

GInt32 FileInputStream::read() throw(std::ios_base::failure, std::logic_error)
{
	GInt8 pBuffer[1] = {0};
	return  this->read(pBuffer, 1);
}

GInt32 FileInputStream::read(GInt8 * pBuffer, GInt32 iBufferLen, GInt32 iOffset, GInt32 iLen) throw(std::ios_base::failure, std::logic_error)
{
	if (!pBuffer)
	{
		throw invalid_argument(EXCEPTION_DESCRIPTION("invalid_argument"));
	}
	else if (iOffset < 0 || iLen < 0 ||iBufferLen < iOffset + iLen)
	{
		throw out_of_range(EXCEPTION_DESCRIPTION("out_of_range"));
	}
	else if (iLen == 0)
	{
		return 0;
	}

	GInt32 ret = m_file->read(pBuffer + iOffset, iLen);
	if (ret < 0)
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
	if (ret == 0)
	{
		ret = -1;
	}

	return ret;
}

GInt64 FileInputStream::skip(GInt64 lNum) throw(std::ios_base::failure)
{
	if (lNum == 0)
	{
		return 0;
	}
	if (lNum  < 0)
	{
		throw out_of_range("");
	}

	// TODO: not complete
	if (m_file->seek(lNum, G_SEEK_CUR))
	{
		throw ios_base::failure(EXCEPTION_DESCRIPTION("ios_base::failure"));
	}
	return 0;
}

shared_ptr<GFile> FileInputStream::GetFile()
{
	return m_file;
}
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_dataframe
/// This tutorial illustrates how to express the H1 analysis with a RDataFrame.
///
/// \macro_code
/// \macro_image
///
/// \date December 2016
/// \author Axel Naumann, Danilo Piparo (CERN)

auto Select = [](ROOT::RDataFrame &dataFrame) {
   using Farray_t = ROOT::VecOps::RVec<float>;
   using Iarray_t = ROOT::VecOps::RVec<int>;

   auto ret = dataFrame.Filter("TMath::Abs(md0_d - 1.8646) < 0.04")
                 .Filter("ptds_d > 2.5")
                 .Filter("TMath::Abs(etads_d) < 1.5")
                 .Filter([](int ik, int ipi, Iarray_t& nhitrp) { return nhitrp[ik - 1] * nhitrp[ipi - 1] > 1; },
                         {"ik", "ipi", "nhitrp"})
                 .Filter([](int ik, Farray_t& rstart, Farray_t& rend) { return rend[ik - 1] - rstart[ik - 1] > 22; },
                         {"ik", "rstart", "rend"})
                 .Filter([](int ipi, Farray_t& rstart, Farray_t& rend) { return rend[ipi - 1] - rstart[ipi - 1] > 22; },
                         {"ipi", "rstart", "rend"})
                 .Filter([](int ik, Farray_t& nlhk) { return nlhk[ik - 1] > 0.1; }, {"ik", "nlhk"})
                 .Filter([](int ipi, Farray_t& nlhpi) { return nlhpi[ipi - 1] > 0.1; }, {"ipi", "nlhpi"})
                 .Filter([](int ipis, Farray_t& nlhpi) { return nlhpi[ipis - 1] > 0.1; }, {"ipis", "nlhpi"})
                 .Filter("njets >= 1");

   return ret;
};

const Double_t dxbin = (0.17 - 0.13) / 40; // Bin-width

Double_t fdm5(Double_t *xx, Double_t *par)
{
   Double_t x = xx[0];
   if (x <= 0.13957)
      return 0;
   Double_t xp3 = (x - par[3]) * (x - par[3]);
   Double_t res =
      dxbin * (par[0] * pow(x - 0.13957, par[1]) + par[2] / 2.5066 / par[4] * exp(-xp3 / 2 / par[4] / par[4]));
   return res;
}

Double_t fdm2(Double_t *xx, Double_t *par)
{
   static const Double_t sigma = 0.0012;
   Double_t x = xx[0];
   if (x <= 0.13957)
      return 0;
   Double_t xp3 = (x - 0.1454) * (x - 0.1454);
   Double_t res = dxbin * (par[0] * pow(x - 0.13957, 0.25) + par[1] / 2.5066 / sigma * exp(-xp3 / 2 / sigma / sigma));
   return res;
}

void FitAndPlotHdmd(TH1 &hdmd)
{
   // create the canvas for the h1analysis fit
   gStyle->SetOptFit();
   auto c1 = new TCanvas("c1", "h1analysis analysis", 10, 10, 800, 600);
   hdmd.GetXaxis()->SetTitle("m_{K#pi#pi} - m_{K#pi}[GeV/c^{2}]");
   hdmd.GetXaxis()->SetTitleOffset(1.4);

   // fit histogram hdmd with function f5 using the loglikelihood option
   auto f5 = new TF1("f5", fdm5, 0.139, 0.17, 5);
   f5->SetParameters(1000000, .25, 2000, .1454, .001);
   hdmd.Fit("f5", "lr");

   hdmd.DrawClone();
}

void FitAndPlotH2(TH2 &h2)
{
   // create the canvas for tau d0
   auto c2 = new TCanvas("c2", "tauD0", 100, 100, 800, 600);

   c2->SetGrid();
   c2->SetBottomMargin(0.15);

   // Project slices of 2-d histogram h2 along X , then fit each slice
   // with function f2 and make a histogram for each fit parameter
   // Note that the generated histograms are added to the list of objects
   // in the current directory.
   auto f2 = new TF1("f2", fdm2, 0.139, 0.17, 2);
   f2->SetParameters(10000, 10);
   h2.FitSlicesX(f2, 0, -1, 1, "qln");

   // See TH2::FitSlicesX documentation
   auto h2_1 = (TH1D *)gDirectory->Get("h2_1");
   h2_1->GetXaxis()->SetTitle("#tau [ps]");
   h2_1->SetMarkerStyle(21);
   h2_1->DrawClone();
   c2->Update();

   auto line = new TLine(0, 0, 0, c2->GetUymax());
   line->Draw();
}

void df101_h1Analysis()
{
   TChain chain("h42");
   chain.Add("http://root.cern.ch/files/h1/dstarmb.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp1a.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp1b.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp2.root");

   ROOT::EnableImplicitMT(4);

   ROOT::RDataFrame dataFrame(chain);
   auto selected = Select(dataFrame);
   auto hdmdARP = selected.Histo1D({"hdmd", "Dm_d", 40, 0.13, 0.17}, "dm_d");
   auto selectedAddedBranch = selected.Define("h2_y", "rpd0_t / 0.029979f * 1.8646f / ptd0_d");
   auto h2ARP = selectedAddedBranch.Histo2D({"h2", "ptD0 vs Dm_d", 30, 0.135, 0.165, 30, -3, 6}, "dm_d", "h2_y");

   FitAndPlotHdmd(*hdmdARP);
   FitAndPlotH2(*h2ARP);
}
<commit_msg>put back the \notebook directive as it is not the blocking factor<commit_after>/// \file
/// \ingroup tutorial_dataframe
/// \notebook
/// This tutorial illustrates how to express the H1 analysis with a RDataFrame.
///
/// \macro_code
/// \macro_image
///
/// \date December 2016
/// \author Axel Naumann, Danilo Piparo (CERN)

auto Select = [](ROOT::RDataFrame &dataFrame) {
   using Farray_t = ROOT::VecOps::RVec<float>;
   using Iarray_t = ROOT::VecOps::RVec<int>;

   auto ret = dataFrame.Filter("TMath::Abs(md0_d - 1.8646) < 0.04")
                 .Filter("ptds_d > 2.5")
                 .Filter("TMath::Abs(etads_d) < 1.5")
                 .Filter([](int ik, int ipi, Iarray_t& nhitrp) { return nhitrp[ik - 1] * nhitrp[ipi - 1] > 1; },
                         {"ik", "ipi", "nhitrp"})
                 .Filter([](int ik, Farray_t& rstart, Farray_t& rend) { return rend[ik - 1] - rstart[ik - 1] > 22; },
                         {"ik", "rstart", "rend"})
                 .Filter([](int ipi, Farray_t& rstart, Farray_t& rend) { return rend[ipi - 1] - rstart[ipi - 1] > 22; },
                         {"ipi", "rstart", "rend"})
                 .Filter([](int ik, Farray_t& nlhk) { return nlhk[ik - 1] > 0.1; }, {"ik", "nlhk"})
                 .Filter([](int ipi, Farray_t& nlhpi) { return nlhpi[ipi - 1] > 0.1; }, {"ipi", "nlhpi"})
                 .Filter([](int ipis, Farray_t& nlhpi) { return nlhpi[ipis - 1] > 0.1; }, {"ipis", "nlhpi"})
                 .Filter("njets >= 1");

   return ret;
};

const Double_t dxbin = (0.17 - 0.13) / 40; // Bin-width

Double_t fdm5(Double_t *xx, Double_t *par)
{
   Double_t x = xx[0];
   if (x <= 0.13957)
      return 0;
   Double_t xp3 = (x - par[3]) * (x - par[3]);
   Double_t res =
      dxbin * (par[0] * pow(x - 0.13957, par[1]) + par[2] / 2.5066 / par[4] * exp(-xp3 / 2 / par[4] / par[4]));
   return res;
}

Double_t fdm2(Double_t *xx, Double_t *par)
{
   static const Double_t sigma = 0.0012;
   Double_t x = xx[0];
   if (x <= 0.13957)
      return 0;
   Double_t xp3 = (x - 0.1454) * (x - 0.1454);
   Double_t res = dxbin * (par[0] * pow(x - 0.13957, 0.25) + par[1] / 2.5066 / sigma * exp(-xp3 / 2 / sigma / sigma));
   return res;
}

void FitAndPlotHdmd(TH1 &hdmd)
{
   // create the canvas for the h1analysis fit
   gStyle->SetOptFit();
   auto c1 = new TCanvas("c1", "h1analysis analysis", 10, 10, 800, 600);
   hdmd.GetXaxis()->SetTitle("m_{K#pi#pi} - m_{K#pi}[GeV/c^{2}]");
   hdmd.GetXaxis()->SetTitleOffset(1.4);

   // fit histogram hdmd with function f5 using the loglikelihood option
   auto f5 = new TF1("f5", fdm5, 0.139, 0.17, 5);
   f5->SetParameters(1000000, .25, 2000, .1454, .001);
   hdmd.Fit("f5", "lr");

   hdmd.DrawClone();
}

void FitAndPlotH2(TH2 &h2)
{
   // create the canvas for tau d0
   auto c2 = new TCanvas("c2", "tauD0", 100, 100, 800, 600);

   c2->SetGrid();
   c2->SetBottomMargin(0.15);

   // Project slices of 2-d histogram h2 along X , then fit each slice
   // with function f2 and make a histogram for each fit parameter
   // Note that the generated histograms are added to the list of objects
   // in the current directory.
   auto f2 = new TF1("f2", fdm2, 0.139, 0.17, 2);
   f2->SetParameters(10000, 10);
   h2.FitSlicesX(f2, 0, -1, 1, "qln");

   // See TH2::FitSlicesX documentation
   auto h2_1 = (TH1D *)gDirectory->Get("h2_1");
   h2_1->GetXaxis()->SetTitle("#tau [ps]");
   h2_1->SetMarkerStyle(21);
   h2_1->DrawClone();
   c2->Update();

   auto line = new TLine(0, 0, 0, c2->GetUymax());
   line->Draw();
}

void df101_h1Analysis()
{
   TChain chain("h42");
   chain.Add("http://root.cern.ch/files/h1/dstarmb.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp1a.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp1b.root");
   chain.Add("http://root.cern.ch/files/h1/dstarp2.root");

   ROOT::EnableImplicitMT(4);

   ROOT::RDataFrame dataFrame(chain);
   auto selected = Select(dataFrame);
   auto hdmdARP = selected.Histo1D({"hdmd", "Dm_d", 40, 0.13, 0.17}, "dm_d");
   auto selectedAddedBranch = selected.Define("h2_y", "rpd0_t / 0.029979f * 1.8646f / ptd0_d");
   auto h2ARP = selectedAddedBranch.Histo2D({"h2", "ptD0 vs Dm_d", 30, 0.135, 0.165, 30, -3, 6}, "dm_d", "h2_y");

   FitAndPlotHdmd(*hdmdARP);
   FitAndPlotH2(*h2ARP);
}
<|endoftext|>


<commit_before>#include "cqts_engine.h"
#include <QFile>
#include <QDir>

#include <QStringList>
#include <QTextStream>

#include <QDebug>

CQTs_engine::CQTs_engine()
{
}

/*****class handler*****/
/*ClassFile structure:
 *Class Name
 *lv max
 *datanumber 16*fort+8*ref+4*will+bab
 *bab= 1(01) poor, 2(10) good ,3(11) average
 *endofile
 */

CQTs_Class::CQTs_Class(QString classLink){
    classLink.remove(".ClC");
    QFile file(classLink+".ClC");//temporary
    int data;//data-sink for bab and ST
    int F=16, R=8, W=4, bab=3;//mask for ST&BAB
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        Name="error";
        data=0;
        lmax=-1;
    //add an alert!
       }
       else{
        QTextStream in(&file);
        Name= in.readLine();
        in >> lmax;
        in >> data;
    }
    fort = (data & F)/F;//good? 0/1
    ref = (data & R)/R;//good? 0/1
    will = (data & W)/W;//good ?0/1
    BAB = (data & bab);// good 10, poor 01, average 11, i know it's not intuitive
    /*qDebug()<<Name;
    qDebug()<<lmax;
    qDebug()<<data;
    qDebug()<<BAB;
    qDebug()<<fort;
    qDebug()<<ref;
    qDebug()<<will;
*/
}

QString CQTs_Class::className(){return Name;}

int CQTs_Class::classBAB(){return BAB;}

bool CQTs_Class::STFort(){return fort;}

bool CQTs_Class::STRef(){return ref;}

bool CQTs_Class::STWill(){return will;}

/*****utilities*****/

QStringList extensionFind(QString ext,QString dir){
    QDir workDir(dir);

    QStringList filelist;
    filelist = workDir.entryList(QStringList(ext),QDir::Files | QDir::NoSymLinks);
    return filelist;
}

QStringList extensionFind(QString ext){
    return extensionFind(ext,"./");
}
<commit_msg>designed charater file<commit_after>#include "cqts_engine.h"
#include <QFile>
#include <QDir>

#include <QStringList>
#include <QTextStream>

#include <QDebug>

CQTs_engine::CQTs_engine()
{
}
/*****character handler*****/
/*CharacterFile structure:
 *Name
 *Surname
 *age
 *lv
 *bab
 *hp
 *fort \t ref \t will
 *endoffile
 */
CQTs_Character::CQTs_Character(QString filename){
    filename.remove(".chc");
    QFile file(filename+".ClC");

}

/*****class handler*****/
/*ClassFile structure:
 *Class Name
 *lv max
 *datanumber 16*fort+8*ref+4*will+bab
 *bab= 1(01) poor, 2(10) good ,3(11) average
 *endoffile
 */

CQTs_Class::CQTs_Class(QString classLink){
    classLink.remove(".ClC");
    QFile file(classLink+".ClC");//temporary
    int data;//data-sink for bab and ST
    int F=16, R=8, W=4, bab=3;//mask for ST&BAB
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){
        Name="error";
        data=0;
        lmax=-1;
    //add an alert!
       }
       else{
        QTextStream in(&file);
        Name= in.readLine();
        in >> lmax;
        in >> data;
    }
    fort = (data & F)/F;//good? 0/1
    ref = (data & R)/R;//good? 0/1
    will = (data & W)/W;//good ?0/1
    BAB = (data & bab);// good 10, poor 01, average 11, i know it's not intuitive
    /*qDebug()<<Name;
    qDebug()<<lmax;
    qDebug()<<data;
    qDebug()<<BAB;
    qDebug()<<fort;
    qDebug()<<ref;
    qDebug()<<will;
*/
}

QString CQTs_Class::className(){return Name;}

int CQTs_Class::classBAB(){return BAB;}

bool CQTs_Class::STFort(){return fort;}

bool CQTs_Class::STRef(){return ref;}

bool CQTs_Class::STWill(){return will;}

/*****utilities*****/

QStringList extensionFind(QString ext,QString dir){
    QDir workDir(dir);

    QStringList filelist;
    filelist = workDir.entryList(QStringList(ext),QDir::Files | QDir::NoSymLinks);
    return filelist;
}

QStringList extensionFind(QString ext){
    return extensionFind(ext,"./");
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2000-2007 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"
#include "csqsqrt.h"
#include "csgeom/sphere.h"
#include "imesh/objmodel.h"
#include "igeom/clip2d.h"
#include "plugins/engine/3d/sector.h"
#include "plugins/engine/3d/meshfact.h"
#include "plugins/engine/3d/meshlod.h"
#include "plugins/engine/3d/light.h"
#include "plugins/engine/3d/engine.h"
#include "iengine/portal.h"
#include "iengine/rview.h"
#include "ivideo/graph3d.h"
#include "ivideo/rendermesh.h"

CS_LEAKGUARD_IMPLEMENT (csMeshFactoryWrapper);

// ---------------------------------------------------------------------------
// csMeshFactoryWrapper
// ---------------------------------------------------------------------------

csMeshFactoryWrapper::csMeshFactoryWrapper (csEngine* engine,
                                            iMeshObjectFactory *meshFact)
  : scfImplementationType (this), meshFact (meshFact), parent (0),
  zbufMode (CS_ZBUF_USE), engine (engine)
{
  children.SetMeshFactory (this);

  render_priority = engine->GetObjectRenderPriority ();
  imposter_active = false;
  imposter_factory = 0;

  /* Work around iShaderVariableContext cast not working before
     CS::ShaderVariableContextImpl construction */
  csRefTrackerAccess::AddAlias (
    static_cast<iShaderVariableContext*> (this),
    this);
}

csMeshFactoryWrapper::csMeshFactoryWrapper (csEngine* engine)
  : scfImplementationType (this), parent (0), zbufMode (CS_ZBUF_USE),
  engine (engine)
{
  children.SetMeshFactory (this);

  render_priority = engine->GetObjectRenderPriority ();
  imposter_active = false;
  imposter_factory = 0;

  /* Work around iShaderVariableContext cast not working before
     CS::ShaderVariableContextImpl construction */
  csRefTrackerAccess::AddAlias (
    static_cast<iShaderVariableContext*> (this),
    this);
}

csMeshFactoryWrapper::~csMeshFactoryWrapper ()
{
  // This line MUST be here to ensure that the children are not
  // removed after the destructor has already finished.
  children.RemoveAll ();
  delete imposter_factory;
}

void csMeshFactoryWrapper::SelfDestruct ()
{
  engine->GetMeshFactories ()->Remove (
    static_cast<iMeshFactoryWrapper*> (this));
}

void csMeshFactoryWrapper::SetZBufModeRecursive (csZBufMode mode)
{
  SetZBufMode (mode);
  const iMeshFactoryList* ml = &children;
  if (!ml) return;
  int i;
  for (i = 0 ; i < ml->GetCount () ; i++)
    ml->Get (i)->SetZBufModeRecursive (mode);
}

void csMeshFactoryWrapper::SetRenderPriorityRecursive (long rp)
{
  SetRenderPriority (rp);
  const iMeshFactoryList* ml = &children;
  if (!ml) return;
  int i;
  for (i = 0 ; i < ml->GetCount () ; i++)
    ml->Get (i)->SetRenderPriorityRecursive (rp);
}

void csMeshFactoryWrapper::SetRenderPriority (long rp)
{
  render_priority = rp;
}

void csMeshFactoryWrapper::SetMeshObjectFactory (iMeshObjectFactory *meshFact)
{
  csMeshFactoryWrapper::meshFact = meshFact;
}

csPtr<iMeshWrapper> csMeshFactoryWrapper::CreateMeshWrapper ()
{
  csRef<iMeshObject> basemesh = meshFact->NewInstance ();
  csMeshWrapper* cmesh = new csMeshWrapper (engine, basemesh);
  iMeshWrapper* mesh = static_cast<iMeshWrapper*> (cmesh);
  basemesh->SetMeshWrapper (mesh);

  if (GetName ()) mesh->QueryObject ()->SetName (GetName ());
  mesh->SetFactory (this);
  mesh->SetRenderPriority (render_priority);
  mesh->SetZBufMode (zbufMode);
  mesh->GetFlags ().Set (flags.Get (), flags.Get ());

  if (static_lod)
  {
    iLODControl* lod = mesh->CreateStaticLOD ();
    iSharedVariable* varm, * vara;
    static_lod->GetLOD (varm, vara);
    if (varm)
    {
      lod->SetLOD (varm, vara);
    }
    else
    {
      float m, a;
      static_lod->GetLOD (m, a);
      lod->SetLOD (m, a);
    }
  }

  int i;
  for (i = 0; i < children.GetCount (); i++)
  {
    iMeshFactoryWrapper *childfact = children.Get (i);
    csRef<iMeshWrapper> child = childfact->CreateMeshWrapper ();
    child->QuerySceneNode ()->SetParent (mesh->QuerySceneNode ());
    child->GetMovable ()->SetTransform (childfact->GetTransform ());
    child->GetMovable ()->UpdateMove ();

    if (static_lod)
    {
      // We have static lod so we need to put the child in the right
      // lod level.
      int l;
      for (l = 0 ; l < static_lod->GetLODCount () ; l++)
      {
        csArray<iMeshFactoryWrapper*>& facts_for_lod =
      	  static_lod->GetMeshesForLOD (l);
        size_t j;
	for (j = 0 ; j < facts_for_lod.GetSize () ; j++)
	{
	  if (facts_for_lod[j] == childfact)
	    mesh->AddMeshToStaticLOD (l, child);
	}
      }
    }
  }

  return csPtr<iMeshWrapper> (mesh);
}

void csMeshFactoryWrapper::HardTransform (const csReversibleTransform &t)
{
  meshFact->HardTransform (t);
}

iLODControl* csMeshFactoryWrapper::CreateStaticLOD ()
{
  static_lod = csPtr<csStaticLODFactoryMesh> (new csStaticLODFactoryMesh ());
  return static_lod;
}

void csMeshFactoryWrapper::DestroyStaticLOD ()
{
  static_lod = 0;
}

iLODControl* csMeshFactoryWrapper::GetStaticLOD ()
{
  return (iLODControl*)static_lod;
}

void csMeshFactoryWrapper::SetStaticLOD (float m, float a)
{
  if (static_lod) static_lod->SetLOD (m, a);
}

void csMeshFactoryWrapper::GetStaticLOD (float& m, float& a) const
{
  if (static_lod)
    static_lod->GetLOD (m, a);
  else
  {
    m = 0;
    a = 0;
  }
}

void csMeshFactoryWrapper::RemoveFactoryFromStaticLOD (
	iMeshFactoryWrapper* fact)
{
  if (!static_lod) return;	// No static lod, nothing to do here.
  int lod;
  for (lod = 0 ; lod < static_lod->GetLODCount () ; lod++)
  {
    csArray<iMeshFactoryWrapper*>& meshes_for_lod =
    	static_lod->GetMeshesForLOD (lod);
    meshes_for_lod.Delete (fact);
  }
}

void csMeshFactoryWrapper::AddFactoryToStaticLOD (int lod,
	iMeshFactoryWrapper* fact)
{
  if (!static_lod) return;	// No static lod, nothing to do here.
  csArray<iMeshFactoryWrapper*>& meshes_for_lod =
  	static_lod->GetMeshesForLOD (lod);
  meshes_for_lod.Push (fact);
}

void csMeshFactoryWrapper::SetImposterActive (bool flag)
{
  imposter_active = flag;
  if (imposter_active)
  {
    if (!imposter_factory)
      imposter_factory = new csImposterFactory (this);
  }
  else if (!imposter_active)
  {
    delete imposter_factory;
  }
}

//--------------------------------------------------------------------------
// csMeshFactoryList
//--------------------------------------------------------------------------
csMeshFactoryList::csMeshFactoryList ()
  : scfImplementationType (this), list (64)
{
  listener.AttachNew (new NameChangeListener (this));
}

csMeshFactoryList::~csMeshFactoryList ()
{
  RemoveAll ();
}

void csMeshFactoryList::NameChanged (iObject* object, const char* oldname,
  	const char* newname)
{
  csRef<iMeshFactoryWrapper> mesh =
    scfQueryInterface<iMeshFactoryWrapper> (object);
  CS_ASSERT (mesh != 0);
  if (oldname) factories_hash.Delete (oldname, mesh);
  if (newname) factories_hash.Put (newname, mesh);
}

int csMeshFactoryList::Add (iMeshFactoryWrapper *obj)
{
  PrepareFactory (obj);
  const char* name = obj->QueryObject ()->GetName ();
  if (name)
    factories_hash.Put (name, obj);
  obj->QueryObject ()->AddNameChangeListener (listener);
  return (int)list.Push (obj);
}

bool csMeshFactoryList::Remove (iMeshFactoryWrapper *obj)
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  FreeFactory (obj);
  const char* name = obj->QueryObject ()->GetName ();
  if (name)
    factories_hash.Delete (name, obj);
  obj->QueryObject ()->RemoveNameChangeListener (listener);
  list.Delete (obj);
  return true;
}

bool csMeshFactoryList::Remove (int n)
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  return Remove (Get (n));
}

void csMeshFactoryList::RemoveAll ()
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  size_t i;
  for (i = 0 ; i < list.GetSize () ; i++)
  {
    list[i]->QueryObject ()->RemoveNameChangeListener (listener);
    FreeFactory (list[i]);
  }
  factories_hash.DeleteAll ();
  list.DeleteAll ();
}

int csMeshFactoryList::Find (iMeshFactoryWrapper *obj) const
{
  return (int)list.Find (obj);
}

iMeshFactoryWrapper *csMeshFactoryList::FindByName (
  const char *Name) const
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  if (!Name) return 0;
  return factories_hash.Get (Name, 0);
}

//--------------------------------------------------------------------------
// csMeshFactoryFactoryList
//--------------------------------------------------------------------------
void csMeshFactoryFactoryList::PrepareFactory (iMeshFactoryWrapper* child)
{
  CS_ASSERT (meshfact != 0);
  csMeshFactoryList::PrepareFactory (child);

  // unlink the factory from another possible parent.
  if (child->GetParentContainer ())
    child->GetParentContainer ()->GetChildren ()->Remove (child);

  child->SetParentContainer (meshfact);
}

void csMeshFactoryFactoryList::FreeFactory (iMeshFactoryWrapper* item)
{
  CS_ASSERT (meshfact != 0);
  item->SetParentContainer (0);
  meshfact->RemoveFactoryFromStaticLOD (item);
  csMeshFactoryList::FreeFactory (item);
}
<commit_msg>eol-style + mime-type<commit_after>/*
    Copyright (C) 2000-2007 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "cssysdef.h"
#include "csqsqrt.h"
#include "csgeom/sphere.h"
#include "imesh/objmodel.h"
#include "igeom/clip2d.h"
#include "plugins/engine/3d/sector.h"
#include "plugins/engine/3d/meshfact.h"
#include "plugins/engine/3d/meshlod.h"
#include "plugins/engine/3d/light.h"
#include "plugins/engine/3d/engine.h"
#include "iengine/portal.h"
#include "iengine/rview.h"
#include "ivideo/graph3d.h"
#include "ivideo/rendermesh.h"

CS_LEAKGUARD_IMPLEMENT (csMeshFactoryWrapper);

// ---------------------------------------------------------------------------
// csMeshFactoryWrapper
// ---------------------------------------------------------------------------

csMeshFactoryWrapper::csMeshFactoryWrapper (csEngine* engine,
                                            iMeshObjectFactory *meshFact)
  : scfImplementationType (this), meshFact (meshFact), parent (0),
  zbufMode (CS_ZBUF_USE), engine (engine)
{
  children.SetMeshFactory (this);

  render_priority = engine->GetObjectRenderPriority ();
  imposter_active = false;
  imposter_factory = 0;

  /* Work around iShaderVariableContext cast not working before
     CS::ShaderVariableContextImpl construction */
  csRefTrackerAccess::AddAlias (
    static_cast<iShaderVariableContext*> (this),
    this);
}

csMeshFactoryWrapper::csMeshFactoryWrapper (csEngine* engine)
  : scfImplementationType (this), parent (0), zbufMode (CS_ZBUF_USE),
  engine (engine)
{
  children.SetMeshFactory (this);

  render_priority = engine->GetObjectRenderPriority ();
  imposter_active = false;
  imposter_factory = 0;

  /* Work around iShaderVariableContext cast not working before
     CS::ShaderVariableContextImpl construction */
  csRefTrackerAccess::AddAlias (
    static_cast<iShaderVariableContext*> (this),
    this);
}

csMeshFactoryWrapper::~csMeshFactoryWrapper ()
{
  // This line MUST be here to ensure that the children are not
  // removed after the destructor has already finished.
  children.RemoveAll ();
  delete imposter_factory;
}

void csMeshFactoryWrapper::SelfDestruct ()
{
  engine->GetMeshFactories ()->Remove (
    static_cast<iMeshFactoryWrapper*> (this));
}

void csMeshFactoryWrapper::SetZBufModeRecursive (csZBufMode mode)
{
  SetZBufMode (mode);
  const iMeshFactoryList* ml = &children;
  if (!ml) return;
  int i;
  for (i = 0 ; i < ml->GetCount () ; i++)
    ml->Get (i)->SetZBufModeRecursive (mode);
}

void csMeshFactoryWrapper::SetRenderPriorityRecursive (long rp)
{
  SetRenderPriority (rp);
  const iMeshFactoryList* ml = &children;
  if (!ml) return;
  int i;
  for (i = 0 ; i < ml->GetCount () ; i++)
    ml->Get (i)->SetRenderPriorityRecursive (rp);
}

void csMeshFactoryWrapper::SetRenderPriority (long rp)
{
  render_priority = rp;
}

void csMeshFactoryWrapper::SetMeshObjectFactory (iMeshObjectFactory *meshFact)
{
  csMeshFactoryWrapper::meshFact = meshFact;
}

csPtr<iMeshWrapper> csMeshFactoryWrapper::CreateMeshWrapper ()
{
  csRef<iMeshObject> basemesh = meshFact->NewInstance ();
  csMeshWrapper* cmesh = new csMeshWrapper (engine, basemesh);
  iMeshWrapper* mesh = static_cast<iMeshWrapper*> (cmesh);
  basemesh->SetMeshWrapper (mesh);

  if (GetName ()) mesh->QueryObject ()->SetName (GetName ());
  mesh->SetFactory (this);
  mesh->SetRenderPriority (render_priority);
  mesh->SetZBufMode (zbufMode);
  mesh->GetFlags ().Set (flags.Get (), flags.Get ());

  if (static_lod)
  {
    iLODControl* lod = mesh->CreateStaticLOD ();
    iSharedVariable* varm, * vara;
    static_lod->GetLOD (varm, vara);
    if (varm)
    {
      lod->SetLOD (varm, vara);
    }
    else
    {
      float m, a;
      static_lod->GetLOD (m, a);
      lod->SetLOD (m, a);
    }
  }

  int i;
  for (i = 0; i < children.GetCount (); i++)
  {
    iMeshFactoryWrapper *childfact = children.Get (i);
    csRef<iMeshWrapper> child = childfact->CreateMeshWrapper ();
    child->QuerySceneNode ()->SetParent (mesh->QuerySceneNode ());
    child->GetMovable ()->SetTransform (childfact->GetTransform ());
    child->GetMovable ()->UpdateMove ();

    if (static_lod)
    {
      // We have static lod so we need to put the child in the right
      // lod level.
      int l;
      for (l = 0 ; l < static_lod->GetLODCount () ; l++)
      {
        csArray<iMeshFactoryWrapper*>& facts_for_lod =
      	  static_lod->GetMeshesForLOD (l);
        size_t j;
	for (j = 0 ; j < facts_for_lod.GetSize () ; j++)
	{
	  if (facts_for_lod[j] == childfact)
	    mesh->AddMeshToStaticLOD (l, child);
	}
      }
    }
  }

  return csPtr<iMeshWrapper> (mesh);
}

void csMeshFactoryWrapper::HardTransform (const csReversibleTransform &t)
{
  meshFact->HardTransform (t);
}

iLODControl* csMeshFactoryWrapper::CreateStaticLOD ()
{
  static_lod = csPtr<csStaticLODFactoryMesh> (new csStaticLODFactoryMesh ());
  return static_lod;
}

void csMeshFactoryWrapper::DestroyStaticLOD ()
{
  static_lod = 0;
}

iLODControl* csMeshFactoryWrapper::GetStaticLOD ()
{
  return (iLODControl*)static_lod;
}

void csMeshFactoryWrapper::SetStaticLOD (float m, float a)
{
  if (static_lod) static_lod->SetLOD (m, a);
}

void csMeshFactoryWrapper::GetStaticLOD (float& m, float& a) const
{
  if (static_lod)
    static_lod->GetLOD (m, a);
  else
  {
    m = 0;
    a = 0;
  }
}

void csMeshFactoryWrapper::RemoveFactoryFromStaticLOD (
	iMeshFactoryWrapper* fact)
{
  if (!static_lod) return;	// No static lod, nothing to do here.
  int lod;
  for (lod = 0 ; lod < static_lod->GetLODCount () ; lod++)
  {
    csArray<iMeshFactoryWrapper*>& meshes_for_lod =
    	static_lod->GetMeshesForLOD (lod);
    meshes_for_lod.Delete (fact);
  }
}

void csMeshFactoryWrapper::AddFactoryToStaticLOD (int lod,
	iMeshFactoryWrapper* fact)
{
  if (!static_lod) return;	// No static lod, nothing to do here.
  csArray<iMeshFactoryWrapper*>& meshes_for_lod =
  	static_lod->GetMeshesForLOD (lod);
  meshes_for_lod.Push (fact);
}

void csMeshFactoryWrapper::SetImposterActive (bool flag)
{
  imposter_active = flag;
  if (imposter_active)
  {
    if (!imposter_factory)
      imposter_factory = new csImposterFactory (this);
  }
  else if (!imposter_active)
  {
    delete imposter_factory;
  }
}

//--------------------------------------------------------------------------
// csMeshFactoryList
//--------------------------------------------------------------------------
csMeshFactoryList::csMeshFactoryList ()
  : scfImplementationType (this), list (64)
{
  listener.AttachNew (new NameChangeListener (this));
}

csMeshFactoryList::~csMeshFactoryList ()
{
  RemoveAll ();
}

void csMeshFactoryList::NameChanged (iObject* object, const char* oldname,
  	const char* newname)
{
  csRef<iMeshFactoryWrapper> mesh =
    scfQueryInterface<iMeshFactoryWrapper> (object);
  CS_ASSERT (mesh != 0);
  if (oldname) factories_hash.Delete (oldname, mesh);
  if (newname) factories_hash.Put (newname, mesh);
}

int csMeshFactoryList::Add (iMeshFactoryWrapper *obj)
{
  PrepareFactory (obj);
  const char* name = obj->QueryObject ()->GetName ();
  if (name)
    factories_hash.Put (name, obj);
  obj->QueryObject ()->AddNameChangeListener (listener);
  return (int)list.Push (obj);
}

bool csMeshFactoryList::Remove (iMeshFactoryWrapper *obj)
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  FreeFactory (obj);
  const char* name = obj->QueryObject ()->GetName ();
  if (name)
    factories_hash.Delete (name, obj);
  obj->QueryObject ()->RemoveNameChangeListener (listener);
  list.Delete (obj);
  return true;
}

bool csMeshFactoryList::Remove (int n)
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  return Remove (Get (n));
}

void csMeshFactoryList::RemoveAll ()
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  size_t i;
  for (i = 0 ; i < list.GetSize () ; i++)
  {
    list[i]->QueryObject ()->RemoveNameChangeListener (listener);
    FreeFactory (list[i]);
  }
  factories_hash.DeleteAll ();
  list.DeleteAll ();
}

int csMeshFactoryList::Find (iMeshFactoryWrapper *obj) const
{
  return (int)list.Find (obj);
}

iMeshFactoryWrapper *csMeshFactoryList::FindByName (
  const char *Name) const
{
  CS::Threading::RecursiveMutexScopedLock lock(removeLock);
  if (!Name) return 0;
  return factories_hash.Get (Name, 0);
}

//--------------------------------------------------------------------------
// csMeshFactoryFactoryList
//--------------------------------------------------------------------------
void csMeshFactoryFactoryList::PrepareFactory (iMeshFactoryWrapper* child)
{
  CS_ASSERT (meshfact != 0);
  csMeshFactoryList::PrepareFactory (child);

  // unlink the factory from another possible parent.
  if (child->GetParentContainer ())
    child->GetParentContainer ()->GetChildren ()->Remove (child);

  child->SetParentContainer (meshfact);
}

void csMeshFactoryFactoryList::FreeFactory (iMeshFactoryWrapper* item)
{
  CS_ASSERT (meshfact != 0);
  item->SetParentContainer (0);
  meshfact->RemoveFactoryFromStaticLOD (item);
  csMeshFactoryList::FreeFactory (item);
}
<|endoftext|>


<commit_before>// Time:  O(nlogn)
// Space: O(n)

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number
     *          and the index of the last number
     */
    vector<int> subarraySumClosest(vector<int> nums) {
        const int n = nums.size();

        if (n == 1) {
            return {0, 0};
        }

        // sum_from_start[i] denotes sum for 0 ~ i - 1.
        vector<pair<int,int>> sum_from_start(n + 1, make_pair(0, 0));
        sum_from_start[0].second = -1; // For case closest sum is from 0.
        for (int  i = 0; i < n; ++i) {
            sum_from_start[i+1].first = sum_from_start[i].first + nums[i];
            sum_from_start[i+1].second = i;
        }

        // Sort each sum from start.
        sort(sum_from_start.begin(), sum_from_start.end());

        int min_diff = INT_MAX;
        int start = -1;
        int end = -1;

        // Find min difference of adjacent sum.
        for (int i = 1; i <= n; ++i) {
            int diff = abs(sum_from_start[i].first - sum_from_start[i-1].first);
            if (diff < min_diff) {
                min_diff = diff;
                start = min(sum_from_start[i].second, sum_from_start[i - 1].second) + 1;
                end = max(sum_from_start[i].second, sum_from_start[i - 1].second);
            }
        }

        return {start, end};
    }
};
<commit_msg>Update subarray-sum-closest.cpp<commit_after>// Time:  O(nlogn)
// Space: O(n)

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number
     *          and the index of the last number
     */
    vector<int> subarraySumClosest(vector<int> nums) {
        const int n = nums.size();

        if (n == 1) {
            return {0, 0};
        }

        // sum_from_start[i] denotes sum for 0 ~ i - 1.
        vector<pair<int,int>> sum_from_start(n + 1, {0, 0});
        sum_from_start[0].second = -1; // For case closest sum is from 0.
        for (int  i = 0; i < n; ++i) {
            sum_from_start[i+1].first = sum_from_start[i].first + nums[i];
            sum_from_start[i+1].second = i;
        }

        // Sort each sum from start.
        sort(sum_from_start.begin(), sum_from_start.end());

        int min_diff = INT_MAX;
        int start = -1;
        int end = -1;

        // Find min difference of adjacent sum.
        for (int i = 1; i <= n; ++i) {
            int diff = abs(sum_from_start[i].first - sum_from_start[i-1].first);
            if (diff < min_diff) {
                min_diff = diff;
                start = min(sum_from_start[i].second, sum_from_start[i - 1].second) + 1;
                end = max(sum_from_start[i].second, sum_from_start[i - 1].second);
            }
        }

        return {start, end};
    }
};
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>

#include <string>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/threading/platform_thread.h"  // For |Sleep()|.
#include "mojo/common/test/multiprocess_test_helper.h"
#include "mojo/embedder/scoped_platform_handle.h"
#include "mojo/system/channel.h"
#include "mojo/system/local_message_pipe_endpoint.h"
#include "mojo/system/message_pipe.h"
#include "mojo/system/proxy_message_pipe_endpoint.h"
#include "mojo/system/raw_channel.h"
#include "mojo/system/test_utils.h"
#include "mojo/system/waiter.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace system {
namespace {

class ChannelThread {
 public:
  ChannelThread() : test_io_thread_(test::TestIOThread::kManualStart) {}
  ~ChannelThread() {
    Stop();
  }

  void Start(embedder::ScopedPlatformHandle platform_handle,
             scoped_refptr<MessagePipe> message_pipe) {
    test_io_thread_.Start();
    test_io_thread_.PostTaskAndWait(
        FROM_HERE,
        base::Bind(&ChannelThread::InitChannelOnIOThread,
                   base::Unretained(this), base::Passed(&platform_handle),
                   message_pipe));
  }

  void Stop() {
    if (channel_) {
      // Hack to flush write buffers before quitting.
      // TODO(vtl): Remove this once |Channel| has a
      // |FlushWriteBufferAndShutdown()| (or whatever).
      while (!channel_->IsWriteBufferEmpty())
        base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));

      test_io_thread_.PostTaskAndWait(
          FROM_HERE,
          base::Bind(&ChannelThread::ShutdownChannelOnIOThread,
                     base::Unretained(this)));
    }
    test_io_thread_.Stop();
  }

 private:
  void InitChannelOnIOThread(embedder::ScopedPlatformHandle platform_handle,
                             scoped_refptr<MessagePipe> message_pipe) {
    CHECK_EQ(base::MessageLoop::current(), test_io_thread_.message_loop());
    CHECK(platform_handle.is_valid());

    // Create and initialize |Channel|.
    channel_ = new Channel();
    CHECK(channel_->Init(RawChannel::Create(platform_handle.Pass())));

    // Attach the message pipe endpoint.
    // Note: On the "server" (parent process) side, we need not attach the
    // message pipe endpoint immediately. However, on the "client" (child
    // process) side, this *must* be done here -- otherwise, the |Channel| may
    // receive/process messages (which it can do as soon as it's hooked up to
    // the IO thread message loop, and that message loop runs) before the
    // message pipe endpoint is attached.
    CHECK_EQ(channel_->AttachMessagePipeEndpoint(message_pipe, 1),
             Channel::kBootstrapEndpointId);
    CHECK(channel_->RunMessagePipeEndpoint(Channel::kBootstrapEndpointId,
                                           Channel::kBootstrapEndpointId));
  }

  void ShutdownChannelOnIOThread() {
    CHECK(channel_.get());
    channel_->Shutdown();
    channel_ = NULL;
  }

  test::TestIOThread test_io_thread_;
  scoped_refptr<Channel> channel_;

  DISALLOW_COPY_AND_ASSIGN(ChannelThread);
};

class MultiprocessMessagePipeTest : public testing::Test {
 public:
  MultiprocessMessagePipeTest() {}
  virtual ~MultiprocessMessagePipeTest() {}

 protected:
  void Init(scoped_refptr<MessagePipe> mp) {
    channel_thread_.Start(helper_.server_platform_handle.Pass(), mp);
  }

  mojo::test::MultiprocessTestHelper* helper() { return &helper_; }

 private:
  ChannelThread channel_thread_;
  mojo::test::MultiprocessTestHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTest);
};

MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) {
  Waiter waiter;
  waiter.Init();

  MojoResult add_result = mp->AddWaiter(0, &waiter, flags, MOJO_RESULT_OK);
  if (add_result != MOJO_RESULT_OK) {
    return (add_result == MOJO_RESULT_ALREADY_EXISTS) ? MOJO_RESULT_OK :
                                                        add_result;
  }

  MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE);
  mp->RemoveWaiter(0, &waiter);
  return wait_result;
}

// For each message received, sends a reply message with the same contents
// repeated twice, until the other end is closed or it receives "quitquitquit"
// (which it doesn't reply to). It'll return the number of messages received,
// not including any "quitquitquit" message, modulo 100.
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) {
  ChannelThread channel_thread;
  embedder::ScopedPlatformHandle client_platform_handle =
      mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
  CHECK(client_platform_handle.is_valid());
  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  channel_thread.Start(client_platform_handle.Pass(), mp);

  const std::string quitquitquit("quitquitquit");
  int rv = 0;
  for (;; rv = (rv + 1) % 100) {
    // Wait for our end of the message pipe to be readable.
    MojoResult result = WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE);
    if (result != MOJO_RESULT_OK) {
      // It was closed, probably.
      CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION);
      break;
    }

    std::string read_buffer(1000, '\0');
    uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
    CHECK_EQ(mp->ReadMessage(0,
                             &read_buffer[0], &read_buffer_size,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
    read_buffer.resize(read_buffer_size);
    VLOG(2) << "Child got: " << read_buffer;

    if (read_buffer == quitquitquit) {
      VLOG(2) << "Child quitting.";
      break;
    }

    std::string write_buffer = read_buffer + read_buffer;
    CHECK_EQ(mp->WriteMessage(0,
                              write_buffer.data(),
                              static_cast<uint32_t>(write_buffer.size()),
                              NULL,
                              MOJO_WRITE_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
  }

  mp->Close(0);
  return rv;
}

// Sends "hello" to child, and expects "hellohello" back.
TEST_F(MultiprocessMessagePipeTest, Basic) {
  helper()->StartChild("EchoEcho");

  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  Init(mp);

  std::string hello("hello");
  EXPECT_EQ(MOJO_RESULT_OK,
            mp->WriteMessage(0,
                             hello.data(), static_cast<uint32_t>(hello.size()),
                             NULL,
                             MOJO_WRITE_MESSAGE_FLAG_NONE));

  EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

  std::string read_buffer(1000, '\0');
  uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
  CHECK_EQ(mp->ReadMessage(0,
                           &read_buffer[0], &read_buffer_size,
                           NULL, NULL,
                           MOJO_READ_MESSAGE_FLAG_NONE),
           MOJO_RESULT_OK);
  read_buffer.resize(read_buffer_size);
  VLOG(2) << "Parent got: " << read_buffer;
  EXPECT_EQ(hello + hello, read_buffer);

  mp->Close(0);

  // We sent one message.
  EXPECT_EQ(1 % 100, helper()->WaitForChildShutdown());
}

// Sends a bunch of messages to the child. Expects them "repeated" back. Waits
// for the child to close its end before quitting.
TEST_F(MultiprocessMessagePipeTest, QueueMessages) {
  helper()->StartChild("EchoEcho");

  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  Init(mp);

  static const size_t kNumMessages = 1001;
  for (size_t i = 0; i < kNumMessages; i++) {
    std::string write_buffer(i, 'A' + (i % 26));
    EXPECT_EQ(MOJO_RESULT_OK,
              mp->WriteMessage(0,
                               write_buffer.data(),
                               static_cast<uint32_t>(write_buffer.size()),
                               NULL,
                               MOJO_WRITE_MESSAGE_FLAG_NONE));
  }

  const std::string quitquitquit("quitquitquit");
  EXPECT_EQ(MOJO_RESULT_OK,
            mp->WriteMessage(0,
                             quitquitquit.data(),
                             static_cast<uint32_t>(quitquitquit.size()),
                             NULL,
                             MOJO_WRITE_MESSAGE_FLAG_NONE));

  for (size_t i = 0; i < kNumMessages; i++) {
    EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

    std::string read_buffer(kNumMessages * 2, '\0');
    uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
    CHECK_EQ(mp->ReadMessage(0,
                             &read_buffer[0], &read_buffer_size,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
    read_buffer.resize(read_buffer_size);

    EXPECT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer);
  }

  // Wait for it to become readable, which should fail (since we sent
  // "quitquitquit").
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

  mp->Close(0);

  EXPECT_EQ(static_cast<int>(kNumMessages % 100),
            helper()->WaitForChildShutdown());
}

}  // namespace
}  // namespace system
}  // namespace mojo
<commit_msg>Mojo: Add a multiprocess platform handle passing test.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdint.h>
#include <stdio.h>

#include <string>
#include <vector>

#include "base/bind.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/threading/platform_thread.h"  // For |Sleep()|.
#include "build/build_config.h"  // TODO(vtl): Remove this.
#include "mojo/common/test/multiprocess_test_helper.h"
#include "mojo/common/test/test_utils.h"
#include "mojo/embedder/scoped_platform_handle.h"
#include "mojo/system/channel.h"
#include "mojo/system/dispatcher.h"
#include "mojo/system/local_message_pipe_endpoint.h"
#include "mojo/system/message_pipe.h"
#include "mojo/system/platform_handle_dispatcher.h"
#include "mojo/system/proxy_message_pipe_endpoint.h"
#include "mojo/system/raw_channel.h"
#include "mojo/system/test_utils.h"
#include "mojo/system/waiter.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace system {
namespace {

class ChannelThread {
 public:
  ChannelThread() : test_io_thread_(test::TestIOThread::kManualStart) {}
  ~ChannelThread() {
    Stop();
  }

  void Start(embedder::ScopedPlatformHandle platform_handle,
             scoped_refptr<MessagePipe> message_pipe) {
    test_io_thread_.Start();
    test_io_thread_.PostTaskAndWait(
        FROM_HERE,
        base::Bind(&ChannelThread::InitChannelOnIOThread,
                   base::Unretained(this), base::Passed(&platform_handle),
                   message_pipe));
  }

  void Stop() {
    if (channel_) {
      // Hack to flush write buffers before quitting.
      // TODO(vtl): Remove this once |Channel| has a
      // |FlushWriteBufferAndShutdown()| (or whatever).
      while (!channel_->IsWriteBufferEmpty())
        base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));

      test_io_thread_.PostTaskAndWait(
          FROM_HERE,
          base::Bind(&ChannelThread::ShutdownChannelOnIOThread,
                     base::Unretained(this)));
    }
    test_io_thread_.Stop();
  }

 private:
  void InitChannelOnIOThread(embedder::ScopedPlatformHandle platform_handle,
                             scoped_refptr<MessagePipe> message_pipe) {
    CHECK_EQ(base::MessageLoop::current(), test_io_thread_.message_loop());
    CHECK(platform_handle.is_valid());

    // Create and initialize |Channel|.
    channel_ = new Channel();
    CHECK(channel_->Init(RawChannel::Create(platform_handle.Pass())));

    // Attach the message pipe endpoint.
    // Note: On the "server" (parent process) side, we need not attach the
    // message pipe endpoint immediately. However, on the "client" (child
    // process) side, this *must* be done here -- otherwise, the |Channel| may
    // receive/process messages (which it can do as soon as it's hooked up to
    // the IO thread message loop, and that message loop runs) before the
    // message pipe endpoint is attached.
    CHECK_EQ(channel_->AttachMessagePipeEndpoint(message_pipe, 1),
             Channel::kBootstrapEndpointId);
    CHECK(channel_->RunMessagePipeEndpoint(Channel::kBootstrapEndpointId,
                                           Channel::kBootstrapEndpointId));
  }

  void ShutdownChannelOnIOThread() {
    CHECK(channel_.get());
    channel_->Shutdown();
    channel_ = NULL;
  }

  test::TestIOThread test_io_thread_;
  scoped_refptr<Channel> channel_;

  DISALLOW_COPY_AND_ASSIGN(ChannelThread);
};

class MultiprocessMessagePipeTest : public testing::Test {
 public:
  MultiprocessMessagePipeTest() {}
  virtual ~MultiprocessMessagePipeTest() {}

 protected:
  void Init(scoped_refptr<MessagePipe> mp) {
    channel_thread_.Start(helper_.server_platform_handle.Pass(), mp);
  }

  mojo::test::MultiprocessTestHelper* helper() { return &helper_; }

 private:
  ChannelThread channel_thread_;
  mojo::test::MultiprocessTestHelper helper_;

  DISALLOW_COPY_AND_ASSIGN(MultiprocessMessagePipeTest);
};

MojoResult WaitIfNecessary(scoped_refptr<MessagePipe> mp, MojoWaitFlags flags) {
  Waiter waiter;
  waiter.Init();

  MojoResult add_result = mp->AddWaiter(0, &waiter, flags, MOJO_RESULT_OK);
  if (add_result != MOJO_RESULT_OK) {
    return (add_result == MOJO_RESULT_ALREADY_EXISTS) ? MOJO_RESULT_OK :
                                                        add_result;
  }

  MojoResult wait_result = waiter.Wait(MOJO_DEADLINE_INDEFINITE);
  mp->RemoveWaiter(0, &waiter);
  return wait_result;
}

// For each message received, sends a reply message with the same contents
// repeated twice, until the other end is closed or it receives "quitquitquit"
// (which it doesn't reply to). It'll return the number of messages received,
// not including any "quitquitquit" message, modulo 100.
MOJO_MULTIPROCESS_TEST_CHILD_MAIN(EchoEcho) {
  ChannelThread channel_thread;
  embedder::ScopedPlatformHandle client_platform_handle =
      mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
  CHECK(client_platform_handle.is_valid());
  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  channel_thread.Start(client_platform_handle.Pass(), mp);

  const std::string quitquitquit("quitquitquit");
  int rv = 0;
  for (;; rv = (rv + 1) % 100) {
    // Wait for our end of the message pipe to be readable.
    MojoResult result = WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE);
    if (result != MOJO_RESULT_OK) {
      // It was closed, probably.
      CHECK_EQ(result, MOJO_RESULT_FAILED_PRECONDITION);
      break;
    }

    std::string read_buffer(1000, '\0');
    uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
    CHECK_EQ(mp->ReadMessage(0,
                             &read_buffer[0], &read_buffer_size,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
    read_buffer.resize(read_buffer_size);
    VLOG(2) << "Child got: " << read_buffer;

    if (read_buffer == quitquitquit) {
      VLOG(2) << "Child quitting.";
      break;
    }

    std::string write_buffer = read_buffer + read_buffer;
    CHECK_EQ(mp->WriteMessage(0,
                              write_buffer.data(),
                              static_cast<uint32_t>(write_buffer.size()),
                              NULL,
                              MOJO_WRITE_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
  }

  mp->Close(0);
  return rv;
}

// Sends "hello" to child, and expects "hellohello" back.
TEST_F(MultiprocessMessagePipeTest, Basic) {
  helper()->StartChild("EchoEcho");

  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  Init(mp);

  std::string hello("hello");
  EXPECT_EQ(MOJO_RESULT_OK,
            mp->WriteMessage(0,
                             hello.data(), static_cast<uint32_t>(hello.size()),
                             NULL,
                             MOJO_WRITE_MESSAGE_FLAG_NONE));

  EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

  std::string read_buffer(1000, '\0');
  uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
  CHECK_EQ(mp->ReadMessage(0,
                           &read_buffer[0], &read_buffer_size,
                           NULL, NULL,
                           MOJO_READ_MESSAGE_FLAG_NONE),
           MOJO_RESULT_OK);
  read_buffer.resize(read_buffer_size);
  VLOG(2) << "Parent got: " << read_buffer;
  EXPECT_EQ(hello + hello, read_buffer);

  mp->Close(0);

  // We sent one message.
  EXPECT_EQ(1 % 100, helper()->WaitForChildShutdown());
}

// Sends a bunch of messages to the child. Expects them "repeated" back. Waits
// for the child to close its end before quitting.
TEST_F(MultiprocessMessagePipeTest, QueueMessages) {
  helper()->StartChild("EchoEcho");

  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  Init(mp);

  static const size_t kNumMessages = 1001;
  for (size_t i = 0; i < kNumMessages; i++) {
    std::string write_buffer(i, 'A' + (i % 26));
    EXPECT_EQ(MOJO_RESULT_OK,
              mp->WriteMessage(0,
                               write_buffer.data(),
                               static_cast<uint32_t>(write_buffer.size()),
                               NULL,
                               MOJO_WRITE_MESSAGE_FLAG_NONE));
  }

  const std::string quitquitquit("quitquitquit");
  EXPECT_EQ(MOJO_RESULT_OK,
            mp->WriteMessage(0,
                             quitquitquit.data(),
                             static_cast<uint32_t>(quitquitquit.size()),
                             NULL,
                             MOJO_WRITE_MESSAGE_FLAG_NONE));

  for (size_t i = 0; i < kNumMessages; i++) {
    EXPECT_EQ(MOJO_RESULT_OK, WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

    std::string read_buffer(kNumMessages * 2, '\0');
    uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer.size());
    CHECK_EQ(mp->ReadMessage(0,
                             &read_buffer[0], &read_buffer_size,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE),
             MOJO_RESULT_OK);
    read_buffer.resize(read_buffer_size);

    EXPECT_EQ(std::string(i * 2, 'A' + (i % 26)), read_buffer);
  }

  // Wait for it to become readable, which should fail (since we sent
  // "quitquitquit").
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

  mp->Close(0);

  EXPECT_EQ(static_cast<int>(kNumMessages % 100),
            helper()->WaitForChildShutdown());
}

MOJO_MULTIPROCESS_TEST_CHILD_MAIN(CheckPlatformHandleFile) {
  ChannelThread channel_thread;
  embedder::ScopedPlatformHandle client_platform_handle =
      mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
  CHECK(client_platform_handle.is_valid());
  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  channel_thread.Start(client_platform_handle.Pass(), mp);

  CHECK_EQ(WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE), MOJO_RESULT_OK);

  std::string read_buffer(100, '\0');
  uint32_t num_bytes = static_cast<uint32_t>(read_buffer.size());
  DispatcherVector dispatchers;
  uint32_t num_dispatchers = 10;  // Maximum number to receive.
  CHECK_EQ(mp->ReadMessage(0,
                           &read_buffer[0], &num_bytes,
                           &dispatchers, &num_dispatchers,
                           MOJO_READ_MESSAGE_FLAG_NONE),
           MOJO_RESULT_OK);
  mp->Close(0);

  read_buffer.resize(num_bytes);
  CHECK_EQ(read_buffer, std::string("hello"));
  CHECK_EQ(num_dispatchers, 1u);

  CHECK_EQ(dispatchers[0]->GetType(), Dispatcher::kTypePlatformHandle);

  scoped_refptr<PlatformHandleDispatcher> dispatcher(
      static_cast<PlatformHandleDispatcher*>(dispatchers[0].get()));
  embedder::ScopedPlatformHandle h = dispatcher->PassPlatformHandle().Pass();
  CHECK(h.is_valid());
  dispatcher->Close();

  base::ScopedFILE fp(mojo::test::FILEFromPlatformHandle(h.Pass(), "r"));
  CHECK(fp);
  std::string fread_buffer(100, '\0');
  size_t bytes_read = fread(&fread_buffer[0], 1, fread_buffer.size(), fp.get());
  fread_buffer.resize(bytes_read);
  CHECK_EQ(fread_buffer, "world");

  return 0;
}

#if defined(OS_POSIX)
#if defined(OS_MACOSX)
// TODO(vtl): Apparently, cmsgs on SOCK_STREAM AF_UNIX sockets don't work the
// way I thought they work, at least on Mac. (The non-control data gets merged
// with subsequent data.)
#define MAYBE_PlatformHandlePassing DISABLED_PlatformHandlePassing
#else
#define MAYBE_PlatformHandlePassing PlatformHandlePassing
#endif
#else
// Not yet implemented (on Windows).
#define MAYBE_PlatformHandlePassing DISABLED_PlatformHandlePassing
#endif
TEST_F(MultiprocessMessagePipeTest, MAYBE_PlatformHandlePassing) {
  helper()->StartChild("CheckPlatformHandleFile");

  scoped_refptr<MessagePipe> mp(new MessagePipe(
      scoped_ptr<MessagePipeEndpoint>(new LocalMessagePipeEndpoint()),
      scoped_ptr<MessagePipeEndpoint>(new ProxyMessagePipeEndpoint())));
  Init(mp);

  base::FilePath unused;
  base::ScopedFILE fp(CreateAndOpenTemporaryFile(&unused));
  const std::string world("world");
  ASSERT_EQ(fwrite(&world[0], 1, world.size(), fp.get()), world.size());
  fflush(fp.get());
  rewind(fp.get());

  embedder::ScopedPlatformHandle h(
      mojo::test::PlatformHandleFromFILE(fp.Pass()));
  scoped_refptr<PlatformHandleDispatcher> dispatcher(
      new PlatformHandleDispatcher(h.Pass()));

  const std::string hello("hello");
  DispatcherTransport transport(
      test::DispatcherTryStartTransport(dispatcher.get()));
  ASSERT_TRUE(transport.is_valid());

  std::vector<DispatcherTransport> transports;
  transports.push_back(transport);
  EXPECT_EQ(MOJO_RESULT_OK,
            mp->WriteMessage(0,
                             &hello[0],
                             static_cast<uint32_t>(hello.size()),
                             &transports,
                             MOJO_WRITE_MESSAGE_FLAG_NONE));
  transport.End();

  EXPECT_TRUE(dispatcher->HasOneRef());
  dispatcher = NULL;

  // Wait for it to become readable, which should fail.
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            WaitIfNecessary(mp, MOJO_WAIT_FLAG_READABLE));

  mp->Close(0);

  EXPECT_EQ(0, helper()->WaitForChildShutdown());
}

}  // namespace
}  // namespace system
}  // namespace mojo
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <ros/package.h> // for getting file path for loadng images

#include <moveit/setup_assistant/tools/compute_default_collisions.h>
#include <moveit/setup_assistant/tools/moveit_config_data.h>

#include <boost/filesystem.hpp>  // for reading folders/files
#include <boost/program_options.hpp>
#include <boost/algorithm/string/join.hpp>

#include <fstream>  // for reading in urdf
#include <streambuf>

namespace fs = boost::filesystem;
namespace po = boost::program_options;

bool isXacroFile(const std::string& path) { return path.find(".xacro") != std::string::npos; } // TODO: implement case-insensitive search

bool loadFileToString(std::string& buffer, const std::string& path){
    if(path.empty()) return false;

    std::ifstream stream( path.c_str() );
    if( !stream.good()) return false;

    // Load the file to a string using an efficient memory allocation technique
    stream.seekg(0, std::ios::end);
    buffer.reserve(stream.tellg());
    stream.seekg(0, std::ios::beg);
    buffer.assign( (std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>() );
    stream.close();

    return true;
}

bool loadXacroFileToString(std::string& buffer, const std::string& path, const std::vector<std::string> &xacro_args){
    if(path.empty()) return false;

    std::string cmd = "rosrun xacro xacro ";
    for(std::vector<std::string>::const_iterator it = xacro_args.begin(); it != xacro_args.end(); ++it)
        cmd += *it + " ";
    cmd += path;

    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) return false;

    char pipe_buffer[128];
    while(!feof(pipe)){
        if(fgets(pipe_buffer, 128, pipe) != NULL)
                buffer += pipe_buffer;
    }
    pclose(pipe);

    return true;
}

bool loadXmlFileToString(std::string& buffer, const std::string& path, const std::vector<std::string> &xacro_args){
    if(isXacroFile(path)){
        return loadXacroFileToString(buffer, path, xacro_args);
    }else{
        return loadFileToString(buffer, path);
    }
}

class SortableDisabledCollision {
     const srdf::Model::DisabledCollision dc_;
     const std::string key_;
public:
    SortableDisabledCollision(const srdf::Model::DisabledCollision &dc)
    : dc_(dc), key_(dc.link1_ < dc.link2_ ? (dc.link1_ + "|" + dc.link2_) : (dc.link2_ + "|" + dc.link1_)) {}
    operator const srdf::Model::DisabledCollision () const { return dc_; }
    bool operator < (const SortableDisabledCollision &other) const { return key_ < other.key_; }
};

class CollisionUpdater{
    moveit_setup_assistant::MoveItConfigData config_data;
public:
    bool loadSetupAssistantConfig(const std::string &path){
        config_data.config_pkg_path_ = path;

        fs::path setup_assistant_file = config_data.config_pkg_path_;
        setup_assistant_file /= ".setup_assistant";

        if(!config_data.inputSetupAssistantYAML( setup_assistant_file.make_preferred().native().c_str() ) )
            return false;

        fs::path urdf_path;

        if( config_data.urdf_pkg_name_.empty() || config_data.urdf_pkg_name_ == "\"\"" ){
            urdf_path = config_data.urdf_pkg_relative_path_;
        }else{
            fs::path robot_desc_pkg_path = ros::package::getPath( config_data.urdf_pkg_name_ );
            if( robot_desc_pkg_path.empty() ) return false;

            urdf_path = robot_desc_pkg_path / config_data.urdf_pkg_relative_path_;
        }
        config_data.urdf_path_ = urdf_path.make_preferred().native();

        fs::path srdf_path = config_data.config_pkg_path_ ;
        srdf_path /= config_data.srdf_pkg_relative_path_;
        config_data.srdf_path_ = srdf_path.make_preferred().native();

        return true;
    }

    void setURDF(const std::string &path) {
        if(!path.empty()) config_data.urdf_path_ = path;
    }
    void setSRDF(const std::string &path) {
        if(!path.empty()) config_data.srdf_path_ = path;
    }

    bool setup(bool keep_old, const std::vector<std::string> &xacro_args){
        std::string urdf_string;
        if(!loadXmlFileToString(urdf_string, config_data.urdf_path_, xacro_args)) return false;
        if(!config_data.urdf_model_->initString( urdf_string))return false;

        std::string srdf_string;
        if(!loadXmlFileToString(srdf_string, config_data.srdf_path_, xacro_args)) return false;
        if(!config_data.srdf_->initString( *config_data.urdf_model_, srdf_string)) return false;

        if(!keep_old) config_data.srdf_->disabled_collisions_.clear();

        return true;
    }

    moveit_setup_assistant::LinkPairMap compute(uint32_t trials, double min_collision_fraction,  bool verbose){
        unsigned int collision_progress;
        return moveit_setup_assistant::computeDefaultCollisions(config_data.getPlanningScene(),
                                                                &collision_progress,
                                                                trials > 0,
                                                                trials,
                                                                min_collision_fraction, verbose);
    }

    void write(const moveit_setup_assistant::LinkPairMap &link_pairs, bool include_default, bool include_always, const std::string &output_path){
        // Create temp disabled collision
        srdf::Model::DisabledCollision dc;

        std::set<SortableDisabledCollision> disabled_collisions;
        disabled_collisions.insert(config_data.srdf_->disabled_collisions_.begin(), config_data.srdf_->disabled_collisions_.end());

        // copy the data in this class's LinkPairMap datastructure to srdf::Model::DisabledCollision format
        for ( moveit_setup_assistant::LinkPairMap::const_iterator pair_it = link_pairs.begin();
                pair_it != link_pairs.end(); ++pair_it)
        {
            // Only copy those that are actually disabled
            if( pair_it->second.disable_check ){
                if( pair_it->second.reason == moveit_setup_assistant::DEFAULT && !include_default) continue;
                if( pair_it->second.reason == moveit_setup_assistant::ALWAYS && !include_always) continue;
                dc.link1_ = pair_it->first.first;
                dc.link2_ = pair_it->first.second;
                dc.reason_ = moveit_setup_assistant::disabledReasonToString( pair_it->second.reason );
                disabled_collisions.insert(SortableDisabledCollision(dc));
            }
        }

        config_data.srdf_->disabled_collisions_.assign(disabled_collisions.begin(), disabled_collisions.end());

        // Update collision_matrix for robot pose's use
        config_data.loadAllowedCollisionMatrix();

        config_data.srdf_->writeSRDF(output_path.empty() ? config_data.srdf_path_ : output_path );

    }

};

int main(int argc, char * argv[]){

    std::string config_pkg_path;
    std::string urdf_path;
    std::string srdf_path;

    std::string output_path;

    bool include_default = false, include_always = false, keep_old = false, verbose = false;

    double min_collision_fraction = 1.0;

    uint32_t never_trials = 0;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "show help")
        ("config-pkg", po::value(&config_pkg_path), "path to moveit config package")
        ("urdf", po::value(&urdf_path), "path to URDF ( or xacro)")
        ("srdf", po::value(&srdf_path), "path to SRDF ( or xacro)")
        ("output", po::value(&output_path), "output path for SRDF")

        ("xacro-args", po::value<std::vector<std::string> >()->composing(), "additional arguments for xacro")

        ("default", po::bool_switch(&include_default),  "disable default colliding pairs")
        ("always", po::bool_switch(&include_always),  "disable always colliding pairs")

        ("keep", po::bool_switch(&keep_old),  "keep disabled link from SRDF")
        ("verbose", po::bool_switch(&verbose),  "verbose output")

        ("trials", po::value(&never_trials),  "number of trials for searching never colliding pairs")
        ("min-collision-fraction", po::value(&min_collision_fraction),  "fraction of small sample size to determine links that are alwas colliding")
      ;

    po::positional_options_description pos_desc;
    pos_desc.add("xacro-args", -1);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pos_desc).run(), vm);
    po::notify(vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 1;
    }

    CollisionUpdater updater;

    if(!config_pkg_path.empty()){
        if(!updater.loadSetupAssistantConfig(config_pkg_path)){
            std::cerr << "Could not load config at '" << config_pkg_path << "'" << std::endl;
            return 1;
        }
    }else if (urdf_path.empty() || srdf_path.empty()){
            std::cerr << "Please provide config package or URDF and SRDF path" << std::endl;
            return 1;
    }

    updater.setURDF(urdf_path);
    updater.setSRDF(srdf_path);

    std::vector<std::string> xacro_args;
    if(vm.count("xacro-args")) xacro_args = vm["xacro-args"].as<std::vector<std::string> >();

    if(!updater.setup(keep_old, xacro_args)){
        std::cerr << "Could not setup updater" << std::endl;
        return 1;
    }

    moveit_setup_assistant::LinkPairMap link_pairs = updater.compute(never_trials, min_collision_fraction,verbose);

    updater.write(link_pairs, include_default, include_always, output_path);

    return 0;
}
<commit_msg>require output path to be set if SRDF path is overwritten by a xacro file path<commit_after>#include <ros/ros.h>
#include <ros/package.h> // for getting file path for loadng images

#include <moveit/setup_assistant/tools/compute_default_collisions.h>
#include <moveit/setup_assistant/tools/moveit_config_data.h>

#include <boost/filesystem.hpp>  // for reading folders/files
#include <boost/program_options.hpp>
#include <boost/algorithm/string/join.hpp>

#include <fstream>  // for reading in urdf
#include <streambuf>

namespace fs = boost::filesystem;
namespace po = boost::program_options;

bool isXacroFile(const std::string& path) { return path.find(".xacro") != std::string::npos; } // TODO: implement case-insensitive search

bool loadFileToString(std::string& buffer, const std::string& path){
    if(path.empty()) return false;

    std::ifstream stream( path.c_str() );
    if( !stream.good()) return false;

    // Load the file to a string using an efficient memory allocation technique
    stream.seekg(0, std::ios::end);
    buffer.reserve(stream.tellg());
    stream.seekg(0, std::ios::beg);
    buffer.assign( (std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>() );
    stream.close();

    return true;
}

bool loadXacroFileToString(std::string& buffer, const std::string& path, const std::vector<std::string> &xacro_args){
    if(path.empty()) return false;

    std::string cmd = "rosrun xacro xacro ";
    for(std::vector<std::string>::const_iterator it = xacro_args.begin(); it != xacro_args.end(); ++it)
        cmd += *it + " ";
    cmd += path;

    FILE* pipe = popen(cmd.c_str(), "r");
    if (!pipe) return false;

    char pipe_buffer[128];
    while(!feof(pipe)){
        if(fgets(pipe_buffer, 128, pipe) != NULL)
                buffer += pipe_buffer;
    }
    pclose(pipe);

    return true;
}

bool loadXmlFileToString(std::string& buffer, const std::string& path, const std::vector<std::string> &xacro_args){
    if(isXacroFile(path)){
        return loadXacroFileToString(buffer, path, xacro_args);
    }else{
        return loadFileToString(buffer, path);
    }
}

class SortableDisabledCollision {
     const srdf::Model::DisabledCollision dc_;
     const std::string key_;
public:
    SortableDisabledCollision(const srdf::Model::DisabledCollision &dc)
    : dc_(dc), key_(dc.link1_ < dc.link2_ ? (dc.link1_ + "|" + dc.link2_) : (dc.link2_ + "|" + dc.link1_)) {}
    operator const srdf::Model::DisabledCollision () const { return dc_; }
    bool operator < (const SortableDisabledCollision &other) const { return key_ < other.key_; }
};

class CollisionUpdater{
    moveit_setup_assistant::MoveItConfigData config_data;
public:
    bool loadSetupAssistantConfig(const std::string &path){
        config_data.config_pkg_path_ = path;

        fs::path setup_assistant_file = config_data.config_pkg_path_;
        setup_assistant_file /= ".setup_assistant";

        if(!config_data.inputSetupAssistantYAML( setup_assistant_file.make_preferred().native().c_str() ) )
            return false;

        fs::path urdf_path;

        if( config_data.urdf_pkg_name_.empty() || config_data.urdf_pkg_name_ == "\"\"" ){
            urdf_path = config_data.urdf_pkg_relative_path_;
        }else{
            fs::path robot_desc_pkg_path = ros::package::getPath( config_data.urdf_pkg_name_ );
            if( robot_desc_pkg_path.empty() ) return false;

            urdf_path = robot_desc_pkg_path / config_data.urdf_pkg_relative_path_;
        }
        config_data.urdf_path_ = urdf_path.make_preferred().native();

        fs::path srdf_path = config_data.config_pkg_path_ ;
        srdf_path /= config_data.srdf_pkg_relative_path_;
        config_data.srdf_path_ = srdf_path.make_preferred().native();

        return true;
    }

    void setURDF(const std::string &path) {
        if(!path.empty()) config_data.urdf_path_ = path;
    }
    void setSRDF(const std::string &path) {
        if(!path.empty()) config_data.srdf_path_ = path;
    }

    bool setup(bool keep_old, const std::vector<std::string> &xacro_args){
        std::string urdf_string;
        if(!loadXmlFileToString(urdf_string, config_data.urdf_path_, xacro_args)) return false;
        if(!config_data.urdf_model_->initString( urdf_string))return false;

        std::string srdf_string;
        if(!loadXmlFileToString(srdf_string, config_data.srdf_path_, xacro_args)) return false;
        if(!config_data.srdf_->initString( *config_data.urdf_model_, srdf_string)) return false;

        if(!keep_old) config_data.srdf_->disabled_collisions_.clear();

        return true;
    }

    moveit_setup_assistant::LinkPairMap compute(uint32_t trials, double min_collision_fraction,  bool verbose){
        unsigned int collision_progress;
        return moveit_setup_assistant::computeDefaultCollisions(config_data.getPlanningScene(),
                                                                &collision_progress,
                                                                trials > 0,
                                                                trials,
                                                                min_collision_fraction, verbose);
    }

    void write(const moveit_setup_assistant::LinkPairMap &link_pairs, bool include_default, bool include_always, const std::string &output_path){
        // Create temp disabled collision
        srdf::Model::DisabledCollision dc;

        std::set<SortableDisabledCollision> disabled_collisions;
        disabled_collisions.insert(config_data.srdf_->disabled_collisions_.begin(), config_data.srdf_->disabled_collisions_.end());

        // copy the data in this class's LinkPairMap datastructure to srdf::Model::DisabledCollision format
        for ( moveit_setup_assistant::LinkPairMap::const_iterator pair_it = link_pairs.begin();
                pair_it != link_pairs.end(); ++pair_it)
        {
            // Only copy those that are actually disabled
            if( pair_it->second.disable_check ){
                if( pair_it->second.reason == moveit_setup_assistant::DEFAULT && !include_default) continue;
                if( pair_it->second.reason == moveit_setup_assistant::ALWAYS && !include_always) continue;
                dc.link1_ = pair_it->first.first;
                dc.link2_ = pair_it->first.second;
                dc.reason_ = moveit_setup_assistant::disabledReasonToString( pair_it->second.reason );
                disabled_collisions.insert(SortableDisabledCollision(dc));
            }
        }

        config_data.srdf_->disabled_collisions_.assign(disabled_collisions.begin(), disabled_collisions.end());

        // Update collision_matrix for robot pose's use
        config_data.loadAllowedCollisionMatrix();

        config_data.srdf_->writeSRDF(output_path.empty() ? config_data.srdf_path_ : output_path );

    }

};

int main(int argc, char * argv[]){

    std::string config_pkg_path;
    std::string urdf_path;
    std::string srdf_path;

    std::string output_path;

    bool include_default = false, include_always = false, keep_old = false, verbose = false;

    double min_collision_fraction = 1.0;

    uint32_t never_trials = 0;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "show help")
        ("config-pkg", po::value(&config_pkg_path), "path to moveit config package")
        ("urdf", po::value(&urdf_path), "path to URDF ( or xacro)")
        ("srdf", po::value(&srdf_path), "path to SRDF ( or xacro)")
        ("output", po::value(&output_path), "output path for SRDF")

        ("xacro-args", po::value<std::vector<std::string> >()->composing(), "additional arguments for xacro")

        ("default", po::bool_switch(&include_default),  "disable default colliding pairs")
        ("always", po::bool_switch(&include_always),  "disable always colliding pairs")

        ("keep", po::bool_switch(&keep_old),  "keep disabled link from SRDF")
        ("verbose", po::bool_switch(&verbose),  "verbose output")

        ("trials", po::value(&never_trials),  "number of trials for searching never colliding pairs")
        ("min-collision-fraction", po::value(&min_collision_fraction),  "fraction of small sample size to determine links that are alwas colliding")
      ;

    po::positional_options_description pos_desc;
    pos_desc.add("xacro-args", -1);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pos_desc).run(), vm);
    po::notify(vm);

    if (vm.count("help")) {
        std::cout << desc << std::endl;
        return 1;
    }

    CollisionUpdater updater;

    if(!config_pkg_path.empty()){
        if(!updater.loadSetupAssistantConfig(config_pkg_path)){
            std::cerr << "Could not load config at '" << config_pkg_path << "'" << std::endl;
            return 1;
        }
    }else if (urdf_path.empty() || srdf_path.empty()){
        std::cerr << "Please provide config package or URDF and SRDF path" << std::endl;
        return 1;
    }else if(isXacroFile(srdf_path) && output_path.empty()){
        std::cerr << "Please provide a different output file for SRDF xacro input file" << std::endl;
        return 1;
    }

    updater.setURDF(urdf_path);
    updater.setSRDF(srdf_path);

    std::vector<std::string> xacro_args;
    if(vm.count("xacro-args")) xacro_args = vm["xacro-args"].as<std::vector<std::string> >();

    if(!updater.setup(keep_old, xacro_args)){
        std::cerr << "Could not setup updater" << std::endl;
        return 1;
    }

    moveit_setup_assistant::LinkPairMap link_pairs = updater.compute(never_trials, min_collision_fraction,verbose);

    updater.write(link_pairs, include_default, include_always, output_path);

    return 0;
}
<|endoftext|>