<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local Includes
#include "libmesh/mesh_function.h"
#include "libmesh/dense_vector.h"
#include "libmesh/equation_systems.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/dof_map.h"
#include "libmesh/point_locator_tree.h"
#include "libmesh/fe_base.h"
#include "libmesh/fe_interface.h"
#include "libmesh/fe_compute_data.h"
#include "libmesh/mesh_base.h"
#include "libmesh/point.h"

namespace libMesh
{

//------------------------------------------------------------------
// MeshFunction methods
MeshFunction::MeshFunction (const EquationSystems& eqn_systems,
			    const NumericVector<Number>& vec,
			    const DofMap& dof_map,
			    const std::vector<unsigned int>& vars,
			    const FunctionBase<Number>* master) :
  FunctionBase<Number> (master),
  _eqn_systems         (eqn_systems),
  _vector              (vec),
  _dof_map             (dof_map),
  _system_vars         (vars),
  _point_locator       (NULL),
  _out_of_mesh_mode    (false),
  _out_of_mesh_value   ()
{
}

MeshFunction::MeshFunction (const EquationSystems& eqn_systems,
			    const NumericVector<Number>& vec,
			    const DofMap& dof_map,
			    const unsigned int var,
			    const FunctionBase<Number>* master) :
  FunctionBase<Number> (master),
  _eqn_systems         (eqn_systems),
  _vector              (vec),
  _dof_map             (dof_map),
  _system_vars         (1,var),
  _point_locator       (NULL),
  _out_of_mesh_mode    (false),
  _out_of_mesh_value   ()
{
//   std::vector<unsigned int> buf (1);
//   buf[0] = var;
//   _system_vars (buf);
}

MeshFunction::~MeshFunction ()
{
  // only delete the point locator when we are the master
  if ((this->_point_locator != NULL) && (this->_master == NULL))
    delete this->_point_locator;
}

void MeshFunction::init (const Trees::BuildType /*point_locator_build_type*/)
{
  // are indices of the desired variable(s) provided?
  libmesh_assert_greater (this->_system_vars.size(), 0);

  // Don't do twice...
  if (this->_initialized)
    {
      libmesh_assert(this->_point_locator);
      return;
    }

  /*
   * set up the PointLocator: either someone else
   * is the master (go and get the address of his
   * point locator) or this object is the master
   * (build the point locator  on our own).
   */
  if (this->_master != NULL)
    {
      // we aren't the master
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);

      if (master->_point_locator == NULL)
        {
	  libMesh::err << "ERROR: When the master-servant concept is used,"
		        << std::endl
		        << " the master has to be initialized first!"
		        << std::endl;
	  libmesh_error();
	}
      else
        {
	  this->_point_locator = master->_point_locator;
	}
    }
  else
    {
      // we are the master: build the point locator

      // constant reference to the other mesh
      const MeshBase& mesh = this->_eqn_systems.get_mesh();

      // build the point locator.  Only \p TREE version available
      //AutoPtr<PointLocatorBase> ap (PointLocatorBase::build (TREE, mesh));
      //this->_point_locator = ap.release();
      // this->_point_locator = new PointLocatorTree (mesh, point_locator_build_type);
       this->_point_locator = mesh.sub_point_locator().release();

      // Point locator no longer needs to be initialized.
      //      this->_point_locator->init();
    }

  // ready for use
  this->_initialized = true;
}

void
MeshFunction::clear ()
{
  // only delete the point locator when we are the master
  if ((this->_point_locator != NULL) && (this->_master == NULL))
    {
      delete this->_point_locator;
      this->_point_locator = NULL;
    }
  this->_initialized = false;
}

AutoPtr<FunctionBase<Number> > MeshFunction::clone () const
{
  return AutoPtr<FunctionBase<Number> >
    (new MeshFunction
      (_eqn_systems, _vector, _dof_map, _system_vars, this));
}

Number MeshFunction::operator() (const Point& p,
				 const Real time)
{
  libmesh_assert (this->initialized());
  // At the moment the function we call ignores the time
  libmesh_assert_equal_to (time, 0.);

  DenseVector<Number> buf (1);
  this->operator() (p, time, buf);
  return buf(0);
}

Gradient MeshFunction::gradient (const Point& p,
				 const Real time)
{
  libmesh_assert (this->initialized());
  // At the moment the function we call ignores the time
  libmesh_assert_equal_to (time, 0.);

  std::vector<Gradient> buf (1);
  this->gradient(p, time, buf);
  return buf[0];
}

#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
Tensor MeshFunction::hessian (const Point& p,
			      const Real time)
{
  libmesh_assert (this->initialized());
  // At the moment the function we call ignores the time
  libmesh_assert_equal_to (time, 0.);

  std::vector<Tensor> buf (1);
  this->hessian(p, time, buf);
  return buf[0];
}
#endif

void MeshFunction::operator() (const Point& p,
			       const Real,
			       DenseVector<Number>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output = _out_of_mesh_value;
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

	    /**
	     * Build an FEComputeData that contains both input and output data
	     * for the specific compute_data method.
	     */
	    {
	      FEComputeData data (this->_eqn_systems, mapped_point);

	      FEInterface::compute_data (dim, fe_type, element, data);

	      // where the solution values for the var-th variable are stored
	      std::vector<unsigned int> dof_indices;
	      this->_dof_map.dof_indices (element, dof_indices, var);

	      // interpolate the solution
	      {
		Number value = 0.;

		for (unsigned int i=0; i<dof_indices.size(); i++)
		  value += this->_vector(dof_indices[i]) * data.shape[i];

		output(index) = value;
	      }

	    }

	    // next variable
	  }
      }
    }

  // all done
  return;
}

void MeshFunction::gradient (const Point& p,
			     const Real,
			     std::vector<Gradient>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output.resize(0);
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

        std::vector<Point> point_list (1, mapped_point);

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

            AutoPtr<FEBase> point_fe (FEBase::build(dim, fe_type));
            const std::vector<std::vector<RealGradient> >& dphi = point_fe->get_dphi();
            point_fe->reinit(element, &point_list);

	    // where the solution values for the var-th variable are stored
	    std::vector<unsigned int> dof_indices;
	    this->_dof_map.dof_indices (element, dof_indices, var);

	    // interpolate the solution
	    Gradient grad(0.);

	    for (unsigned int i=0; i<dof_indices.size(); i++)
	      grad.add_scaled(dphi[i][0], this->_vector(dof_indices[i]));

	    output[index] = grad;
	  }
      }
    }

  // all done
  return;
}

#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
void MeshFunction::hessian (const Point& p,
			    const Real,
			    std::vector<Tensor>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output.resize(0);
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

        std::vector<Point> point_list (1, mapped_point);

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

            AutoPtr<FEBase> point_fe (FEBase::build(dim, fe_type));
            const std::vector<std::vector<RealTensor> >& d2phi =
			    point_fe->get_d2phi();
            point_fe->reinit(element, &point_list);

	    // where the solution values for the var-th variable are stored
	    std::vector<unsigned int> dof_indices;
	    this->_dof_map.dof_indices (element, dof_indices, var);

	    // interpolate the solution
	    Tensor hess;

	    for (unsigned int i=0; i<dof_indices.size(); i++)
	      hess.add_scaled(d2phi[i][0], this->_vector(dof_indices[i]));

	    output[index] = hess;
	  }
      }
    }

  // all done
  return;
}
#endif

const PointLocatorBase& MeshFunction::get_point_locator (void) const
{
  libmesh_assert (this->initialized());
  return *_point_locator;
}

void MeshFunction::enable_out_of_mesh_mode(const DenseVector<Number>& value)
{
  libmesh_assert (this->initialized());
  _point_locator->enable_out_of_mesh_mode();
  _out_of_mesh_mode = true;
  _out_of_mesh_value = value;
}

void MeshFunction::enable_out_of_mesh_mode(const Number& value)
{
  DenseVector<Number> v(1);
  v(0) = value;
  this->enable_out_of_mesh_mode(v);
}

void MeshFunction::disable_out_of_mesh_mode(void)
{
  libmesh_assert (this->initialized());
  _point_locator->disable_out_of_mesh_mode();
  _out_of_mesh_mode = false;
}

} // namespace libMesh

<commit_msg>These solutions could be overzealous in the common "system1.time == system2.time" usage case<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes

// Local Includes
#include "libmesh/mesh_function.h"
#include "libmesh/dense_vector.h"
#include "libmesh/equation_systems.h"
#include "libmesh/numeric_vector.h"
#include "libmesh/dof_map.h"
#include "libmesh/point_locator_tree.h"
#include "libmesh/fe_base.h"
#include "libmesh/fe_interface.h"
#include "libmesh/fe_compute_data.h"
#include "libmesh/mesh_base.h"
#include "libmesh/point.h"

