void panzer::GatherTangents<EvalT, Traits>::
evaluateFields(typename Traits::EvalData workset)
{ 

  if(workset.num_cells<=0)
    return;
  else {
    const shards::CellTopology & parentCell = *basis->getCellTopology();
    int cellDim = parentCell.getDimension();
    int numEdges = gatherFieldTangents.dimension(1);

    refEdgeTan = Intrepid2::FieldContainer<ScalarT>(numEdges,cellDim);

    for(int i=0;i<numEdges;i++) {
      Intrepid2::FieldContainer<double> refEdgeTan_local(cellDim);
      Intrepid2::CellTools<double>::getReferenceEdgeTangent(refEdgeTan_local, i, parentCell);

      for(int d=0;d<cellDim;d++)
        refEdgeTan(i,d) = refEdgeTan_local(d);
    }

    // Loop over workset faces and edge points
    for(std::size_t c=0;c<workset.num_cells;c++) {
      for(int pt = 0; pt < numEdges; pt++) {

        // Apply parent cell Jacobian to ref. edge tangent
        for(int i = 0; i < cellDim; i++) {
          edgeTan(c, pt, i) = 0.0;
          for(int j = 0; j < cellDim; j++){
            edgeTan(c, pt, i) +=  pointValues.jac(c, pt, i, j)*refEdgeTan(pt,j);
          }// for j
        }// for i
      }// for pt
    }// for pCell

    // Multiply tangent by orientation
    for(std::size_t c=0;c<workset.num_cells;c++) {
      for(int b=0;b<gatherFieldTangents.dimension(1);b++) {
        for(int d=0;d<gatherFieldTangents.dimension(2);d++) {
          gatherFieldTangents(c,b,d) = edgeTan(c,b,d)*dof_orientation(c,b); 
        }
      }
    }
  }

}
//**********************************************************************
PHX_EVALUATE_FIELDS(DirichletResidual_EdgeBasis,workset)
{ 
  if(workset.num_cells<=0)
    return;

  residual.deep_copy(ScalarT(0.0));

  if(workset.subcell_dim==1) {
    Intrepid2::CellTools<ScalarT>::getPhysicalEdgeTangents(edgeTan,
                                            pointValues.jac,
                                            this->wda(workset).subcell_index, 
                                           *basis->getCellTopology());

    for(std::size_t c=0;c<workset.num_cells;c++) {
      for(int b=0;b<dof.dimension(1);b++) {
        for(int d=0;d<dof.dimension(2);d++)
          residual(c,b) += (dof(c,b,d)-value(c,b,d))*edgeTan(c,b,d);
      } 
    }
  }
  else if(workset.subcell_dim==2) {
    // we need to compute the tangents on each edge for each cell.
    // how do we do this????
    const shards::CellTopology & parentCell = *basis->getCellTopology();
    int cellDim = parentCell.getDimension();
    int numEdges = dof.dimension(1);

    refEdgeTan = Kokkos::createDynRankView(residual.get_kokkos_view(),"refEdgeTan",numEdges,cellDim);

    for(int i=0;i<numEdges;i++) {
      Kokkos::DynRankView<double,PHX::Device> refEdgeTan_local("refEdgeTan_local",cellDim);
      Intrepid2::CellTools<double>::getReferenceEdgeTangent(refEdgeTan_local, i, parentCell);

      for(int d=0;d<cellDim;d++) 
        refEdgeTan(i,d) = refEdgeTan_local(d);
    }

    // Loop over workset faces and edge points
    for(std::size_t c=0;c<workset.num_cells;c++) {
      for(int pt = 0; pt < numEdges; pt++) {

        // Apply parent cell Jacobian to ref. edge tangent
        for(int i = 0; i < cellDim; i++) {
          edgeTan(c, pt, i) = 0.0;
          for(int j = 0; j < cellDim; j++){
            edgeTan(c, pt, i) +=  pointValues.jac(c, pt, i, j)*refEdgeTan(pt,j);
          }// for j
        }// for i
      }// for pt
    }// for pCell

    for(std::size_t c=0;c<workset.num_cells;c++) {
      for(int b=0;b<dof.dimension(1);b++) {
        for(int d=0;d<dof.dimension(2);d++)
          residual(c,b) += (dof(c,b,d)-value(c,b,d))*edgeTan(c,b,d);
      } 
    }

  }
  else {
    // don't know what to do 
    TEUCHOS_ASSERT(false);
  }

  // loop over residuals scaling by orientation. This gurantees
  // everything is oriented in the "positive" direction, this allows
  // sums acrossed processor to be oriented in the same way (right?)
  for(std::size_t c=0;c<workset.num_cells;c++) {
    for(int b=0;b<dof.dimension(1);b++) {
      residual(c,b) *= dof_orientation(c,b);
    }
  }
}