// Automatically generated by FFC, the FEniCS Form Compiler, version 0.3.5.
// For further information, go to http://www/fenics.org/ffc/.
// Licensed under the GNU GPL Version 2.

#ifndef __OPTIMIZATION_H
#define __OPTIMIZATION_H

#include <dolfin/Mesh.h>
#include <dolfin/Cell.h>
#include <dolfin/Point.h>
#include <dolfin/AffineMap.h>
#include <dolfin/FiniteElement.h>
#include <dolfin/FiniteElementSpec.h>
#include <dolfin/BilinearForm.h>
#include <dolfin/LinearForm.h>
#include <dolfin/Functional.h>
#include <dolfin/FEM.h>

namespace dolfin { namespace Optimization {

/// This class contains the form to be evaluated, including
/// contributions from the interior and boundary of the domain.

class BilinearForm : public dolfin::BilinearForm
{
public:

  class TestElement;

  class TrialElement;

  BilinearForm();
  

  bool interior_contribution() const;

  void eval(real block[], const AffineMap& map) const;

  bool boundary_contribution() const;

  void eval(real block[], const AffineMap& map, unsigned int facet) const;

};

class BilinearForm::TestElement : public dolfin::FiniteElement
{
public:

  TestElement() : dolfin::FiniteElement(), tensordims(0), subelements(0)
  {
    // Element is scalar, don't need to initialize tensordims

    // Element is simple, don't need to initialize subelements
  }

  ~TestElement()
  {
    if ( tensordims ) delete [] tensordims;
    if ( subelements )
    {
      for (unsigned int i = 0; i < elementdim(); i++)
        delete subelements[i];
      delete [] subelements;
    }
  }

  inline unsigned int spacedim() const
  {
    return 10;
  }

  inline unsigned int shapedim() const
  {
    return 2;
  }

  inline unsigned int tensordim(unsigned int i) const
  {
    dolfin_error("Element is scalar.");
    return 0;
  }

  inline unsigned int elementdim() const
  {
    return 1;
  }

  inline unsigned int rank() const
  {
    return 0;
  }

  void nodemap(int nodes[], const Cell& cell, const Mesh& mesh) const
  {
    static unsigned int edge_reordering_0[2][2] = {{0, 1}, {1, 0}};
    nodes[0] = cell.entities(0)[0];
    nodes[1] = cell.entities(0)[1];
    nodes[2] = cell.entities(0)[2];
    int alignment = cell.alignment(1, 0);
    int offset = mesh.topology().size(0);
    nodes[3] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][0];
    nodes[4] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 1);
    nodes[5] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][0];
    nodes[6] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 2);
    nodes[7] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][0];
    nodes[8] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][1];
    offset = offset + 2*mesh.topology().size(1);
    nodes[9] = offset + cell.index();
  }

  void pointmap(Point points[], unsigned int components[], const AffineMap& map) const
  {
    points[0] = map(0.000000000000000e+00, 0.000000000000000e+00);
    points[1] = map(1.000000000000000e+00, 0.000000000000000e+00);
    points[2] = map(0.000000000000000e+00, 1.000000000000000e+00);
    points[3] = map(6.666666666666667e-01, 3.333333333333333e-01);
    points[4] = map(3.333333333333334e-01, 6.666666666666666e-01);
    points[5] = map(0.000000000000000e+00, 6.666666666666667e-01);
    points[6] = map(0.000000000000000e+00, 3.333333333333334e-01);
    points[7] = map(3.333333333333333e-01, 0.000000000000000e+00);
    points[8] = map(6.666666666666666e-01, 0.000000000000000e+00);
    points[9] = map(3.333333333333333e-01, 3.333333333333333e-01);
    components[0] = 0;
    components[1] = 0;
    components[2] = 0;
    components[3] = 0;
    components[4] = 0;
    components[5] = 0;
    components[6] = 0;
    components[7] = 0;
    components[8] = 0;
    components[9] = 0;
  }

  void vertexeval(uint vertex_nodes[], unsigned int vertex, const Mesh& mesh) const
  {
    // FIXME: Temporary fix for Lagrange elements
    vertex_nodes[0] = vertex;
  }

  const FiniteElement& operator[] (unsigned int i) const
  {
    return *this;
  }

  FiniteElement& operator[] (unsigned int i)
  {
    return *this;
  }

  FiniteElementSpec spec() const
  {
    FiniteElementSpec s("Lagrange", "triangle", 3);
    return s;
  }
  