namespace libMesh
{

//------------------------------------------------------------------
// MeshFunction methods
MeshFunction::MeshFunction (const EquationSystems& eqn_systems,
			    const NumericVector<Number>& vec,
			    const DofMap& dof_map,
			    const std::vector<unsigned int>& vars,
			    const FunctionBase<Number>* master) :
  FunctionBase<Number> (master),
  _eqn_systems         (eqn_systems),
  _vector              (vec),
  _dof_map             (dof_map),
  _system_vars         (vars),
  _point_locator       (NULL),
  _out_of_mesh_mode    (false),
  _out_of_mesh_value   ()
{
}

MeshFunction::MeshFunction (const EquationSystems& eqn_systems,
			    const NumericVector<Number>& vec,
			    const DofMap& dof_map,
			    const unsigned int var,
			    const FunctionBase<Number>* master) :
  FunctionBase<Number> (master),
  _eqn_systems         (eqn_systems),
  _vector              (vec),
  _dof_map             (dof_map),
  _system_vars         (1,var),
  _point_locator       (NULL),
  _out_of_mesh_mode    (false),
  _out_of_mesh_value   ()
{
//   std::vector<unsigned int> buf (1);
//   buf[0] = var;
//   _system_vars (buf);
}

MeshFunction::~MeshFunction ()
{
  // only delete the point locator when we are the master
  if ((this->_point_locator != NULL) && (this->_master == NULL))
    delete this->_point_locator;
}

void MeshFunction::init (const Trees::BuildType /*point_locator_build_type*/)
{
  // are indices of the desired variable(s) provided?
  libmesh_assert_greater (this->_system_vars.size(), 0);

  // Don't do twice...
  if (this->_initialized)
    {
      libmesh_assert(this->_point_locator);
      return;
    }

  /*
   * set up the PointLocator: either someone else
   * is the master (go and get the address of his
   * point locator) or this object is the master
   * (build the point locator  on our own).
   */
  if (this->_master != NULL)
    {
      // we aren't the master
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);

      if (master->_point_locator == NULL)
        {
	  libMesh::err << "ERROR: When the master-servant concept is used,"
		        << std::endl
		        << " the master has to be initialized first!"
		        << std::endl;
	  libmesh_error();
	}
      else
        {
	  this->_point_locator = master->_point_locator;
	}
    }
  else
    {
      // we are the master: build the point locator

      // constant reference to the other mesh
      const MeshBase& mesh = this->_eqn_systems.get_mesh();

      // build the point locator.  Only \p TREE version available
      //AutoPtr<PointLocatorBase> ap (PointLocatorBase::build (TREE, mesh));
      //this->_point_locator = ap.release();
      // this->_point_locator = new PointLocatorTree (mesh, point_locator_build_type);
       this->_point_locator = mesh.sub_point_locator().release();

      // Point locator no longer needs to be initialized.
      //      this->_point_locator->init();
    }

  // ready for use
  this->_initialized = true;
}

void
MeshFunction::clear ()
{
  // only delete the point locator when we are the master
  if ((this->_point_locator != NULL) && (this->_master == NULL))
    {
      delete this->_point_locator;
      this->_point_locator = NULL;
    }
  this->_initialized = false;
}

AutoPtr<FunctionBase<Number> > MeshFunction::clone () const
{
  return AutoPtr<FunctionBase<Number> >
    (new MeshFunction
      (_eqn_systems, _vector, _dof_map, _system_vars, this));
}

Number MeshFunction::operator() (const Point& p,
				 const Real time)
{
  libmesh_assert (this->initialized());

  DenseVector<Number> buf (1);
  this->operator() (p, time, buf);
  return buf(0);
}

Gradient MeshFunction::gradient (const Point& p,
				 const Real time)
{
  libmesh_assert (this->initialized());

  std::vector<Gradient> buf (1);
  this->gradient(p, time, buf);
  return buf[0];
}

#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
Tensor MeshFunction::hessian (const Point& p,
			      const Real time)
{
  libmesh_assert (this->initialized());

  std::vector<Tensor> buf (1);
  this->hessian(p, time, buf);
  return buf[0];
}
#endif

void MeshFunction::operator() (const Point& p,
			       const Real,
			       DenseVector<Number>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output = _out_of_mesh_value;
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

	    /**
	     * Build an FEComputeData that contains both input and output data
	     * for the specific compute_data method.
	     */
	    {
	      FEComputeData data (this->_eqn_systems, mapped_point);

	      FEInterface::compute_data (dim, fe_type, element, data);

	      // where the solution values for the var-th variable are stored
	      std::vector<unsigned int> dof_indices;
	      this->_dof_map.dof_indices (element, dof_indices, var);

	      // interpolate the solution
	      {
		Number value = 0.;

		for (unsigned int i=0; i<dof_indices.size(); i++)
		  value += this->_vector(dof_indices[i]) * data.shape[i];

		output(index) = value;
	      }

	    }

	    // next variable
	  }
      }
    }

  // all done
  return;
}

void MeshFunction::gradient (const Point& p,
			     const Real,
			     std::vector<Gradient>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output.resize(0);
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

        std::vector<Point> point_list (1, mapped_point);

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

            AutoPtr<FEBase> point_fe (FEBase::build(dim, fe_type));
            const std::vector<std::vector<RealGradient> >& dphi = point_fe->get_dphi();
            point_fe->reinit(element, &point_list);

	    // where the solution values for the var-th variable are stored
	    std::vector<unsigned int> dof_indices;
	    this->_dof_map.dof_indices (element, dof_indices, var);

	    // interpolate the solution
	    Gradient grad(0.);

	    for (unsigned int i=0; i<dof_indices.size(); i++)
	      grad.add_scaled(dphi[i][0], this->_vector(dof_indices[i]));

	    output[index] = grad;
	  }
      }
    }

  // all done
  return;
}

#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
void MeshFunction::hessian (const Point& p,
			    const Real,
			    std::vector<Tensor>& output)
{
  libmesh_assert (this->initialized());

  /* Ensure that in the case of a master mesh function, the
     out-of-mesh mode is enabled either for both or for none.  This is
     important because the out-of-mesh mode is also communicated to
     the point locator.  Since this is time consuming, enable it only
     in debug mode.  */
#ifdef DEBUG
  if (this->_master != NULL)
    {
      const MeshFunction* master =
	libmesh_cast_ptr<const MeshFunction*>(this->_master);
      if(_out_of_mesh_mode!=master->_out_of_mesh_mode)
	{
	  libMesh::err << "ERROR: If you use out-of-mesh-mode in connection with master mesh functions, you must enable out-of-mesh mode for both the master and the slave mesh function." << std::endl;
	  libmesh_error();
	}
    }
#endif

  // locate the point in the other mesh
  const Elem* element = this->_point_locator->operator()(p);

  if(element==NULL)
    {
      output.resize(0);
    }
  else
    {
      // resize the output vector to the number of output values
      // that the user told us
      output.resize (this->_system_vars.size());

      {
	const unsigned int dim = this->_eqn_systems.get_mesh().mesh_dimension();

	/*
	 * Get local coordinates to feed these into compute_data().
	 * Note that the fe_type can safely be used from the 0-variable,
	 * since the inverse mapping is the same for all FEFamilies
	 */
	const Point mapped_point (FEInterface::inverse_map (dim,
							    this->_dof_map.variable_type(0),
							    element,
							    p));

        std::vector<Point> point_list (1, mapped_point);

	// loop over all vars
	for (unsigned int index=0; index < this->_system_vars.size(); index++)
	  {
	    /*
	     * the data for this variable
	     */
	    const unsigned int var = _system_vars[index];
	    const FEType& fe_type = this->_dof_map.variable_type(var);

            AutoPtr<FEBase> point_fe (FEBase::build(dim, fe_type));
            const std::vector<std::vector<RealTensor> >& d2phi =
			    point_fe->get_d2phi();
            point_fe->reinit(element, &point_list);

	    // where the solution values for the var-th variable are stored
	    std::vector<unsigned int> dof_indices;
	    this->_dof_map.dof_indices (element, dof_indices, var);

	    // interpolate the solution
	    Tensor hess;

	    for (unsigned int i=0; i<dof_indices.size(); i++)
	      hess.add_scaled(d2phi[i][0], this->_vector(dof_indices[i]));

	    output[index] = hess;
	  }
      }
    }

  // all done
  return;
}
#endif

const PointLocatorBase& MeshFunction::get_point_locator (void) const
{
  libmesh_assert (this->initialized());
  return *_point_locator;
}

void MeshFunction::enable_out_of_mesh_mode(const DenseVector<Number>& value)
{
  libmesh_assert (this->initialized());
  _point_locator->enable_out_of_mesh_mode();
  _out_of_mesh_mode = true;
  _out_of_mesh_value = value;
}

void MeshFunction::enable_out_of_mesh_mode(const Number& value)
{
  DenseVector<Number> v(1);
  v(0) = value;
  this->enable_out_of_mesh_mode(v);
}

void MeshFunction::disable_out_of_mesh_mode(void)
{
  libmesh_assert (this->initialized());
  _point_locator->disable_out_of_mesh_mode();
  _out_of_mesh_mode = false;
}

} // namespace libMesh

<|endoftext|>


<commit_before>// Copyright 2014 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 "config.h"
#include "bindings/core/v8/ScriptStreamer.h"

#include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/PendingScript.h"
#include "core/fetch/ScriptResource.h"
#include "core/frame/Settings.h"
#include "platform/SharedBuffer.h"
#include "wtf/MainThread.h"
#include "wtf/text/TextEncodingRegistry.h"

