//
// This code complies with UFC version 1.0, and is generated with SyFi version 0.4.0.
//
// http://www.fenics.org/syfi/
// http://www.fenics.org/ufc/
//


#include <stdexcept>
#include <math.h>
#include <ufc.h>
#include <pycc/Functions/Ptv.h>
#include <pycc/Functions/Ptv_tools.h>
#include <pycc/Functions/Dof_Ptv.h>
#include <pycc/Functions/OrderedPtvSet.h>
#include <pycc/Functions/Dof_OrderedPtvSet.h>
#include "dof_map_Lagrange_1_2D.h"
#include "fe_Lagrange_1_2D.h"
#include "form__stiffness_form__Lagrange_1_2D.h"


namespace pycc
{

/// This class defines the interface for the tabulation of the cell
/// tensor corresponding to the local contribution to a form from
/// the integral over a cell.

class cell_itg__stiffness_form__Lagrange_1_2D: public ufc::cell_integral
{
public:

  /// Constructor
  cell_itg__stiffness_form__Lagrange_1_2D();

  /// Destructor
  virtual ~cell_itg__stiffness_form__Lagrange_1_2D();

  /// Tabulate the tensor for the contribution from a local cell
  virtual void tabulate_tensor(double* A,
                               const double * const * w,
                               const ufc::cell& c) const;

};


/// Constructor
cell_itg__stiffness_form__Lagrange_1_2D::cell_itg__stiffness_form__Lagrange_1_2D() 
: ufc::cell_integral()
{

}

/// Destructor
cell_itg__stiffness_form__Lagrange_1_2D::~cell_itg__stiffness_form__Lagrange_1_2D()
{

}

/// Tabulate the tensor for the contribution from a local cell
void cell_itg__stiffness_form__Lagrange_1_2D::tabulate_tensor(double* A,
                                    const double * const * w,
                                    const ufc::cell& c) const
{
  // coordinates
  double x0 = c.coordinates[0][0]; double y0 = c.coordinates[0][1];
  double x1 = c.coordinates[1][0]; double y1 = c.coordinates[1][1];
  double x2 = c.coordinates[2][0]; double y2 = c.coordinates[2][1];
  
  // affine map
  double G00 = x1 - x0;
  double G01 = x2 - x0;
  
  double G10 = y1 - y0;
  double G11 = y2 - y0;
  
  double detG_tmp = G00*G11-G01*G10;
  double detG = fabs(detG_tmp);
  
  double GinvT00 =  G11 / detG_tmp;
  double GinvT01 = -G10 / detG_tmp;
  double GinvT10 = -G01 / detG_tmp;
  double GinvT11 =  G00 / detG_tmp;
  
  
  memset(A, 0, sizeof(double)*9);
  
  A[3*0 + 0] = detG*((GinvT01*GinvT01)/2.0+(GinvT11*GinvT11)/2.0+GinvT10*GinvT00
      +GinvT01*GinvT11+(GinvT00*GinvT00)/2.0+(GinvT10*GinvT10)/2.0);
  A[3*0 + 1] = detG*(-(GinvT01*GinvT01)/2.0-GinvT10*GinvT00/2.0
      -GinvT01*GinvT11/2.0-(GinvT00*GinvT00)/2.0);
  A[3*0 + 2] = detG*(-(GinvT11*GinvT11)/2.0-GinvT10*GinvT00/2.0
      -GinvT01*GinvT11/2.0-(GinvT10*GinvT10)/2.0);
  A[3*1 + 0] = detG*(-(GinvT01*GinvT01)/2.0-GinvT10*GinvT00/2.0
      -GinvT01*GinvT11/2.0-(GinvT00*GinvT00)/2.0);
  A[3*1 + 1] = detG*((GinvT01*GinvT01)/2.0+(GinvT00*GinvT00)/2.0);
  A[3*1 + 2] = detG*(GinvT10*GinvT00/2.0+GinvT01*GinvT11/2.0);
  A[3*2 + 0] = detG*(-(GinvT11*GinvT11)/2.0-GinvT10*GinvT00/2.0
      -GinvT01*GinvT11/2.0-(GinvT10*GinvT10)/2.0);
  A[3*2 + 1] = detG*(GinvT10*GinvT00/2.0+GinvT01*GinvT11/2.0);
  A[3*2 + 2] = detG*((GinvT11*GinvT11)/2.0+(GinvT10*GinvT10)/2.0);
}



/// Constructor
form__stiffness_form__Lagrange_1_2D::form__stiffness_form__Lagrange_1_2D() : ufc::form()
{
  
}

/// Destructor
form__stiffness_form__Lagrange_1_2D::~form__stiffness_form__Lagrange_1_2D()
{
  
}

/// Return a string identifying the form
const char* form__stiffness_form__Lagrange_1_2D::signature() const
{
  return "form__stiffness_form__Lagrange_1_2D // generated by SyFi";
}

/// Return the rank of the global tensor (r)
unsigned int form__stiffness_form__Lagrange_1_2D::rank() const
{
  return 2;
}

/// Return the number of coefficients (n)
unsigned int form__stiffness_form__Lagrange_1_2D::num_coefficients() const
{
  return 0;
}

/// Return the number of cell integrals
unsigned int form__stiffness_form__Lagrange_1_2D::num_cell_integrals() const
{
  return 1;
}
  
/// Return the number of exterior facet integrals
unsigned int form__stiffness_form__Lagrange_1_2D::num_exterior_facet_integrals() const
{
  return 0;
}
  
/// Return the number of interior facet integrals
unsigned int form__stiffness_form__Lagrange_1_2D::num_interior_facet_integrals() const
{
  return 0;
}

/// Create a new finite element for argument function i
ufc::finite_element* form__stiffness_form__Lagrange_1_2D::
     create_finite_element(unsigned int i) const
{
  switch(i)
  {
  case 0:
    return new fe_Lagrange_1_2D();
  case 1:
    return new fe_Lagrange_1_2D();
  }
  throw std::runtime_error("Invalid index in create_finite_element()");
}

/// Create a new dof map for argument function i
ufc::dof_map* form__stiffness_form__Lagrange_1_2D::create_dof_map(unsigned int i) const
{
  switch(i)
  {
  case 0:
    return new dof_map_Lagrange_1_2D();
  case 1:
    return new dof_map_Lagrange_1_2D();
  }
  throw std::runtime_error("Invalid index in create_dof_map()");
}

/// Create a new cell integral on sub domain i
ufc::cell_integral* form__stiffness_form__Lagrange_1_2D::
     create_cell_integral(unsigned int i) const
{
  return new cell_itg__stiffness_form__Lagrange_1_2D();
}

/// Create a new exterior facet integral on sub domain i
ufc::exterior_facet_integral* form__stiffness_form__Lagrange_1_2D::
     create_exterior_facet_integral(unsigned int i) const
{
  return 0;
}

/// Create a new interior facet integral on sub domain i
ufc::interior_facet_integral* form__stiffness_form__Lagrange_1_2D::
     create_interior_facet_integral(unsigned int i) const
{
  return 0;
}


} // namespace