private:

  unsigned int* tensordims;
  FiniteElement** subelements;

};

class BilinearForm::TrialElement : public dolfin::FiniteElement
{
public:

  TrialElement() : dolfin::FiniteElement(), tensordims(0), subelements(0)
  {
    // Element is scalar, don't need to initialize tensordims

    // Element is simple, don't need to initialize subelements
  }

  ~TrialElement()
  {
    if ( tensordims ) delete [] tensordims;
    if ( subelements )
    {
      for (unsigned int i = 0; i < elementdim(); i++)
        delete subelements[i];
      delete [] subelements;
    }
  }

  inline unsigned int spacedim() const
  {
    return 10;
  }

  inline unsigned int shapedim() const
  {
    return 2;
  }

  inline unsigned int tensordim(unsigned int i) const
  {
    dolfin_error("Element is scalar.");
    return 0;
  }

  inline unsigned int elementdim() const
  {
    return 1;
  }

  inline unsigned int rank() const
  {
    return 0;
  }

  void nodemap(int nodes[], const Cell& cell, const Mesh& mesh) const
  {
    static unsigned int edge_reordering_0[2][2] = {{0, 1}, {1, 0}};
    nodes[0] = cell.entities(0)[0];
    nodes[1] = cell.entities(0)[1];
    nodes[2] = cell.entities(0)[2];
    int alignment = cell.alignment(1, 0);
    int offset = mesh.topology().size(0);
    nodes[3] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][0];
    nodes[4] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 1);
    nodes[5] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][0];
    nodes[6] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 2);
    nodes[7] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][0];
    nodes[8] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][1];
    offset = offset + 2*mesh.topology().size(1);
    nodes[9] = offset + cell.index();
  }

  void pointmap(Point points[], unsigned int components[], const AffineMap& map) const
  {
    points[0] = map(0.000000000000000e+00, 0.000000000000000e+00);
    points[1] = map(1.000000000000000e+00, 0.000000000000000e+00);
    points[2] = map(0.000000000000000e+00, 1.000000000000000e+00);
    points[3] = map(6.666666666666667e-01, 3.333333333333333e-01);
    points[4] = map(3.333333333333334e-01, 6.666666666666666e-01);
    points[5] = map(0.000000000000000e+00, 6.666666666666667e-01);
    points[6] = map(0.000000000000000e+00, 3.333333333333334e-01);
    points[7] = map(3.333333333333333e-01, 0.000000000000000e+00);
    points[8] = map(6.666666666666666e-01, 0.000000000000000e+00);
    points[9] = map(3.333333333333333e-01, 3.333333333333333e-01);
    components[0] = 0;
    components[1] = 0;
    components[2] = 0;
    components[3] = 0;
    components[4] = 0;
    components[5] = 0;
    components[6] = 0;
    components[7] = 0;
    components[8] = 0;
    components[9] = 0;
  }

  void vertexeval(uint vertex_nodes[], unsigned int vertex, const Mesh& mesh) const
  {
    // FIXME: Temporary fix for Lagrange elements
    vertex_nodes[0] = vertex;
  }

  const FiniteElement& operator[] (unsigned int i) const
  {
    return *this;
  }

  FiniteElement& operator[] (unsigned int i)
  {
    return *this;
  }

  FiniteElementSpec spec() const
  {
    FiniteElementSpec s("Lagrange", "triangle", 3);
    return s;
  }
  
private:

  unsigned int* tensordims;
  FiniteElement** subelements;

};

BilinearForm::BilinearForm() : dolfin::BilinearForm(0)
{
  // Create finite element for test space
  _test = new TestElement();

  // Create finite element for trial space
  _trial = new TrialElement();
}