namespace blink {

// For passing data between the main thread (producer) and the streamer thread
// (consumer). The main thread prepares the data (copies it from Resource) and
// the streamer thread feeds it to V8.
class SourceStreamDataQueue {
    WTF_MAKE_NONCOPYABLE(SourceStreamDataQueue);
public:
    SourceStreamDataQueue()
        : m_finished(false) { }

    ~SourceStreamDataQueue()
    {
        while (!m_data.isEmpty()) {
            std::pair<const uint8_t*, size_t> next_data = m_data.takeFirst();
            delete[] next_data.first;
        }
    }

    void produce(const uint8_t* data, size_t length)
    {
        MutexLocker locker(m_mutex);
        m_data.append(std::make_pair(data, length));
        m_haveData.signal();
    }

    void finish()
    {
        MutexLocker locker(m_mutex);
        m_finished = true;
        m_haveData.signal();
    }

    void consume(const uint8_t** data, size_t* length)
    {
        MutexLocker locker(m_mutex);
        while (!tryGetData(data, length))
            m_haveData.wait(m_mutex);
    }

private:
    bool tryGetData(const uint8_t** data, size_t* length)
    {
        if (!m_data.isEmpty()) {
            std::pair<const uint8_t*, size_t> next_data = m_data.takeFirst();
            *data = next_data.first;
            *length = next_data.second;
            return true;
        }
        if (m_finished) {
            *length = 0;
            return true;
        }
        return false;
    }

    WTF::Deque<std::pair<const uint8_t*, size_t> > m_data;
    bool m_finished;
    Mutex m_mutex;
    ThreadCondition m_haveData;
};

// SourceStream implements the streaming interface towards V8. The main
// functionality is preparing the data to give to V8 on main thread, and
// actually giving the data (via GetMoreData which is called on a background
// thread).
class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
    WTF_MAKE_NONCOPYABLE(SourceStream);
public:
    SourceStream(ScriptStreamer* streamer)
        : v8::ScriptCompiler::ExternalSourceStream()
        , m_streamer(streamer)
        , m_cancelled(false)
        , m_dataPosition(0) { }

    virtual ~SourceStream() { }

    // Called by V8 on a background thread. Should block until we can return
    // some data.
    virtual size_t GetMoreData(const uint8_t** src) OVERRIDE
    {
        ASSERT(!isMainThread());
        {
            MutexLocker locker(m_mutex);
            if (m_cancelled)
                return 0;
        }
        size_t length = 0;
        // This will wait until there is data.
        m_dataQueue.consume(src, &length);
        {
            MutexLocker locker(m_mutex);
            if (m_cancelled)
                return 0;
        }
        return length;
    }

    void didFinishLoading()
    {
        ASSERT(isMainThread());
        m_dataQueue.finish();
    }

    void didReceiveData()
    {
        ASSERT(isMainThread());
        prepareDataOnMainThread();
    }

    void cancel()
    {
        ASSERT(isMainThread());
        // The script is no longer needed by the upper layers. Stop streaming
        // it. The next time GetMoreData is called (or woken up), it will return
        // 0, which will be interpreted as EOS by V8 and the parsing will
        // fail. ScriptStreamer::streamingComplete will be called, and at that
        // point we will release the references to SourceStream.
        {
            MutexLocker locker(m_mutex);
            m_cancelled = true;
        }
        m_dataQueue.finish();
    }

private:
    void prepareDataOnMainThread()
    {
        ASSERT(isMainThread());
        // The Resource must still be alive; otherwise we should've cancelled
        // the streaming (if we have cancelled, the background thread is not
        // waiting).
        ASSERT(m_streamer->resource());

        if (m_streamer->resource()->cachedMetadata(V8ScriptRunner::tagForCodeCache())) {
            // The resource has a code cache, so it's unnecessary to stream and
            // parse the code. Cancel the streaming and resume the non-streaming
            // code path.
            m_streamer->suppressStreaming();
            {
                MutexLocker locker(m_mutex);
                m_cancelled = true;
            }
            m_dataQueue.finish();
            return;
        }

        if (!m_resourceBuffer) {
            // We don't have a buffer yet. Try to get it from the resource.
            SharedBuffer* buffer = m_streamer->resource()->resourceBuffer();
            if (!buffer)
                return;
            m_resourceBuffer = RefPtr<SharedBuffer>(buffer);
        }

        // Get as much data from the ResourceBuffer as we can.
        const char* data = 0;
        Vector<const char*> chunks;
        Vector<unsigned> chunkLengths;
        size_t dataLength = 0;
        while (unsigned length = m_resourceBuffer->getSomeData(data, m_dataPosition)) {
            // FIXME: Here we can limit based on the total length, if it turns
            // out that we don't want to give all the data we have (memory
            // vs. speed).
            chunks.append(data);
            chunkLengths.append(length);
            dataLength += length;
            m_dataPosition += length;
        }
        // Copy the data chunks into a new buffer, since we're going to give the
        // data to a background thread.
        if (dataLength > 0) {
            uint8_t* copiedData = new uint8_t[dataLength];
            unsigned offset = 0;
            for (size_t i = 0; i < chunks.size(); ++i) {
                memcpy(copiedData + offset, chunks[i], chunkLengths[i]);
                offset += chunkLengths[i];
            }
            m_dataQueue.produce(copiedData, dataLength);
        }
    }

    ScriptStreamer* m_streamer;

    // For coordinating between the main thread and background thread tasks.
    // Guarded by m_mutex.
    bool m_cancelled;
    Mutex m_mutex;

    unsigned m_dataPosition; // Only used by the main thread.
    RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread.
    SourceStreamDataQueue m_dataQueue; // Thread safe.
};

size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024;

bool ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, ScriptState* scriptState)
{
    ASSERT(isMainThread());
    if (!settings || !settings->v8ScriptStreamingEnabled())
        return false;
    ScriptResource* resource = script.resource();
    ASSERT(!resource->isLoaded());
    if (!resource->url().protocolIsInHTTPFamily())
        return false;
    if (resource->resourceToRevalidate()) {
        // This happens e.g., during reloads. We're actually not going to load
        // the current Resource of the PendingScript but switch to another
        // Resource -> don't stream.
        return false;
    }
    // We cannot filter out short scripts, even if we wait for the HTTP headers
    // to arrive. In general, the web servers don't seem to send the
    // Content-Length HTTP header for scripts.

    WTF::TextEncoding textEncoding(resource->encoding());
    const char* encodingName = textEncoding.name();

    // Here's a list of encodings we can use for streaming. These are
    // the canonical names.
    v8::ScriptCompiler::StreamedSource::Encoding encoding;
    if (strcmp(encodingName, "windows-1252") == 0
        || strcmp(encodingName, "ISO-8859-1") == 0
        || strcmp(encodingName, "US-ASCII") == 0) {
        encoding = v8::ScriptCompiler::StreamedSource::ONE_BYTE;
    } else if (strcmp(encodingName, "UTF-8") == 0) {
        encoding = v8::ScriptCompiler::StreamedSource::UTF8;
    } else {
        // We don't stream other encodings; especially we don't stream two byte
        // scripts to avoid the handling of byte order marks. Most scripts are
        // Latin1 or UTF-8 anyway, so this should be enough for most real world
        // purposes.
        return false;
    }

    if (scriptState->contextIsValid())
        return false;
    ScriptState::Scope scope(scriptState);

    // The Resource might go out of scope if the script is no longer needed. We
    // will soon call PendingScript::setStreamer, which makes the PendingScript
    // notify the ScriptStreamer when it is destroyed.
    RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, encoding));

    // Decide what kind of cached data we should produce while streaming. By
    // default, we generate the parser cache for streamed scripts, to emulate
    // the non-streaming behavior (see V8ScriptRunner::compileScript).
    v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProduceParserCache;
    if (settings->v8CacheOptions() == V8CacheOptionsCode)
        compileOption = v8::ScriptCompiler::kProduceCodeCache;
    v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCompiler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compileOption);
    if (scriptStreamingTask) {
        streamer->m_task = scriptStreamingTask;
        // ScriptStreamer needs to stay alive as long as the background task is
        // running. This is taken care of with a manual ref() & deref() pair;
        // the corresponding deref() is in streamingComplete.
        streamer->ref();
        script.setStreamer(streamer.release());
        return true;
    }
    // Otherwise, V8 cannot stream the script.
    return false;
}

void ScriptStreamer::streamingComplete()
{
    ASSERT(isMainThread());
    // It's possible that the corresponding Resource was deleted before V8
    // finished streaming. In that case, the data or the notification is not
    // needed. In addition, if the streaming is suppressed, the non-streaming
    // code path will resume after the resource has loaded, before the
    // background task finishes.
    if (m_detached || m_streamingSuppressed) {
        deref();
        return;
    }

    // We have now streamed the whole script to V8 and it has parsed the
    // script. We're ready for the next step: compiling and executing the
    // script.
    m_parsingFinished = true;

    notifyFinishedToClient();

    // The background thread no longer holds an implicit reference.
    deref();
}

