bool SpatialDerivSpecifier::operator<(const SpatialDerivSpecifier& other) const
{
  if (type() < other.type()) return true;
  if (type() > other.type()) return false;

  if (isPartial()) return mi() < other.mi();
  if (isNormal()) return normalDerivOrder() < other.normalDerivOrder();

  return false;
}
void Legendre::refEval(
  const CellType& cellType,
  const Array<Point>& pts,
  const SpatialDerivSpecifier& sds,
  Array<Array<Array<double> > >& result,
  int verbosity) const
{
  TEUCHOS_TEST_FOR_EXCEPTION(!(sds.isPartial() || sds.isIdentity()), 
    std::runtime_error,
    "cannot evaluate spatial derivative " << sds << " on Legendre basis");
  const MultiIndex& deriv = sds.mi();
  typedef Array<double> Adouble;
  result.resize(1);
  result[0].resize(pts.length());

  switch(cellType)
  {
    case PointCell:
      result[0] = tuple<Adouble>(tuple(1.0));
      return;
    case LineCell:
      for (int i=0; i<pts.length(); i++)
      {
        evalOnLine(pts[i], deriv, result[0][i]);
      }
      return;
    case QuadCell:
      for (int i=0; i<pts.length(); i++)
      {
        evalOnQuad(pts[i], deriv, result[0][i]);
      }
      return;
    case BrickCell:
      for (int i=0; i<pts.length(); i++)
      {
        evalOnBrick(pts[i], deriv, result[0][i]);
      }
      return;
    default:
      TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error,
        "Legendre::refEval() unimplemented for cell type "
        << cellType);

  }
}
void EdgeLocalizedBasis::refEval(
  const CellType& cellType,
  const Array<Point>& pts,
  const SpatialDerivSpecifier& sds,
  Array<Array<Array<double> > >& result,
  int verbosity) const
{
  TEUCHOS_TEST_FOR_EXCEPTION(!(sds.isPartial() || sds.isIdentity()), 
    std::runtime_error,
    "cannot evaluate spatial derivative " << sds << " on EdgeLocalizedBasis basis");
  const MultiIndex& deriv = sds.mi();
  typedef Array<double> Adouble;
  result.resize(1);
  result[0].resize(pts.length());

  int dim = dimension(cellType);
  
  if (dim==0)
  {
    result[0] = tuple<Adouble>(tuple(1.0));
  }
  else if (dim==1)
  {
    for (int i=0; i<pts.length(); i++)
    {
      evalOnLine(pts[i], deriv, result[0][i]);
    }
  }
  else if (dim==2)
  {
    for (int i=0; i<pts.length(); i++)
    {
      evalOnTriangle(pts[i], deriv, result[0][i]);
    }
  }
  else if (dim==3)
  {
    for (int i=0; i<pts.length(); i++)
    {
      evalOnTet(pts[i], deriv, result[0][i]);
    }
  }
}
void RaviartThomas::refEval(
  const CellType& cellType,
  const Array<Point>& pts,
  const SpatialDerivSpecifier& sds,
  Array<Array<Array<double> > >& result,
  int verbosity) const
{
  const MultiIndex& deriv = sds.mi();
  switch(cellType) {
    case PointCell:
    {
      TEST_FOR_EXCEPTION(true, RuntimeError, "evaluation of RaviartThomas elements for PointCell not supported");
    }
    break;
    case LineCell:
    {
      result.resize(1);
      result[0].resize(pts.length());
      Array<ADReal> tmp;
      tmp.resize(2);
      for (int i=0;i<pts.length();i++) {
        ADReal x = ADReal( pts[i][0] , 0 , 1 );
        ADReal one(1.0,1);
        result[0][i].resize(2);
        tmp[0] = one - x;
        tmp[1] = x;
        if (deriv.order()==0) {
          for (int j=0;j<tmp.length();j++) {
            result[0][i][j] = tmp[j].value();
          }
        }
        else {
          for (int j=0;j<tmp.length();j++) {
            result[0][i][j] = tmp[j].gradient()[deriv.firstOrderDirection()];
          }
        }
      }
    }
    break;
    case TriangleCell:
    {
      result.resize(2);
      result[0].resize(pts.length());
      result[1].resize(pts.length());
      Array<ADReal> tmp0;
      Array<ADReal> tmp1;
      tmp0.resize(3);
      tmp1.resize(3);
      for (int i=0;i<pts.length();i++) {
        ADReal x = ADReal(pts[i][0],0,2);
        ADReal y = ADReal(pts[i][1],1,2);
        ADReal one(1.0,2);
        ADReal rt2(std::sqrt(2.0),2);
        result[0][i].resize(3);
        result[1][i].resize(3);
        tmp0[0] = x;
        tmp1[0] = y - one;
        tmp0[1] = rt2 * x;
        tmp1[1] = rt2 * y;
        tmp0[2] = x - one;
        tmp1[2] = y;
        if (deriv.order()==0) {
          for (int j=0;j<tmp0.length();j++) {
            result[0][i][j] = tmp0[j].value();
            result[1][i][j] = tmp1[j].value();
          }
        }
        else {
          for (int j=0;j<tmp0.length();j++) {
            result[0][i][j] = tmp0[j].gradient()[deriv.firstOrderDirection()];
            result[1][i][j] = tmp1[j].gradient()[deriv.firstOrderDirection()];
          }
        }
      }
    }
    break;
    case TetCell:
    {
      TEST_FOR_EXCEPTION(true, RuntimeError, "evaluation of RaviartThomas elements for TetCell not supported");
    }
    break;
    default:
      TEST_FOR_EXCEPTION(true, RuntimeError, "evaluation of RaviartThomas elements unknown cell type");
      break;
  }

  return;
}