// Contribution from the interior
bool BilinearForm::interior_contribution() const { return true; }

void BilinearForm::eval(real block[], const AffineMap& map) const
{
  // Compute geometry tensors
  const real G0_0_0 = map.det*map.g00*map.g00 + map.det*map.g01*map.g01;
  const real G0_0_1 = map.det*map.g00*map.g10 + map.det*map.g01*map.g11;
  const real G0_1_0 = map.det*map.g10*map.g00 + map.det*map.g11*map.g01;
  const real G0_1_1 = map.det*map.g10*map.g10 + map.det*map.g11*map.g11;

  // Compute element tensor
  block[73] = 1.687499999999994e-01*G0_0_1 + 1.687499999999997e-01*G0_1_0 + 3.374999999999996e-01*G0_1_1;
  block[16] = -3.749999999999934e-02*G0_0_0;
  block[37] = block[73];
  block[85] = -block[73] + 3.375000000000002e-01*G0_1_1;
  block[58] = block[85];
  block[90] = 0.0;
  block[67] = -5.000000000000021e+00*block[85];
  block[76] = block[67];
  block[11] = 4.249999999999998e-01*G0_0_0;
  block[82] = -3.750000000000028e-02*G0_1_1;
  block[7] = -block[82] + -6.749999999999996e-01*G0_0_0 + 3.749999999999970e-02*G0_0_1 + -6.749999999999996e-01*G0_1_0;
  block[40] = -block[7] + -7.124999999999995e-01*G0_0_0 + -7.124999999999995e-01*G0_1_0;
  block[4] = block[40];
  block[32] = -block[82] + -2.999999999999995e-01*G0_0_1;
  block[45] = -block[67] + -1.687499999999998e+00*G0_0_0;
  block[69] = 1.200000000000000e+00*block[45];
  block[55] = -block[45] + 1.687499999999998e+00*G0_1_1;
  block[93] = block[69];
  block[60] = block[7] + 7.124999999999997e-01*G0_0_0 + -7.124999999999992e-01*G0_1_1;
  block[75] = block[85];
  block[31] = -block[16] + 7.125000000000000e-01*G0_1_0;
  block[99] = 2.399999999999999e+00*block[55];
  block[78] = -block[73] + -1.350000000000000e+00*G0_0_0 + -1.012500000000000e+00*G0_1_0;
  block[21] = 8.750000000000001e-02*G0_1_0;
  block[1] = -block[21] + -8.750000000000001e-02*G0_0_0;
  block[89] = -6.000000000000028e+00*block[85];
  block[94] = -6.000000000000012e+00*block[73];
  block[51] = block[16];
  block[72] = block[82];
  block[15] = block[16];
  block[36] = -block[85] + 3.374999999999996e-01*G0_0_0;
  block[22] = 4.249999999999997e-01*G0_1_1;
  block[86] = block[85];
  block[41] = -block[16] + -2.999999999999993e-01*G0_1_0;
  block[97] = block[94];
  block[64] = block[36];
  block[54] = block[45];
  block[71] = -block[41] + 3.750000000000001e-01*G0_0_0;
  block[5] = -block[40] + 2.999999999999997e-01*G0_0_1 + 3.000000000000000e-01*G0_1_1;
  block[8] = block[7] + 1.012500000000000e+00*G0_0_0 + 1.012500000000000e+00*G0_1_0;
  block[35] = block[36];
  block[27] = block[82];
  block[83] = -5.000000000000015e+00*block[73];
  block[46] = block[36];
  block[92] = 0.0;
  block[61] = block[16];
  block[57] = block[85];
  block[74] = block[73];
  block[13] = -block[16] + 7.125000000000002e-01*G0_0_1;
  block[48] = block[73];
  block[30] = block[40];
  block[28] = block[82];
  block[98] = block[89];
  block[80] = -block[40] + 3.000000000000000e-01*G0_0_0 + 2.999999999999999e-01*G0_0_1;
  block[62] = -block[32] + 3.750000000000003e-01*G0_1_1;
  block[50] = -block[40] + 2.999999999999998e-01*G0_1_0 + 2.999999999999999e-01*G0_1_1;
  block[14] = -block[16] + -2.999999999999990e-01*G0_0_1;
  block[39] = block[69];
  block[23] = -block[82] + -2.999999999999994e-01*G0_1_0;
  block[26] = -block[23] + 3.750000000000003e-01*G0_1_1;
  block[19] = 0.0;
  block[87] = -block[73] + -1.350000000000000e+00*G0_0_0 + -1.012500000000001e+00*G0_0_1;
  block[42] = -block[82] + 7.124999999999995e-01*G0_0_1;
  block[96] = block[69];
  block[65] = -block[36] + -1.012500000000000e+00*G0_0_1 + -1.349999999999999e+00*G0_1_1;
  block[53] = block[36];
  block[70] = block[7] + -7.124999999999994e-01*G0_0_1 + 7.124999999999995e-01*G0_1_0;
  block[68] = block[85];
  block[6] = -block[40] + -7.124999999999991e-01*G0_0_1 + -7.124999999999992e-01*G0_1_1;
  block[17] = -block[14] + 3.750000000000001e-01*G0_0_0;
  block[9] = 0.0;
  block[34] = -block[73] + -3.375000000000000e-01*G0_0_0 + 1.012499999999998e+00*G0_0_1;
  block[24] = -block[82] + 7.124999999999995e-01*G0_1_0;
  block[25] = -block[24] + -6.374999999999995e-01*G0_1_1;
  block[84] = block[73];
  block[59] = block[89];
  block[47] = block[73];
  block[91] = 0.0;
  block[66] = block[55];
  block[56] = -block[36] + -1.012499999999999e+00*G0_1_0 + -1.349999999999999e+00*G0_1_1;
  block[77] = block[55];
  block[3] = block[40];
  block[12] = 8.750000000000001e-02*G0_0_1;
  block[10] = -block[12] + -8.750000000000001e-02*G0_0_0;
  block[2] = -block[12] + -8.750000000000001e-02*G0_1_1;
  block[49] = block[94];
  block[33] = block[55];
  block[29] = 0.0;
  block[81] = -block[31] + -6.374999999999990e-01*G0_0_0;
  block[44] = block[55];
  block[63] = block[36];
  block[0] = -1.133333333333335e+01*block[40];
  block[79] = block[94];
  block[38] = block[83];
  block[20] = -block[21] + -8.750000000000001e-02*G0_1_1;
  block[18] = -block[13] + -6.374999999999988e-01*G0_0_0;
  block[88] = block[55];
  block[43] = -block[73] + -3.375000000000000e-01*G0_0_0 + 1.012499999999998e+00*G0_1_0;
  block[95] = block[89];
  block[52] = -block[42] + -6.374999999999995e-01*G0_1_1;
}