void ScriptStreamer::cancel()
{
    ASSERT(isMainThread());
    // The upper layer doesn't need the script any more, but streaming might
    // still be ongoing. Tell SourceStream to try to cancel it whenever it gets
    // the control the next time. It can also be that V8 has already completed
    // its operations and streamingComplete will be called soon.
    m_detached = true;
    m_resource = 0;
    m_stream->cancel();
}

void ScriptStreamer::suppressStreaming()
{
    ASSERT(!m_parsingFinished);
    ASSERT(!m_loadingFinished);
    m_streamingSuppressed = true;
}

void ScriptStreamer::notifyAppendData(ScriptResource* resource)
{
    ASSERT(isMainThread());
    ASSERT(m_resource == resource);
    if (m_streamingSuppressed)
        return;
    if (!m_firstDataChunkReceived) {
        m_firstDataChunkReceived = true;
        // Check the size of the first data chunk. The expectation is that if
        // the first chunk is small, there won't be a second one. In those
        // cases, it doesn't make sense to stream at all.
        if (resource->resourceBuffer()->size() < kSmallScriptThreshold) {
            suppressStreaming();
            return;
        }
        if (ScriptStreamerThread::shared()->isRunningTask()) {
            // At the moment we only have one thread for running the tasks. A
            // new task shouldn't be queued before the running task completes,
            // because the running task can block and wait for data from the
            // network. At the moment we are only streaming parser blocking
            // scripts, but this code can still be hit when multiple frames are
            // loading simultaneously.
            suppressStreaming();
            return;
        }
        ScriptStreamingTask* task = new ScriptStreamingTask(m_task, this);
        ScriptStreamerThread::shared()->postTask(task);
        m_task = 0;
    }
    m_stream->didReceiveData();
}

void ScriptStreamer::notifyFinished(Resource* resource)
{
    ASSERT(isMainThread());
    ASSERT(m_resource == resource);
    // A special case: empty scripts. We didn't receive any data before this
    // notification. In that case, there won't be a "parsing complete"
    // notification either, and we should not wait for it.
    if (!m_firstDataChunkReceived)
        suppressStreaming();
    m_stream->didFinishLoading();
    m_loadingFinished = true;
    notifyFinishedToClient();
}

ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::StreamedSource::Encoding encoding)
    : m_resource(resource)
    , m_detached(false)
    , m_stream(new SourceStream(this))
    , m_source(m_stream, encoding) // m_source takes ownership of m_stream.
    , m_client(0)
    , m_task(0)
    , m_loadingFinished(false)
    , m_parsingFinished(false)
    , m_firstDataChunkReceived(false)
    , m_streamingSuppressed(false)
{
}

void ScriptStreamer::notifyFinishedToClient()
{
    ASSERT(isMainThread());
    // Usually, the loading will be finished first, and V8 will still need some
    // time to catch up. But the other way is possible too: if V8 detects a
    // parse error, the V8 side can complete before loading has finished. Send
    // the notification after both loading and V8 side operations have
    // completed. Here we also check that we have a client: it can happen that a
    // function calling notifyFinishedToClient was already scheduled in the task
    // queue and the upper layer decided that it's not interested in the script
    // and called removeClient.
    if (isFinished() && m_client)
        m_client->notifyFinished(m_resource);
}

} // namespace blink
<commit_msg>Script streaming fix: don't ref() ScriptStreamer too early.<commit_after>// Copyright 2014 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 "config.h"
#include "bindings/core/v8/ScriptStreamer.h"

#include "bindings/core/v8/ScriptStreamerThread.h"
#include "bindings/core/v8/V8ScriptRunner.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/PendingScript.h"
#include "core/fetch/ScriptResource.h"
#include "core/frame/Settings.h"
#include "platform/SharedBuffer.h"
#include "wtf/MainThread.h"
#include "wtf/text/TextEncodingRegistry.h"

namespace blink {

// For passing data between the main thread (producer) and the streamer thread
// (consumer). The main thread prepares the data (copies it from Resource) and
// the streamer thread feeds it to V8.
class SourceStreamDataQueue {
    WTF_MAKE_NONCOPYABLE(SourceStreamDataQueue);
public:
    SourceStreamDataQueue()
        : m_finished(false) { }

    ~SourceStreamDataQueue()
    {
        while (!m_data.isEmpty()) {
            std::pair<const uint8_t*, size_t> next_data = m_data.takeFirst();
            delete[] next_data.first;
        }
    }

    void produce(const uint8_t* data, size_t length)
    {
        MutexLocker locker(m_mutex);
        m_data.append(std::make_pair(data, length));
        m_haveData.signal();
    }

    void finish()
    {
        MutexLocker locker(m_mutex);
        m_finished = true;
        m_haveData.signal();
    }

    void consume(const uint8_t** data, size_t* length)
    {
        MutexLocker locker(m_mutex);
        while (!tryGetData(data, length))
            m_haveData.wait(m_mutex);
    }

private:
    bool tryGetData(const uint8_t** data, size_t* length)
    {
        if (!m_data.isEmpty()) {
            std::pair<const uint8_t*, size_t> next_data = m_data.takeFirst();
            *data = next_data.first;
            *length = next_data.second;
            return true;
        }
        if (m_finished) {
            *length = 0;
            return true;
        }
        return false;
    }

    WTF::Deque<std::pair<const uint8_t*, size_t> > m_data;
    bool m_finished;
    Mutex m_mutex;
    ThreadCondition m_haveData;
};

// SourceStream implements the streaming interface towards V8. The main
// functionality is preparing the data to give to V8 on main thread, and
// actually giving the data (via GetMoreData which is called on a background
// thread).
class SourceStream : public v8::ScriptCompiler::ExternalSourceStream {
    WTF_MAKE_NONCOPYABLE(SourceStream);
public:
    SourceStream(ScriptStreamer* streamer)
        : v8::ScriptCompiler::ExternalSourceStream()
        , m_streamer(streamer)
        , m_cancelled(false)
        , m_dataPosition(0) { }

    virtual ~SourceStream() { }

    // Called by V8 on a background thread. Should block until we can return
    // some data.
    virtual size_t GetMoreData(const uint8_t** src) OVERRIDE
    {
        ASSERT(!isMainThread());
        {
            MutexLocker locker(m_mutex);
            if (m_cancelled)
                return 0;
        }
        size_t length = 0;
        // This will wait until there is data.
        m_dataQueue.consume(src, &length);
        {
            MutexLocker locker(m_mutex);
            if (m_cancelled)
                return 0;
        }
        return length;
    }

    void didFinishLoading()
    {
        ASSERT(isMainThread());
        m_dataQueue.finish();
    }

    void didReceiveData()
    {
        ASSERT(isMainThread());
        prepareDataOnMainThread();
    }

    void cancel()
    {
        ASSERT(isMainThread());
        // The script is no longer needed by the upper layers. Stop streaming
        // it. The next time GetMoreData is called (or woken up), it will return
        // 0, which will be interpreted as EOS by V8 and the parsing will
        // fail. ScriptStreamer::streamingComplete will be called, and at that
        // point we will release the references to SourceStream.
        {
            MutexLocker locker(m_mutex);
            m_cancelled = true;
        }
        m_dataQueue.finish();
    }

private:
    void prepareDataOnMainThread()
    {
        ASSERT(isMainThread());
        // The Resource must still be alive; otherwise we should've cancelled
        // the streaming (if we have cancelled, the background thread is not
        // waiting).
        ASSERT(m_streamer->resource());

        if (m_streamer->resource()->cachedMetadata(V8ScriptRunner::tagForCodeCache())) {
            // The resource has a code cache, so it's unnecessary to stream and
            // parse the code. Cancel the streaming and resume the non-streaming
            // code path.
            m_streamer->suppressStreaming();
            {
                MutexLocker locker(m_mutex);
                m_cancelled = true;
            }
            m_dataQueue.finish();
            return;
        }

        if (!m_resourceBuffer) {
            // We don't have a buffer yet. Try to get it from the resource.
            SharedBuffer* buffer = m_streamer->resource()->resourceBuffer();
            if (!buffer)
                return;
            m_resourceBuffer = RefPtr<SharedBuffer>(buffer);
        }

        // Get as much data from the ResourceBuffer as we can.
        const char* data = 0;
        Vector<const char*> chunks;
        Vector<unsigned> chunkLengths;
        size_t dataLength = 0;
        while (unsigned length = m_resourceBuffer->getSomeData(data, m_dataPosition)) {
            // FIXME: Here we can limit based on the total length, if it turns
            // out that we don't want to give all the data we have (memory
            // vs. speed).
            chunks.append(data);
            chunkLengths.append(length);
            dataLength += length;
            m_dataPosition += length;
        }
        // Copy the data chunks into a new buffer, since we're going to give the
        // data to a background thread.
        if (dataLength > 0) {
            uint8_t* copiedData = new uint8_t[dataLength];
            unsigned offset = 0;
            for (size_t i = 0; i < chunks.size(); ++i) {
                memcpy(copiedData + offset, chunks[i], chunkLengths[i]);
                offset += chunkLengths[i];
            }
            m_dataQueue.produce(copiedData, dataLength);
        }
    }

