Basis_HGRAD_LINE_Hermite_FEM<Scalar,ArrayScalar>::Basis_HGRAD_LINE_Hermite_FEM() : 
    latticePts_(2,1) {
    this->basisCardinality_  = 4;    // Four basis functions
    this->basisDegree_       = 3;    // Cubic polynomials
    this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Line<2> >() );
    this->basisType_         = BASIS_FEM_DEFAULT;
    this->basisCoordinates_  = COORDINATES_CARTESIAN;
    this->basisTagsAreSet_   = false;

    latticePts_(0,0) = -1.0;
    latticePts_(1,0) =  1.0;
 
    setupVandermonde();

} // no-arg constructor
  void Basis_HGRAD_LINE_Cn_FEM<Scalar,ArrayScalar>::getDofCoords( ArrayScalar & dofCoords ) const
  {
    for (int i=0;i<latticePts_.dimension(0);i++)
      {
	for (int j=0;j<latticePts_.dimension(1);j++)
	  {
	    dofCoords(i,j) = latticePts_(i,j);
	  }
      }
    return;
  }
Basis_HGRAD_LINE_Hermite_FEM<Scalar,ArrayScalar>::Basis_HGRAD_LINE_Hermite_FEM( const ArrayScalar &pts) : 
    latticePts_( pts.dimension(0), 1 ) {

    int n = pts.dimension(0);

    this->basisCardinality_  = 2*n;                   
    this->basisDegree_       = 2*n-1;    
    this->basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Line<2> >() );
    this->basisType_         = BASIS_FEM_DEFAULT;
    this->basisCoordinates_  = COORDINATES_CARTESIAN;
    this->basisTagsAreSet_   = false;

    for( int i=0; i<n-1; ++i ) {
      TEUCHOS_TEST_FOR_EXCEPTION( pts(i,0) >= pts(i+1,0), std::runtime_error ,
        "Intrepid::Basis_HGRAD_LINE_Hermite_FEM Illegal points given to constructor" );
    }  

    // copy points int latticePts, correcting endpoints if needed
    if (std::abs(pts(0,0)+1.0) < INTREPID_TOL) {
      latticePts_(0,0) = -1.0;
    }
    else {
      latticePts_(0,0) = pts(0,0);
    }
    for (int i=1;i<n-1;i++) {
      latticePts_(i,0) = pts(i,0);
    }
    if (std::abs(pts(n-1,0)-1.0) < INTREPID_TOL) {
      latticePts_(n-1,0) = 1.0;
    }
    else {
      latticePts_(n-1,0) = pts(n-1,0);
    }  

    setupVandermonde();

} // Constructor with points given
void Basis_HGRAD_LINE_Hermite_FEM<Scalar,ArrayScalar>::setupVandermonde( bool factor  ) {

    initializeTags();

    int nBf = this->getCardinality();
    int n   = nBf/2;

    V_.shape(nBf,nBf);

    // Make containers to store the Legendre polynomials and their derivatives
    // at a given point 
    ArrayScalar P ( nBf );
    ArrayScalar Px( nBf );

    // Loop over grid points
    for( int i=0; i<n; ++i ) {

      recurrence(P,Px,latticePts_(i,0));
      
      // Loop over basis functions     
      for(int j=0; j<nBf; ++j ) {
        V_(j, i  ) = P (j);
        V_(j, i+n) = Px(j); 
      }
    }

    solver_.setMatrix(Teuchos::rcpFromRef(V_));

    if(factor) {
      solver_.factorWithEquilibration(true);
      solver_.factor();
      isFactored_ = true;
    }
    else {
      isFactored_ = false;
    }

}
  Basis_HGRAD_LINE_Cn_FEM<Scalar,ArrayScalar>::Basis_HGRAD_LINE_Cn_FEM( const int n ,
									const ArrayScalar &pts ):
    latticePts_( n+1 , 1 ),
    Phis_( n ),
    V_(n+1,n+1),
    Vinv_(n+1,n+1)
  {
    const int N = n+1;
    this -> basisCardinality_  = N;
    this -> basisDegree_       = n;
    this -> basisCellTopology_ = shards::CellTopology(shards::getCellTopologyData<shards::Line<2> >() );
    this -> basisType_         = BASIS_FEM_FIAT;
    this -> basisCoordinates_  = COORDINATES_CARTESIAN;
    this -> basisTagsAreSet_   = false;


    // check validity of points
    for (int i=0;i<n;i++) {
      TEUCHOS_TEST_FOR_EXCEPTION( pts(i,0) >= pts(i+1,0) ,
			  std::runtime_error ,
			  "Intrepid2::Basis_HGRAD_LINE_Cn_FEM Illegal points given to constructor" );
    }

    // copy points int latticePts, correcting endpoints if needed
    if (std::abs(pts(0,0)+1.0) < INTREPID_TOL) {
      latticePts_(0,0) = -1.0;
    }
    else {
      latticePts_(0,0) = pts(0,0);
    }
    for (int i=1;i<n;i++) {
      latticePts_(i,0) = pts(i,0);
    }
    if (std::abs(pts(n,0)-1.0) < INTREPID_TOL) {
      latticePts_(n,0) = 1.0;
    }
    else {
      latticePts_(n,0) = pts(n,0);
    }
    
    // form Vandermonde matrix.  Actually, this is the transpose of the VDM,
    // so we transpose on copy below.
  
    Phis_.getValues( V_ , latticePts_ , OPERATOR_VALUE );

    // now I need to copy V into a Teuchos array to do the inversion
    Teuchos::SerialDenseMatrix<int,Scalar> Vsdm(N,N);
    for (int i=0;i<N;i++) {
      for (int j=0;j<N;j++) {
        Vsdm(i,j) = V_(i,j);
      }
    }

    // invert the matrix
    Teuchos::SerialDenseSolver<int,Scalar> solver;
    solver.setMatrix( rcp( &Vsdm , false ) );
    solver.invert( );

    // now I need to copy the inverse into Vinv
    for (int i=0;i<N;i++) {
      for (int j=0;j<N;j++) {
        Vinv_(i,j) = Vsdm(j,i);
      }
    }

  }  
  void Basis_HGRAD_LINE_Cn_FEM<Scalar, ArrayScalar>::initializeTags() {
  
    // Basis-dependent initializations
    int tagSize  = 4;        // size of DoF tag, i.e., number of fields in the tag
    int posScDim = 0;        // position in the tag, counting from 0, of the subcell dim 
    int posScOrd = 1;        // position in the tag, counting from 0, of the subcell ordinal
    int posDfOrd = 2;        // position in the tag, counting from 0, of DoF ordinal relative to the subcell
  
    // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration 

    int *tags = new int[ tagSize * this->getCardinality() ];

    int internal_dof;
    int edge_dof;

    const int n = this->getDegree();

    // now we check the points for association 
    if (latticePts_(0,0) == -1.0) {
      tags[0] = 0;
      tags[1] = 0;
      tags[2] = 0;
      tags[3] = 1;
      edge_dof = 1;
      internal_dof = n-1;
    }
    else {
      tags[0] = 1;
      tags[1] = 0;
      tags[2] = 0;
      tags[3] = n+1;
      edge_dof = 0;
      internal_dof = n+1;
    }
    for (int i=1;i<n;i++) {
      tags[4*i] = 1;
      tags[4*i+1] = 0;
      tags[4*i+2] = -edge_dof + i;
      tags[4*i+3] = internal_dof;
    }
    if (latticePts_(n,0) == 1.0) {
      tags[4*n] = 0;
      tags[4*n+1] = 1;
      tags[4*n+2] = 0;
      tags[4*n+3] = 1;
    }
    else {
      tags[4*n] = 1;
      tags[4*n+1] = 0;
      tags[4*n+2] = n;
      tags[4*n+3] = n;
    }	 
    
    Intrepid2::setOrdinalTagData(this -> tagToOrdinal_,
                                this -> ordinalToTag_,
                                tags,
                                this -> basisCardinality_,
                                tagSize,
                                posScDim,
                                posScOrd,
                                posDfOrd);

    delete []tags;
  
  }  