// No contribution from the boundary
bool BilinearForm::boundary_contribution() const { return false; }

void BilinearForm::eval(real block[], const AffineMap& map, unsigned int facet) const {}

/// This class contains the form to be evaluated, including
/// contributions from the interior and boundary of the domain.

class LinearForm : public dolfin::LinearForm
{
public:

  class TestElement;

  class FunctionElement_0;

  LinearForm(Function& w0);
  

  bool interior_contribution() const;

  void eval(real block[], const AffineMap& map) const;

  bool boundary_contribution() const;

  void eval(real block[], const AffineMap& map, unsigned int facet) const;

};

class LinearForm::TestElement : public dolfin::FiniteElement
{
public:

  TestElement() : dolfin::FiniteElement(), tensordims(0), subelements(0)
  {
    // Element is scalar, don't need to initialize tensordims

    // Element is simple, don't need to initialize subelements
  }

  ~TestElement()
  {
    if ( tensordims ) delete [] tensordims;
    if ( subelements )
    {
      for (unsigned int i = 0; i < elementdim(); i++)
        delete subelements[i];
      delete [] subelements;
    }
  }

  inline unsigned int spacedim() const
  {
    return 10;
  }

  inline unsigned int shapedim() const
  {
    return 2;
  }

  inline unsigned int tensordim(unsigned int i) const
  {
    dolfin_error("Element is scalar.");
    return 0;
  }