    ScriptStreamer* m_streamer;

    // For coordinating between the main thread and background thread tasks.
    // Guarded by m_mutex.
    bool m_cancelled;
    Mutex m_mutex;

    unsigned m_dataPosition; // Only used by the main thread.
    RefPtr<SharedBuffer> m_resourceBuffer; // Only used by the main thread.
    SourceStreamDataQueue m_dataQueue; // Thread safe.
};

size_t ScriptStreamer::kSmallScriptThreshold = 30 * 1024;

bool ScriptStreamer::startStreaming(PendingScript& script, Settings* settings, ScriptState* scriptState)
{
    ASSERT(isMainThread());
    if (!settings || !settings->v8ScriptStreamingEnabled())
        return false;
    ScriptResource* resource = script.resource();
    ASSERT(!resource->isLoaded());
    if (!resource->url().protocolIsInHTTPFamily())
        return false;
    if (resource->resourceToRevalidate()) {
        // This happens e.g., during reloads. We're actually not going to load
        // the current Resource of the PendingScript but switch to another
        // Resource -> don't stream.
        return false;
    }
    // We cannot filter out short scripts, even if we wait for the HTTP headers
    // to arrive. In general, the web servers don't seem to send the
    // Content-Length HTTP header for scripts.

    WTF::TextEncoding textEncoding(resource->encoding());
    const char* encodingName = textEncoding.name();

    // Here's a list of encodings we can use for streaming. These are
    // the canonical names.
    v8::ScriptCompiler::StreamedSource::Encoding encoding;
    if (strcmp(encodingName, "windows-1252") == 0
        || strcmp(encodingName, "ISO-8859-1") == 0
        || strcmp(encodingName, "US-ASCII") == 0) {
        encoding = v8::ScriptCompiler::StreamedSource::ONE_BYTE;
    } else if (strcmp(encodingName, "UTF-8") == 0) {
        encoding = v8::ScriptCompiler::StreamedSource::UTF8;
    } else {
        // We don't stream other encodings; especially we don't stream two byte
        // scripts to avoid the handling of byte order marks. Most scripts are
        // Latin1 or UTF-8 anyway, so this should be enough for most real world
        // purposes.
        return false;
    }

    if (scriptState->contextIsValid())
        return false;
    ScriptState::Scope scope(scriptState);

    // The Resource might go out of scope if the script is no longer needed. We
    // will soon call PendingScript::setStreamer, which makes the PendingScript
    // notify the ScriptStreamer when it is destroyed.
    RefPtr<ScriptStreamer> streamer = adoptRef(new ScriptStreamer(resource, encoding));

    // Decide what kind of cached data we should produce while streaming. By
    // default, we generate the parser cache for streamed scripts, to emulate
    // the non-streaming behavior (see V8ScriptRunner::compileScript).
    v8::ScriptCompiler::CompileOptions compileOption = v8::ScriptCompiler::kProduceParserCache;
    if (settings->v8CacheOptions() == V8CacheOptionsCode)
        compileOption = v8::ScriptCompiler::kProduceCodeCache;
    v8::ScriptCompiler::ScriptStreamingTask* scriptStreamingTask = v8::ScriptCompiler::StartStreamingScript(scriptState->isolate(), &(streamer->m_source), compileOption);
    if (scriptStreamingTask) {
        streamer->m_task = scriptStreamingTask;
        script.setStreamer(streamer.release());
        return true;
    }
    // Otherwise, V8 cannot stream the script.
    return false;
}

void ScriptStreamer::streamingComplete()
{
    ASSERT(isMainThread());
    // It's possible that the corresponding Resource was deleted before V8
    // finished streaming. In that case, the data or the notification is not
    // needed. In addition, if the streaming is suppressed, the non-streaming
    // code path will resume after the resource has loaded, before the
    // background task finishes.
    if (m_detached || m_streamingSuppressed) {
        deref();
        return;
    }

    // We have now streamed the whole script to V8 and it has parsed the
    // script. We're ready for the next step: compiling and executing the
    // script.
    m_parsingFinished = true;

    notifyFinishedToClient();

    // The background thread no longer holds an implicit reference.
    deref();
}

void ScriptStreamer::cancel()
{
    ASSERT(isMainThread());
    // The upper layer doesn't need the script any more, but streaming might
    // still be ongoing. Tell SourceStream to try to cancel it whenever it gets
    // the control the next time. It can also be that V8 has already completed
    // its operations and streamingComplete will be called soon.
    m_detached = true;
    m_resource = 0;
    m_stream->cancel();
}

void ScriptStreamer::suppressStreaming()
{
    ASSERT(!m_parsingFinished);
    ASSERT(!m_loadingFinished);
    m_streamingSuppressed = true;
}

void ScriptStreamer::notifyAppendData(ScriptResource* resource)
{
    ASSERT(isMainThread());
    ASSERT(m_resource == resource);
    if (m_streamingSuppressed)
        return;
    if (!m_firstDataChunkReceived) {
        m_firstDataChunkReceived = true;
        // Check the size of the first data chunk. The expectation is that if
        // the first chunk is small, there won't be a second one. In those
        // cases, it doesn't make sense to stream at all.
        if (resource->resourceBuffer()->size() < kSmallScriptThreshold) {
            suppressStreaming();
            return;
        }
        if (ScriptStreamerThread::shared()->isRunningTask()) {
            // At the moment we only have one thread for running the tasks. A
            // new task shouldn't be queued before the running task completes,
            // because the running task can block and wait for data from the
            // network. At the moment we are only streaming parser blocking
            // scripts, but this code can still be hit when multiple frames are
            // loading simultaneously.
            suppressStreaming();
            return;
        }
        ASSERT(m_task);
        // ScriptStreamer needs to stay alive as long as the background task is
        // running. This is taken care of with a manual ref() & deref() pair;
        // the corresponding deref() is in streamingComplete.
        ref();
        ScriptStreamingTask* task = new ScriptStreamingTask(m_task, this);
        ScriptStreamerThread::shared()->postTask(task);
        m_task = 0;
    }
    m_stream->didReceiveData();
}

void ScriptStreamer::notifyFinished(Resource* resource)
{
    ASSERT(isMainThread());
    ASSERT(m_resource == resource);
    // A special case: empty scripts. We didn't receive any data before this
    // notification. In that case, there won't be a "parsing complete"
    // notification either, and we should not wait for it.
    if (!m_firstDataChunkReceived)
        suppressStreaming();
    m_stream->didFinishLoading();
    m_loadingFinished = true;
    notifyFinishedToClient();
}

ScriptStreamer::ScriptStreamer(ScriptResource* resource, v8::ScriptCompiler::StreamedSource::Encoding encoding)
    : m_resource(resource)
    , m_detached(false)
    , m_stream(new SourceStream(this))
    , m_source(m_stream, encoding) // m_source takes ownership of m_stream.
    , m_client(0)
    , m_task(0)
    , m_loadingFinished(false)
    , m_parsingFinished(false)
    , m_firstDataChunkReceived(false)
    , m_streamingSuppressed(false)
{
}

void ScriptStreamer::notifyFinishedToClient()
{
    ASSERT(isMainThread());
    // Usually, the loading will be finished first, and V8 will still need some
    // time to catch up. But the other way is possible too: if V8 detects a
    // parse error, the V8 side can complete before loading has finished. Send
    // the notification after both loading and V8 side operations have
    // completed. Here we also check that we have a client: it can happen that a
    // function calling notifyFinishedToClient was already scheduled in the task
    // queue and the upper layer decided that it's not interested in the script
    // and called removeClient.
    if (isFinished() && m_client)
        m_client->notifyFinished(m_resource);
}

} // namespace blink
<|endoftext|>


<commit_before>#include "DebugDraw.h"
#include "../../Graphics/GraphicsManager.h"
#include "../../Logger.h"
#include "../AARect.h"
#include "../Rect.h"
#include "../Helpers.h"

namespace star
{
	DebugDraw * DebugDraw::m_InstancePtr = nullptr;

	DebugDraw::DebugDraw()
		: m_PointSize(1.0f)
		, m_Shader(nullptr)
		, m_ColorLocation(0)
		, m_MVPLocation(0)
		, m_PositionLocation(0)
		, m_CircleSegments(16)
		, m_DrawOpTriangles(0.5f)
		, m_DrawOpLines(1.0f)
		, m_DrawOpPoints(1.0f)
	{

	}

	DebugDraw* DebugDraw::GetInstance()
	{
		if(m_InstancePtr == nullptr)
		{
			m_InstancePtr = new DebugDraw();
		}
		return m_InstancePtr;
	}

	DebugDraw::~DebugDraw()
	{
		delete m_Shader;
	}

	void DebugDraw::SetDrawOpacityTriangles(float opacity)
	{
		m_DrawOpTriangles = opacity;
	}

	void DebugDraw::SetDrawOpacityLines(float opacity)
	{
		m_DrawOpLines = opacity;
	}

	void DebugDraw::SetDrawOpacityPoints(float opacity)
	{
		m_DrawOpPoints = opacity;
	}