void Basis_HGRAD_LINE_Hermite_FEM<Scalar, ArrayScalar>::initializeTags() {

  // Basis-dependent intializations
  int tagSize  = 4;        // size of DoF tag, i.e., number of fields in the tag
  int posScDim = 0;        // position in the tag, counting from 0, of the subcell dim 
  int posScOrd = 1;        // position in the tag, counting from 0, of the subcell ordinal
  int posDfOrd = 2;        // position in the tag, counting from 0, of DoF ordinal relative to the subcell
    
  // An array with local DoF tags assigned to the basis functions, in the order of their local enumeration 

  int C = this->getCardinality();
  tags_.reserve( tagSize * C );

  int n = C/2;

  int hasLeftVertex  = static_cast<int>( latticePts_(0  , 0)  == -1.0 );
  int hasRightVertex = static_cast<int>( latticePts_(n-1, 0)  ==  1.0 );

  int internal_dof = C - 2*(hasLeftVertex+hasRightVertex);

  if( hasLeftVertex ) {

    // Value interpolant 
    tags_[0] = 0;               //  this is a vertex (interval end point)
    tags_[1] = 0;               //  this is the first subcell
    tags_[2] = 0;               //  this is the first DoF for this vertex
    tags_[3] = 2;               //  this vertex has 2 DoF

    // Derivative interpolant 
    tags_[4] = 0;                //  this is a vertex (interval end point)
    tags_[5] = 0;                //  this is the first subcell  
    tags_[6] = 1;                //  this is the second DoF for this vertex
    tags_[7] = 2;                //  this vertex has 2 DoF

  }
  else { // no left vertex

    // Value interpolant 
    tags_[0] = 1;                     // this point is on a line  
    tags_[1] = 0;                     // no subcells
    tags_[2] = 0;                     // this is the first DoF for this line
    tags_[3] = C-2*hasRightVertex;    // this cell has 2n DoF

    // Derivative interpolant 
    tags_[4] = 1;                     // this point is on a line  
    tags_[5] = 0;                     // no subcells
    tags_[6] = 1;                     // this is the second DoF for this line
    tags_[7] = C-2*hasRightVertex;    // this cell has 2n DoF
  } 

  if( hasRightVertex ) {
    int i0 = C-2; 
    int i1 = C-1;
    
    // Value interpolant 
    tags_[4*i0  ] = 0;                      
    tags_[4*i0+1] = hasLeftVertex;        
    tags_[4*i0+2] = 0;                          
    tags_[4*i0+3] = 2;                         

    // Derivative interpolant 
    tags_[4*i1  ] = 0;   
    tags_[4*i1+1] = hasLeftVertex; 
    tags_[4*i1+2] = 1;   
    tags_[4*i1+3] = 2;   
  }
  else { // no right vertex 
    int i0 = C-2; 
    int i1 = C-1;
    
    // Value interpolant 
    tags_[4*i0  ] = 1;                      
    tags_[4*i0+1] = 0;        
    tags_[4*i0+2] = internal_dof-2;
    tags_[4*i0+3] = internal_dof;                         

    // Derivative interpolant 
    tags_[4*i1  ] = 1;      
    tags_[4*i1+1] = 0;      
    tags_[4*i1+2] = internal_dof-1;      
    tags_[4*i1+3] = internal_dof;   
  }

  for( int i=1; i<n-1; ++i ) {
    int i0 = 2*i; int i1 = 2*i+1;

    // Value interpolant 
    tags_[4*i0  ] = 1;  // Points on a line (1 dimensional)
    tags_[4*i0+1] = 0;
    tags_[4*i0+2] = i0 - 2*hasLeftVertex;
    tags_[4*i0+3] = internal_dof;

    // Derivative interpolant 
    tags_[4*i1  ] = 1;
    tags_[4*i1+1] = 0;
    tags_[4*i1+2] = i1 - 2*hasLeftVertex;
    tags_[4*i1+3] = internal_dof;
  }

  // Basis-independent function sets tag and enum data in tagToOrdinal_ and ordinalToTag_ arrays:
  Intrepid::setOrdinalTagData(this -> tagToOrdinal_,
                              this -> ordinalToTag_,
                              tags_.data(),
                              this -> basisCardinality_,
                              tagSize,
                              posScDim,
                              posScOrd,
                              posDfOrd);

}