  inline unsigned int elementdim() const
  {
    return 1;
  }

  inline unsigned int rank() const
  {
    return 0;
  }

  void nodemap(int nodes[], const Cell& cell, const Mesh& mesh) const
  {
    static unsigned int edge_reordering_0[2][2] = {{0, 1}, {1, 0}};
    nodes[0] = cell.entities(0)[0];
    nodes[1] = cell.entities(0)[1];
    nodes[2] = cell.entities(0)[2];
    int alignment = cell.alignment(1, 0);
    int offset = mesh.topology().size(0);
    nodes[3] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][0];
    nodes[4] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 1);
    nodes[5] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][0];
    nodes[6] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 2);
    nodes[7] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][0];
    nodes[8] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][1];
    offset = offset + 2*mesh.topology().size(1);
    nodes[9] = offset + cell.index();
  }

  void pointmap(Point points[], unsigned int components[], const AffineMap& map) const
  {
    points[0] = map(0.000000000000000e+00, 0.000000000000000e+00);
    points[1] = map(1.000000000000000e+00, 0.000000000000000e+00);
    points[2] = map(0.000000000000000e+00, 1.000000000000000e+00);
    points[3] = map(6.666666666666667e-01, 3.333333333333333e-01);
    points[4] = map(3.333333333333334e-01, 6.666666666666666e-01);
    points[5] = map(0.000000000000000e+00, 6.666666666666667e-01);
    points[6] = map(0.000000000000000e+00, 3.333333333333334e-01);
    points[7] = map(3.333333333333333e-01, 0.000000000000000e+00);
    points[8] = map(6.666666666666666e-01, 0.000000000000000e+00);
    points[9] = map(3.333333333333333e-01, 3.333333333333333e-01);
    components[0] = 0;
    components[1] = 0;
    components[2] = 0;
    components[3] = 0;
    components[4] = 0;
    components[5] = 0;
    components[6] = 0;
    components[7] = 0;
    components[8] = 0;
    components[9] = 0;
  }

  void vertexeval(uint vertex_nodes[], unsigned int vertex, const Mesh& mesh) const
  {
    // FIXME: Temporary fix for Lagrange elements
    vertex_nodes[0] = vertex;
  }

  const FiniteElement& operator[] (unsigned int i) const
  {
    return *this;
  }

  FiniteElement& operator[] (unsigned int i)
  {
    return *this;
  }

  FiniteElementSpec spec() const
  {
    FiniteElementSpec s("Lagrange", "triangle", 3);
    return s;
  }
  
private:

  unsigned int* tensordims;
  FiniteElement** subelements;

};

class LinearForm::FunctionElement_0 : public dolfin::FiniteElement
{
public:

  FunctionElement_0() : dolfin::FiniteElement(), tensordims(0), subelements(0)
  {
    // Element is scalar, don't need to initialize tensordims

    // Element is simple, don't need to initialize subelements
  }

  ~FunctionElement_0()
  {
    if ( tensordims ) delete [] tensordims;
    if ( subelements )
    {
      for (unsigned int i = 0; i < elementdim(); i++)
        delete subelements[i];
      delete [] subelements;
    }
  }

  inline unsigned int spacedim() const
  {
    return 10;
  }

  inline unsigned int shapedim() const
  {
    return 2;
  }

  inline unsigned int tensordim(unsigned int i) const
  {
    dolfin_error("Element is scalar.");
    return 0;
  }

  inline unsigned int elementdim() const
  {
    return 1;
  }

  inline unsigned int rank() const
  {
    return 0;
  }