	void DebugDraw::SetCircleSegements(uint32 segments)
	{
		m_CircleSegments = segments;
	}

	void DebugDraw::Initialize()
	{
		static const GLchar* vertexShader = "\
			uniform mat4 MVP;\
			attribute vec2 position;\
			void main() {\
			  vec4 NewPosition = vec4(position, 0.0, 1.0);\
			  NewPosition *= MVP;\
			  gl_Position = NewPosition;\
			}\
			";

		static const GLchar* fragmentShader = "\
			precision mediump float; \
			uniform vec4 color;\
			void main() { \
			  gl_FragColor = color; \
			} \
			";

		// create program
		m_Shader = new Shader();
		m_Shader->Init(vertexShader, fragmentShader);

		m_ColorLocation = m_Shader->GetUniformLocation("color");
		m_MVPLocation = m_Shader->GetUniformLocation("MVP");
		m_PositionLocation = m_Shader->GetAttribLocation("position");
	}

	void DebugDraw::DrawPolygon(const vec2* vertices, int32 vertexCount, const Color& color)
	{
		CreatePolygonVertices(vertices, vertexCount);
		DrawPrimitives(Lines, vertexCount, color);
	}

	void DebugDraw::DrawSolidPolygon(const vec2* vertices, int32 vertexCount, const Color& color)
	{
		CreatePolygonVertices(vertices, vertexCount);
		DrawPrimitives(Triangles + Lines, vertexCount, color);
	}

	void DebugDraw::DrawCircle(const vec2& center, float radius, const Color& color)
	{
		CreateCircleVertices(center, radius);
		DrawPrimitives(Lines, m_CircleSegments, color);
	}

	void DebugDraw::DrawSolidCircle(const vec2& center, float radius,
			const Color& color)
	{
		CreateCircleVertices(center, radius);
		DrawPrimitives(Triangles + Lines, m_CircleSegments, color);
	}

	void DebugDraw::DrawSegment(const vec2& pos1, const vec2& pos2, const Color& color)
	{
		m_Vertices[0].x = pos1.x;
		m_Vertices[0].x = pos1.y;
		m_Vertices[1].y = pos2.x;
		m_Vertices[1].y = pos2.y;
		DrawPrimitives(Lines, 2, color);
	}

	void DebugDraw::DrawPoint(const vec2& pos, float size, const Color& color)
	{
		m_PointSize = size;

		m_Vertices[0].x = pos.x;
		m_Vertices[0].y = pos.y;
		DrawPrimitives(Points, 1, color);
	}

	void DebugDraw::DrawLine(const vec2& pos1, const vec2& pos2, const Color& color)
	{
		m_Vertices[0].x = pos1.x;
		m_Vertices[0].y = pos1.y;
		m_Vertices[1].x = pos2.x;
		m_Vertices[1].y = pos2.y;
		DrawPrimitives(Lines,2,color);
	}

	void DebugDraw::DrawString(int aX, int aY, const tstring& text)
	{
		//[TODO] Implement this through the font manager, draw text on screen on given pos.
		Logger::GetInstance()->Log(LogLevel::Warning, _T("DebugDraw::DrawString is not yet implemented!"));
	}

	void DebugDraw::DrawRect(const AARect& rect, const Color& color)
	{
		m_Vertices[0].x = float(rect.GetLeft());
		m_Vertices[0].y = float(rect.GetBottom());
		m_Vertices[1].x = float(rect.GetRight());
		m_Vertices[1].y = float(rect.GetBottom());
		m_Vertices[2].x = float(rect.GetRight());
		m_Vertices[2].y = float(rect.GetTop());
		m_Vertices[3].x = float(rect.GetLeft());
		m_Vertices[3].y = float(rect.GetTop());
		DrawPrimitives(Lines, 4, color);
	}

	void DebugDraw::DrawRect(const Rect& rect, const Color& color)
	{
		m_Vertices[0] = rect.GetLeftBottom();
		m_Vertices[1] = rect.GetRightBottom();
		m_Vertices[2] = rect.GetRightTop();
		m_Vertices[3] = rect.GetLeftTop();
		DrawPrimitives(Lines, 4, color);
	}

	void DebugDraw::DrawSolidRect(const AARect& rect, const Color& color)
	{
		m_Vertices[0].x = float(rect.GetLeft());
		m_Vertices[0].y = float(rect.GetBottom());
		m_Vertices[1].x = float(rect.GetRight());
		m_Vertices[1].y = float(rect.GetBottom());
		m_Vertices[2].x = float(rect.GetRight());
		m_Vertices[2].y = float(rect.GetTop());
		m_Vertices[3].x = float(rect.GetLeft());
		m_Vertices[3].y = float(rect.GetTop());
		DrawPrimitives(Triangles + Lines, 4, color);
	}

	void DebugDraw::DrawSolidRect(const Rect& rect, const Color& color)
	{
		m_Vertices[0] = rect.GetLeftBottom();
		m_Vertices[1] = rect.GetRightBottom();
		m_Vertices[2] = rect.GetRightTop();
		m_Vertices[3] = rect.GetLeftTop();
		DrawPrimitives(Triangles + Lines, 4, color);
	}

	void DebugDraw::CreatePolygonVertices(const vec2* vertices, uint32 vertexCount)
	{
		ASSERT(vertexCount <= MAX_VERTICES, _T("more vertices than allocated space"));
		//ASSERT(vertexCount <= MAX_VERTICES, _T("more vertices then allocated space"));

		for (uint32 i = 0; i < vertexCount; i++)
		{
			m_Vertices[i].x = vertices[i].x;
			m_Vertices[i].y = vertices[i].y;
		}
	}

	void DebugDraw::CreateCircleVertices(const vec2& center, float radius)
	{
		// [TODO] Fix this bug in eclipse: (undefined reference to 'star::DebugDraw::MAX_VERTICES')
		//ASSERT(m_CircleSegments < MAX_VERTICES, tstring(_T("You can only draw ")
		//	+ string_cast<tstring>(MAX_VERTICES) + _T(" vertices per primitive")).c_str());
		const float increment = float(2.0 * PI / m_CircleSegments);
		float theta = 0.0f;

		for (uint32 i = 0; i < m_CircleSegments; ++i)
		{
			vec2 v = center + radius * vec2(glm::cos(theta), glm::sin(theta));

			m_Vertices[i].x = v.x;
			m_Vertices[i].y = v.y;
			theta += increment;
		}
	}

	void DebugDraw::DrawPrimitives(uint32 primitiveTypes, uint32 count, const Color& color)
	{
#ifdef DESKTOP
		glUseProgram(m_Shader->GetID());

		glUniformMatrix4fv(m_MVPLocation,
				1, GL_FALSE, glm::value_ptr(GraphicsManager::GetInstance()->GetViewProjectionMatrix()));

		glEnableVertexAttribArray(m_PositionLocation);
		glVertexAttribPointer(m_PositionLocation, 2, GL_FLOAT, GL_FALSE, 0, (GLfloat*) m_Vertices);

		if (primitiveTypes & Triangles)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpTriangles);
			glDrawArrays(GL_TRIANGLE_FAN, 0, count);
		}

		if (primitiveTypes & Lines)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpLines);
			glDrawArrays(GL_LINE_LOOP, 0, count);
		}

		if (primitiveTypes & Points)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpPoints);
			//[TODO] only works for windows..
#ifdef DESKTOP
			glPointSize(m_PointSize);
#endif
			glDrawArrays(GL_POINTS, 0, count);
		}

		glDisableVertexAttribArray(m_PositionLocation);
		glUseProgram(0);
#endif
	}

}
<commit_msg>Debug drawing functions also get correctly scaled now.<commit_after>#include "DebugDraw.h"
#include "../../Graphics/GraphicsManager.h"
#include "../../Graphics/ScaleSystem.h"
#include "../../Logger.h"
#include "../AARect.h"
#include "../Rect.h"
#include "../Helpers.h"

namespace star
{
	DebugDraw * DebugDraw::m_InstancePtr = nullptr;

	DebugDraw::DebugDraw()
		: m_PointSize(1.0f)
		, m_Shader(nullptr)
		, m_ColorLocation(0)
		, m_MVPLocation(0)
		, m_PositionLocation(0)
		, m_CircleSegments(16)
		, m_DrawOpTriangles(0.5f)
		, m_DrawOpLines(1.0f)
		, m_DrawOpPoints(1.0f)
	{

	}

	DebugDraw* DebugDraw::GetInstance()
	{
		if(m_InstancePtr == nullptr)
		{
			m_InstancePtr = new DebugDraw();
		}
		return m_InstancePtr;
	}

	DebugDraw::~DebugDraw()
	{
		delete m_Shader;
	}

	void DebugDraw::SetDrawOpacityTriangles(float opacity)
	{
		m_DrawOpTriangles = opacity;
	}

	void DebugDraw::SetDrawOpacityLines(float opacity)
	{
		m_DrawOpLines = opacity;
	}

	void DebugDraw::SetDrawOpacityPoints(float opacity)
	{
		m_DrawOpPoints = opacity;
	}

	void DebugDraw::SetCircleSegements(uint32 segments)
	{
		m_CircleSegments = segments;
	}

	void DebugDraw::Initialize()
	{
		static const GLchar* vertexShader = "\
			uniform mat4 MVP;\
			attribute vec2 position;\
			void main() {\
			  vec4 NewPosition = vec4(position, 0.0, 1.0);\
			  NewPosition *= MVP;\
			  gl_Position = NewPosition;\
			}\
			";

		static const GLchar* fragmentShader = "\
			precision mediump float; \
			uniform vec4 color;\
			void main() { \
			  gl_FragColor = color; \
			} \
			";

		// create program
		m_Shader = new Shader();
		m_Shader->Init(vertexShader, fragmentShader);

		m_ColorLocation = m_Shader->GetUniformLocation("color");
		m_MVPLocation = m_Shader->GetUniformLocation("MVP");
		m_PositionLocation = m_Shader->GetAttribLocation("position");
	}

	void DebugDraw::DrawPolygon(const vec2* vertices, int32 vertexCount, const Color& color)
	{
		CreatePolygonVertices(vertices, vertexCount);
		DrawPrimitives(Lines, vertexCount, color);
	}

	void DebugDraw::DrawSolidPolygon(const vec2* vertices, int32 vertexCount, const Color& color)
	{
		CreatePolygonVertices(vertices, vertexCount);
		DrawPrimitives(Triangles + Lines, vertexCount, color);
	}

	void DebugDraw::DrawCircle(const vec2& center, float radius, const Color& color)
	{
		CreateCircleVertices(center, radius);
		DrawPrimitives(Lines, m_CircleSegments, color);
	}

	void DebugDraw::DrawSolidCircle(const vec2& center, float radius,
			const Color& color)
	{
		CreateCircleVertices(center, radius);
		DrawPrimitives(Triangles + Lines, m_CircleSegments, color);
	}

	void DebugDraw::DrawSegment(const vec2& pos1, const vec2& pos2, const Color& color)
	{
		m_Vertices[0].x = pos1.x;
		m_Vertices[0].x = pos1.y;
		m_Vertices[1].y = pos2.x;
		m_Vertices[1].y = pos2.y;
		DrawPrimitives(Lines, 2, color);
	}

	void DebugDraw::DrawPoint(const vec2& pos, float size, const Color& color)
	{
		m_PointSize = size;

		m_Vertices[0].x = pos.x;
		m_Vertices[0].y = pos.y;
		DrawPrimitives(Points, 1, color);
	}

	void DebugDraw::DrawLine(const vec2& pos1, const vec2& pos2, const Color& color)
	{
		m_Vertices[0].x = pos1.x;
		m_Vertices[0].y = pos1.y;
		m_Vertices[1].x = pos2.x;
		m_Vertices[1].y = pos2.y;
		DrawPrimitives(Lines,2,color);
	}

	void DebugDraw::DrawString(int aX, int aY, const tstring& text)
	{
		//[TODO] Implement this through the font manager, draw text on screen on given pos.
		Logger::GetInstance()->Log(LogLevel::Warning, _T("DebugDraw::DrawString is not yet implemented!"));
	}

	void DebugDraw::DrawRect(const AARect& rect, const Color& color)
	{
		m_Vertices[0].x = float(rect.GetLeft());
		m_Vertices[0].y = float(rect.GetBottom());
		m_Vertices[1].x = float(rect.GetRight());
		m_Vertices[1].y = float(rect.GetBottom());
		m_Vertices[2].x = float(rect.GetRight());
		m_Vertices[2].y = float(rect.GetTop());
		m_Vertices[3].x = float(rect.GetLeft());
		m_Vertices[3].y = float(rect.GetTop());
		DrawPrimitives(Lines, 4, color);
	}

	void DebugDraw::DrawRect(const Rect& rect, const Color& color)
	{
		m_Vertices[0] = rect.GetLeftBottom();
		m_Vertices[1] = rect.GetRightBottom();
		m_Vertices[2] = rect.GetRightTop();
		m_Vertices[3] = rect.GetLeftTop();
		DrawPrimitives(Lines, 4, color);
	}

	void DebugDraw::DrawSolidRect(const AARect& rect, const Color& color)
	{
		m_Vertices[0].x = float(rect.GetLeft());
		m_Vertices[0].y = float(rect.GetBottom());
		m_Vertices[1].x = float(rect.GetRight());
		m_Vertices[1].y = float(rect.GetBottom());
		m_Vertices[2].x = float(rect.GetRight());
		m_Vertices[2].y = float(rect.GetTop());
		m_Vertices[3].x = float(rect.GetLeft());
		m_Vertices[3].y = float(rect.GetTop());
		DrawPrimitives(Triangles + Lines, 4, color);
	}

	void DebugDraw::DrawSolidRect(const Rect& rect, const Color& color)
	{
		m_Vertices[0] = rect.GetLeftBottom();
		m_Vertices[1] = rect.GetRightBottom();
		m_Vertices[2] = rect.GetRightTop();
		m_Vertices[3] = rect.GetLeftTop();
		DrawPrimitives(Triangles + Lines, 4, color);
	}

	void DebugDraw::CreatePolygonVertices(const vec2* vertices, uint32 vertexCount)
	{
		ASSERT(vertexCount <= MAX_VERTICES, _T("more vertices than allocated space"));
		//ASSERT(vertexCount <= MAX_VERTICES, _T("more vertices then allocated space"));

		for (uint32 i = 0; i < vertexCount; i++)
		{
			m_Vertices[i].x = vertices[i].x;
			m_Vertices[i].y = vertices[i].y;
		}
	}

	void DebugDraw::CreateCircleVertices(const vec2& center, float radius)
	{
		// [TODO] Fix this bug in eclipse: (undefined reference to 'star::DebugDraw::MAX_VERTICES')
		//ASSERT(m_CircleSegments < MAX_VERTICES, tstring(_T("You can only draw ")
		//	+ string_cast<tstring>(MAX_VERTICES) + _T(" vertices per primitive")).c_str());
		const float increment = float(2.0 * PI / m_CircleSegments);
		float theta = 0.0f;

		for (uint32 i = 0; i < m_CircleSegments; ++i)
		{
			vec2 v = center + radius * vec2(glm::cos(theta), glm::sin(theta));

			m_Vertices[i].x = v.x;
			m_Vertices[i].y = v.y;
			theta += increment;
		}
	}

	void DebugDraw::DrawPrimitives(uint32 primitiveTypes, uint32 count, const Color& color)
	{
#ifdef DESKTOP
		glUseProgram(m_Shader->GetID());

		float scaleValue = ScaleSystem::GetInstance()->GetScale();
		mat4x4 scaleMat = glm::scale<float>(scaleValue, scaleValue, 1.0f);

		glUniformMatrix4fv(m_MVPLocation,
			1, GL_FALSE,
			glm::value_ptr(
				scaleMat *
				GraphicsManager::GetInstance()->GetViewProjectionMatrix()
			)
		);

		glEnableVertexAttribArray(m_PositionLocation);
		glVertexAttribPointer(m_PositionLocation, 2, GL_FLOAT, GL_FALSE, 0, (GLfloat*) m_Vertices);

		if (primitiveTypes & Triangles)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpTriangles);
			glDrawArrays(GL_TRIANGLE_FAN, 0, count);
		}

		if (primitiveTypes & Lines)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpLines);
			glDrawArrays(GL_LINE_LOOP, 0, count);
		}

		if (primitiveTypes & Points)
		{
			glUniform4f(m_ColorLocation, color.r, color.g, color.b, m_DrawOpPoints);
			//[TODO] only works for windows..
#ifdef DESKTOP
			glPointSize(m_PointSize);
#endif
			glDrawArrays(GL_POINTS, 0, count);
		}

		glDisableVertexAttribArray(m_PositionLocation);
		glUseProgram(0);
#endif
	}

}
<|endoftext|>


<commit_before>

#include "mfem.hpp"
#include "integ_algoim.hpp"

using namespace mfem;

//level set function for sphere in 3D and circle in 2D
double sphere_ls(const Vector &x)
{
   double r2= x*x;
   return sqrt(r2)-0.5;//the radius is 0.5
}