  void nodemap(int nodes[], const Cell& cell, const Mesh& mesh) const
  {
    static unsigned int edge_reordering_0[2][2] = {{0, 1}, {1, 0}};
    nodes[0] = cell.entities(0)[0];
    nodes[1] = cell.entities(0)[1];
    nodes[2] = cell.entities(0)[2];
    int alignment = cell.alignment(1, 0);
    int offset = mesh.topology().size(0);
    nodes[3] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][0];
    nodes[4] = offset + 2*cell.entities(1)[0] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 1);
    nodes[5] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][0];
    nodes[6] = offset + 2*cell.entities(1)[1] + edge_reordering_0[alignment][1];
    alignment = cell.alignment(1, 2);
    nodes[7] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][0];
    nodes[8] = offset + 2*cell.entities(1)[2] + edge_reordering_0[alignment][1];
    offset = offset + 2*mesh.topology().size(1);
    nodes[9] = offset + cell.index();
  }

  void pointmap(Point points[], unsigned int components[], const AffineMap& map) const
  {
    points[0] = map(0.000000000000000e+00, 0.000000000000000e+00);
    points[1] = map(1.000000000000000e+00, 0.000000000000000e+00);
    points[2] = map(0.000000000000000e+00, 1.000000000000000e+00);
    points[3] = map(6.666666666666667e-01, 3.333333333333333e-01);
    points[4] = map(3.333333333333334e-01, 6.666666666666666e-01);
    points[5] = map(0.000000000000000e+00, 6.666666666666667e-01);
    points[6] = map(0.000000000000000e+00, 3.333333333333334e-01);
    points[7] = map(3.333333333333333e-01, 0.000000000000000e+00);
    points[8] = map(6.666666666666666e-01, 0.000000000000000e+00);
    points[9] = map(3.333333333333333e-01, 3.333333333333333e-01);
    components[0] = 0;
    components[1] = 0;
    components[2] = 0;
    components[3] = 0;
    components[4] = 0;
    components[5] = 0;
    components[6] = 0;
    components[7] = 0;
    components[8] = 0;
    components[9] = 0;
  }

  void vertexeval(uint vertex_nodes[], unsigned int vertex, const Mesh& mesh) const
  {
    // FIXME: Temporary fix for Lagrange elements
    vertex_nodes[0] = vertex;
  }

  const FiniteElement& operator[] (unsigned int i) const
  {
    return *this;
  }

  FiniteElement& operator[] (unsigned int i)
  {
    return *this;
  }

  FiniteElementSpec spec() const
  {
    FiniteElementSpec s("Lagrange", "triangle", 3);
    return s;
  }
  
private:

  unsigned int* tensordims;
  FiniteElement** subelements;

};

LinearForm::LinearForm(Function& w0) : dolfin::LinearForm(1)
{
  // Create finite element for test space
  _test = new TestElement();

  // Add functions
  initFunction(0, w0, new FunctionElement_0());
}

// Contribution from the interior
bool LinearForm::interior_contribution() const { return true; }