int main(int argc, char *argv[])
{
   //   Parse command-line options
   const char *mesh_file = "../../data/beam-tet.mesh";
   int ser_ref_levels = 1;
   int order = 2;
   bool visualization = true;
   int newton_iter = 10;
   int print_level = 0;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
   args.AddOption(&ser_ref_levels,
                  "-rs",
                  "--refine-serial",
                  "Number of times to refine the mesh uniformly in serial.");
   args.AddOption(&order,
                  "-o",
                  "--order",
                  "Order (degree) of the finite elements.");
   args.AddOption(&visualization,
                  "-vis",
                  "--visualization",
                  "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption((&print_level), "-prt", "--print-level", "Print level.");
   args.Parse();
   if (!args.Good())
   {
      args.PrintUsage(std::cout);
      return 1;
   }
   args.PrintOptions(std::cout);

   //   Read the (serial) mesh from the given mesh file.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   int dim = mesh->Dimension();
   //    Refine the mesh in serial to increase the resolution. In this example
   //    we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
   //    a command-line parameter.
   for (int lev = 0; lev < ser_ref_levels; lev++)
   {
      mesh->UniformRefinement();
   }

   // Define the finite element spaces for the solution
   H1_FECollection fec(order, dim);
   FiniteElementSpace fespace(mesh, &fec, 1, Ordering::byVDIM);
   int glob_size = fespace.GetTrueVSize();
   std::cout << "Number of finite element unknowns: " << glob_size << std::endl;

   // Define the level set grid function
   GridFunction x(&fespace);
   Vector lsvec; //true levelset vector

   // Define the level set coefficient
   Coefficient *ls_coeff = nullptr;
   ls_coeff=new FunctionCoefficient(sphere_ls);
   // Project the coefficient onto the LS grid function
   x.ProjectCoefficient(*ls_coeff);
   // Extract the true vector from the grid function
   x.GetTrueDofs(lsvec);

   Vector lsfun; //level set function restricted to an element
   DofTransformation *doftrans;
   ElementTransformation *trans;
   Array<int> vdofs;
   AlgoimIntegrationRule *air;

   DenseMatrix bmat; //gradients of the shape functions in isoparametric space
   DenseMatrix pmat; //gradients of the shape functions in physical space
   Vector inormal; //normal to the level set in isoparametric space
   Vector tnormal; //normal to the level set in physical space
   double w;
   const IntegrationRule* ir=nullptr;

   // loop over the elements
   double vol=0.0;
   double area=0.0;

#ifdef MFEM_USE_ALGOIM
   const int num_gauss_points=4;
   for(int i=0;i<fespace.GetNE();i++)
   {
       const FiniteElement* el=fespace.GetFE(i);
       //get the element transformation
       trans = fespace.GetElementTransformation(i);

       //extract the element vector from the level-set
       doftrans = fespace.GetElementVDofs(i,vdofs);
       lsvec.GetSubVector(vdofs, lsfun);

       //contruct Algoim integration object
       AlgoimIntegrationRule* air=new AlgoimIntegrationRule(num_gauss_points,*el,*trans,lsfun);

       //compute the volume contribution from the element
       ir=air->GetVolumeIntegrationRule();
       for (int i = 0; i < ir->GetNPoints(); i++)
       {
           const IntegrationPoint &ip = ir->IntPoint(i);
           trans->SetIntPoint(&ip);
           w = trans->Weight();
           w = ip.weight * w;
           vol=vol+w;
       }

       //compute the perimeter/area contribution from the element
       bmat.SetSize(el->GetDof(),el->GetDim());
       pmat.SetSize(el->GetDof(),el->GetDim());
       inormal.SetSize(el->GetDim());
       tnormal.SetSize(el->GetDim());

       ir=air->GetSurfaceIntegrationRule();
       for (int i = 0; i < ir->GetNPoints(); i++)
       {
           const IntegrationPoint &ip = ir->IntPoint(i);
           trans->SetIntPoint(&ip);

           el->CalcDShape(ip,bmat);
           Mult(bmat, trans->AdjugateJacobian(), pmat);
           //compute the normal to the LS in isoparametric space
           bmat.MultTranspose(lsfun,inormal);
           //compute the normal to the LS in physicsl space
           pmat.MultTranspose(lsfun,tnormal);
           w = ip.weight*tnormal.Norml2()/inormal.Norml2();
           area=area+w;
       }

       //delete the Algoim integration rule object
       //the integration rules are constructed for the
       //particular element and level set
       delete air;
   }
#endif
   std::cout<<"Volume="<<vol<<std::endl;
   std::cout<<"Area="<<area<<std::endl;

   ParaViewDataCollection dacol("ParaViewDistance", mesh);
   dacol.SetLevelsOfDetail(order);
   dacol.RegisterField("dist",&x);
   dacol.SetTime(1.0);
   dacol.SetCycle(1);
   dacol.Save();

   delete ls_coeff;
   delete mesh;

   return 0;
}
<commit_msg>modified the input mesh<commit_after>

#include "mfem.hpp"
#include "integ_algoim.hpp"

using namespace mfem;

//level set function for sphere in 3D and circle in 2D
double sphere_ls(const Vector &x)
{
   double r2= x*x;
   return -sqrt(r2)+0.5;//the radius is 0.5
}

int main(int argc, char *argv[])
{
   //   Parse command-line options
   const char *mesh_file = "../../data/star-q3.mesh";
   int ser_ref_levels = 1;
   int order = 2;
   bool visualization = true;
   int newton_iter = 10;
   int print_level = 0;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
   args.AddOption(&ser_ref_levels,
                  "-rs",
                  "--refine-serial",
                  "Number of times to refine the mesh uniformly in serial.");
   args.AddOption(&order,
                  "-o",
                  "--order",
                  "Order (degree) of the finite elements.");
   args.AddOption(&visualization,
                  "-vis",
                  "--visualization",
                  "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");
   args.AddOption((&print_level), "-prt", "--print-level", "Print level.");
   args.Parse();
   if (!args.Good())
   {
      args.PrintUsage(std::cout);
      return 1;
   }
   args.PrintOptions(std::cout);

   //   Read the (serial) mesh from the given mesh file.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   int dim = mesh->Dimension();
   //    Refine the mesh in serial to increase the resolution. In this example
   //    we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
   //    a command-line parameter.
   for (int lev = 0; lev < ser_ref_levels; lev++)
   {
      mesh->UniformRefinement();
   }

   // Define the finite element spaces for the solution
   H1_FECollection fec(order, dim);
   FiniteElementSpace fespace(mesh, &fec, 1, Ordering::byVDIM);
   int glob_size = fespace.GetTrueVSize();
   std::cout << "Number of finite element unknowns: " << glob_size << std::endl;

   // Define the level set grid function
   GridFunction x(&fespace);
   Vector lsvec; //true levelset vector

   // Define the level set coefficient
   Coefficient *ls_coeff = nullptr;
   ls_coeff=new FunctionCoefficient(sphere_ls);
   // Project the coefficient onto the LS grid function
   x.ProjectCoefficient(*ls_coeff);
   // Extract the true vector from the grid function
   x.GetTrueDofs(lsvec);

   Vector lsfun; //level set function restricted to an element
   DofTransformation *doftrans;
   ElementTransformation *trans;
   Array<int> vdofs;
   AlgoimIntegrationRule *air;

   DenseMatrix bmat; //gradients of the shape functions in isoparametric space
   DenseMatrix pmat; //gradients of the shape functions in physical space
   Vector inormal; //normal to the level set in isoparametric space
   Vector tnormal; //normal to the level set in physical space
   double w;
   const IntegrationRule* ir=nullptr;

   // loop over the elements
   double vol=0.0;
   double area=0.0;

#ifdef MFEM_USE_ALGOIM
   const int num_gauss_points=4;
   for(int i=0;i<fespace.GetNE();i++)
   {
       const FiniteElement* el=fespace.GetFE(i);
       //get the element transformation
       trans = fespace.GetElementTransformation(i);

       //extract the element vector from the level-set
       doftrans = fespace.GetElementVDofs(i,vdofs);
       lsvec.GetSubVector(vdofs, lsfun);

       //contruct Algoim integration object
       AlgoimIntegrationRule* air=new AlgoimIntegrationRule(num_gauss_points,*el,*trans,lsfun);

       //compute the volume contribution from the element
       ir=air->GetVolumeIntegrationRule();
       for (int i = 0; i < ir->GetNPoints(); i++)
       {
           const IntegrationPoint &ip = ir->IntPoint(i);
           trans->SetIntPoint(&ip);
           w = trans->Weight();
           w = ip.weight * w;
           vol=vol+w;
       }

       //compute the perimeter/area contribution from the element
       bmat.SetSize(el->GetDof(),el->GetDim());
       pmat.SetSize(el->GetDof(),el->GetDim());
       inormal.SetSize(el->GetDim());
       tnormal.SetSize(el->GetDim());

       ir=air->GetSurfaceIntegrationRule();
       for (int i = 0; i < ir->GetNPoints(); i++)
       {
           const IntegrationPoint &ip = ir->IntPoint(i);
           trans->SetIntPoint(&ip);

           el->CalcDShape(ip,bmat);
           Mult(bmat, trans->AdjugateJacobian(), pmat);
           //compute the normal to the LS in isoparametric space
           bmat.MultTranspose(lsfun,inormal);
           //compute the normal to the LS in physicsl space
           pmat.MultTranspose(lsfun,tnormal);
           w = ip.weight*tnormal.Norml2()/inormal.Norml2();
           area=area+w;
       }

       //delete the Algoim integration rule object
       //the integration rules are constructed for the
       //particular element and level set
       delete air;
   }
#endif
   std::cout<<"Volume="<<vol<<std::endl;
   std::cout<<"Area="<<area<<std::endl;

   ParaViewDataCollection dacol("ParaViewDistance", mesh);
   dacol.SetLevelsOfDetail(order);
   dacol.RegisterField("dist",&x);
   dacol.SetTime(1.0);
   dacol.SetCycle(1);
   dacol.Save();

   delete ls_coeff;
   delete mesh;

   return 0;
}
<|endoftext|>