void LinearForm::eval(real block[], const AffineMap& map) const
{
  // Compute coefficients
  const real c0_0 = c[0][0];
  const real c0_1 = c[0][1];
  const real c0_2 = c[0][2];
  const real c0_3 = c[0][3];
  const real c0_4 = c[0][4];
  const real c0_5 = c[0][5];
  const real c0_6 = c[0][6];
  const real c0_7 = c[0][7];
  const real c0_8 = c[0][8];
  const real c0_9 = c[0][9];

  // Compute geometry tensors
  const real G0_0 = map.det*c0_0;
  const real G0_1 = map.det*c0_1;
  const real G0_2 = map.det*c0_2;
  const real G0_3 = map.det*c0_3;
  const real G0_4 = map.det*c0_4;
  const real G0_5 = map.det*c0_5;
  const real G0_6 = map.det*c0_6;
  const real G0_7 = map.det*c0_7;
  const real G0_8 = map.det*c0_8;
  const real G0_9 = map.det*c0_9;

  // Compute element tensor
  block[0] = 5.654761904761898e-03*G0_0 + 8.184523809523801e-04*G0_1 + 8.184523809523793e-04*G0_2 + 2.008928571428568e-03*G0_3 + 2.008928571428570e-03*G0_4 + 1.339285714285713e-03*G0_6 + 1.339285714285709e-03*G0_7 + 2.678571428571425e-03*G0_9;
  block[1] = 8.184523809523800e-04*G0_0 + 5.654761904761894e-03*G0_1 + 8.184523809523791e-04*G0_2 + 1.339285714285704e-03*G0_3 + 2.008928571428569e-03*G0_5 + 2.008928571428569e-03*G0_6 + 1.339285714285709e-03*G0_8 + 2.678571428571413e-03*G0_9;
  block[2] = 8.184523809523793e-04*G0_0 + 8.184523809523792e-04*G0_1 + 5.654761904761899e-03*G0_2 + 1.339285714285713e-03*G0_4 + 1.339285714285709e-03*G0_5 + 2.008928571428571e-03*G0_7 + 2.008928571428570e-03*G0_8 + 2.678571428571422e-03*G0_9;
  block[8] = 1.339285714285710e-03*G0_1 + 2.008928571428570e-03*G0_2 + 2.008928571428570e-02*G0_3 + -1.004464285714284e-02*G0_4 + -4.017857142857136e-03*G0_5 + -1.004464285714284e-02*G0_6 + -1.406249999999999e-02*G0_7 + 4.017857142857141e-02*G0_8 + 1.205357142857144e-02*G0_9;
  block[3] = block[8] + 2.008928571428564e-03*G0_0 + -2.008928571428572e-03*G0_2 + 2.008928571428566e-02*G0_3 + -4.017857142857141e-03*G0_4 + -6.026785714285711e-03*G0_5 + 6.026785714285701e-03*G0_6 + 4.017857142857134e-03*G0_7 + -2.008928571428571e-02*G0_8;
  block[9] = 2.678571428571425e-03*G0_0 + 2.678571428571414e-03*G0_1 + 2.678571428571422e-03*G0_2 + 1.205357142857144e-02*G0_3 + 1.205357142857142e-02*G0_4 + 1.205357142857142e-02*G0_5 + 1.205357142857144e-02*G0_6 + 1.205357142857142e-02*G0_7 + 1.205357142857145e-02*G0_8 + 1.446428571428571e-01*G0_9;
  block[4] = block[8] + 2.008928571428566e-03*G0_0 + -1.339285714285707e-03*G0_1 + -6.696428571428574e-04*G0_2 + -3.415178571428569e-02*G0_3 + 5.022321428571423e-02*G0_4 + 2.410714285714283e-02*G0_5 + 1.004464285714285e-02*G0_7 + -5.022321428571426e-02*G0_8;
  block[5] = block[8] + 6.696428571428591e-04*G0_1 + -6.696428571428604e-04*G0_2 + -3.013392857142855e-02*G0_3 + 3.013392857142854e-02*G0_4 + 4.419642857142853e-02*G0_5 + -4.017857142857144e-03*G0_6 + 4.017857142857142e-03*G0_7 + -4.419642857142855e-02*G0_8;
  block[6] = block[8] + 1.339285714285707e-03*G0_0 + 6.696428571428595e-04*G0_1 + -2.008928571428566e-03*G0_2 + -2.410714285714284e-02*G0_3 + -1.004464285714285e-02*G0_5 + 5.022321428571424e-02*G0_6 + 3.415178571428568e-02*G0_7 + -5.022321428571425e-02*G0_8;
  block[7] = block[8] + 1.339285714285704e-03*G0_0 + -1.339285714285708e-03*G0_1 + -3.013392857142855e-02*G0_3 + 6.026785714285708e-03*G0_4 + -6.026785714285708e-03*G0_5 + 3.013392857142854e-02*G0_6 + 5.424107142857140e-02*G0_7 + -5.424107142857140e-02*G0_8;
}

// No contribution from the boundary
bool LinearForm::boundary_contribution() const { return false; }

void LinearForm::eval(real block[], const AffineMap& map, unsigned int facet) const {}

} }

#endif
