virtual void
    buildAndRegisterGatherAndOrientationEvaluators(PHX::FieldManager<panzer::Traits>& fm,
					           const panzer::PhysicsBlock& side_pb,
						   const LinearObjFactory<panzer::Traits> & lof,
						   const Teuchos::ParameterList& user_data) const
    { side_pb.buildAndRegisterGatherAndOrientationEvaluators(fm,lof,user_data); 
      side_pb.buildAndRegisterDOFProjectionsToIPEvaluators(fm,user_data); }
    virtual void
    buildAndRegisterGatherAndOrientationEvaluators(PHX::FieldManager<panzer::Traits>& fm,
					           const panzer::PhysicsBlock& side_pb,
						   const LinearObjFactory<panzer::Traits> & lof,
						   const Teuchos::ParameterList& user_data) const
    { 
      using Teuchos::RCP;
      using Teuchos::rcp;

      side_pb.buildAndRegisterGatherAndOrientationEvaluators(fm,lof,user_data); 
      side_pb.buildAndRegisterDOFProjectionsToIPEvaluators(fm,Teuchos::ptrFromRef(lof),user_data); 

      // add in side normals
      const std::map<int,Teuchos::RCP<panzer::IntegrationRule> > & int_rules = side_pb.getIntegrationRules();
      for(std::map<int,Teuchos::RCP<panzer::IntegrationRule> >::const_iterator itr=int_rules.begin();
          itr!=int_rules.end();++itr) {
         
        std::stringstream s;
        s << "Side Normal:" << side_pb.cellData().side();
        Teuchos::ParameterList p(s.str());
        p.set<std::string>("Name","Side Normal");
        p.set<int>("Side ID",side_pb.cellData().side());
        p.set< Teuchos::RCP<panzer::IntegrationRule> >("IR", Teuchos::rcp_const_cast<panzer::IntegrationRule>(itr->second));
        p.set<bool>("Normalize",true);

        RCP< PHX::Evaluator<panzer::Traits> > op = rcp(new panzer::Normals<EvalT,panzer::Traits>(p));

        fm.template registerEvaluator<EvalT>(op);
      }

    }
void Example::BCStrategy_Interface_WeakDirichletMatch<EvalT>::
setup(const panzer::PhysicsBlock& side_pb,
      const Teuchos::ParameterList& user_data)
{
  using Teuchos::RCP;
  using std::vector;
  using std::string;
  using std::pair;

  const int di = this->getDetailsIndex();

  // obtain the dof name
  const string dof_name = di == 0 ? this->m_bc.equationSetName() : this->m_bc.equationSetName2();
  other_dof_name = di == 1 ? this->m_bc.equationSetName() : this->m_bc.equationSetName2();

  // need the dof value to form the residual
  this->requireDOFGather(dof_name);

  // unique residual name
  const string residual_name = "Residual_" + this->m_bc.equationSetName();
  const string diff_name = "Difference";

  const std::map<int,RCP< panzer::IntegrationRule > >& ir = side_pb.getIntegrationRules();
  TEUCHOS_ASSERT(ir.size() == 1); 
  
  const int integration_order = ir.begin()->second->order();

  this->addResidualContribution(residual_name,dof_name,diff_name,integration_order,side_pb);
}
Teuchos::RCP<panzer::IntegrationRule>
panzer::BCStrategy_Interface_DefaultImpl<EvalT>::
buildIntegrationRule(const int integration_order,const panzer::PhysicsBlock& side_pb) const
{
  TEUCHOS_ASSERT(side_pb.cellData().isSide());
  Teuchos::RCP<panzer::IntegrationRule> ir = Teuchos::rcp(new panzer::IntegrationRule(integration_order,side_pb.cellData()));
  return ir;
}
void ResponseEvaluatorFactory_ExtremeValue<EvalT,LO,GO>::
buildAndRegisterEvaluators(const std::string & responseName,
                           PHX::FieldManager<panzer::Traits> & fm,
                           const panzer::PhysicsBlock & physicsBlock,
                           const Teuchos::ParameterList & user_data) const
{
   using Teuchos::RCP;
   using Teuchos::rcp;


   // build integration evaluator (integrate over element)
   if(requiresCellExtreme_) {
     std::string field = (quadPointField_=="" ? responseName : quadPointField_);

     // build integration rule to use in cell integral
     RCP<IntegrationRule> ir = rcp(new IntegrationRule(cubatureDegree_,physicsBlock.cellData()));

     Teuchos::ParameterList pl;
     pl.set("Extreme Name",field);
     pl.set("Field Name",field);
     pl.set("IR",ir);
     pl.set("Use Max",useMax_);

     Teuchos::RCP<PHX::Evaluator<panzer::Traits> > eval 
         = Teuchos::rcp(new CellExtreme<EvalT,panzer::Traits>(pl));
 
     this->template registerEvaluator<EvalT>(fm, eval);
   }


   // build scatter evaluator
   {
     Teuchos::RCP<ExtremeValueScatterBase> scatterObj =
         (globalIndexer_!=Teuchos::null) ?  Teuchos::rcp(new ExtremeValueScatter<LO,GO>(globalIndexer_)) : Teuchos::null;
     std::string field = (quadPointField_=="" ? responseName : quadPointField_);

     // build useful evaluator
     Teuchos::RCP<PHX::Evaluator<panzer::Traits> > eval 
         = Teuchos::rcp(new ResponseScatterEvaluator_ExtremeValue<EvalT,panzer::Traits>(field,         
                                                                                        responseName,         
                                                                                        physicsBlock.cellData(),
                                                                                        useMax_,
                                                                                        scatterObj));

     this->template registerEvaluator<EvalT>(fm, eval);

     // require last field
     fm.template requireField<EvalT>(*eval->evaluatedFields()[0]);
   }
}
void Example::BCStrategy_Interface_WeakDirichletMatch<EvalT>::
buildAndRegisterGatherAndOrientationEvaluators(PHX::FieldManager<panzer::Traits>& fm,
			                       const panzer::PhysicsBlock& pb,
				               const panzer::LinearObjFactory<panzer::Traits> & lof,
				               const Teuchos::ParameterList& user_data) const
{
  using Teuchos::RCP;
  using Teuchos::rcp;
  using std::vector;
  using std::map;
  using std::string;
  using std::pair;

  // Gather
  pb.buildAndRegisterGatherAndOrientationEvaluators(fm,lof,user_data);
}
void user_app::BCStrategy_Dirichlet_Constant<EvalT>::
setup(const panzer::PhysicsBlock& side_pb,
      const Teuchos::ParameterList& user_data)
{
  using Teuchos::RCP;
  using std::vector;
  using std::string;
  using std::pair;

/*
  // need the dof value to form the residual
  this->required_dof_names.push_back(this->m_bc.equationSetName());

  // unique residual name
  this->residual_name = "Residual_" + this->m_bc.identifier();

  // map residual to dof 
  this->residual_to_dof_names_map[residual_name] = this->m_bc.equationSetName();

  // map residual to target field
  this->residual_to_target_field_map[residual_name] = "Constant_" + this->m_bc.equationSetName();
*/

  // gather the DOF
  this->addDOF(this->m_bc.equationSetName());              // DOF Name

  // add in the targert
  this->addTarget("Constant_"+this->m_bc.equationSetName(),  // Target Name
                  this->m_bc.equationSetName(),              // DOF Name
                  "Residual_"+this->m_bc.identifier());      // Residual Name

  // find the basis for this dof 
  const vector<pair<string,RCP<panzer::PureBasis> > >& dofs = side_pb.getProvidedDOFs();

  for (vector<pair<string,RCP<panzer::PureBasis> > >::const_iterator dof_it = 
	 dofs.begin(); dof_it != dofs.end(); ++dof_it) {
    if (dof_it->first == this->m_bc.equationSetName())
      this->basis = dof_it->second;
  }

  TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::is_null(this->basis), std::runtime_error,
		     "Error the name \"" << this->m_bc.equationSetName()
		     << "\" is not a valid DOF for the boundary condition:\n"
		     << this->m_bc << "\n");

}
    virtual void buildAndRegisterEvaluators(PHX::FieldManager<panzer::Traits>& fm,
					    const panzer::PhysicsBlock& side_pb,
					    const panzer::ClosureModelFactory_TemplateManager<panzer::Traits>& factory,
					    const Teuchos::ParameterList& models,
					    const Teuchos::ParameterList& user_data) const
    { 
      side_pb.buildAndRegisterEquationSetEvaluators(fm, user_data);
      side_pb.buildAndRegisterClosureModelEvaluatorsForType<EvalT>(fm,factory,models,user_data);

      for(std::size_t i=0;i<refVec_.size();i++) {
        Teuchos::RCP<const ResponseEvaluatorFactoryBase> respEvalFact = refVec_[i].second->template getAsBase<EvalT>();

        // only register evaluators if the type is supported
        if(respEvalFact->typeSupported())
          respEvalFact->buildAndRegisterEvaluators(refVec_[i].first,fm,side_pb,user_data); 
      }
    }
void populateValueArrays(std::size_t num_cells,bool isSide,const panzer::PhysicsBlock & in_pb,WorksetDetails & details)
{
  using Teuchos::RCP;
  using Teuchos::rcp;

  panzer::IntrepidFieldContainerFactory arrayFactory;

  // setup the integration rules and bases
      
  RCP<const panzer::PhysicsBlock> pb = Teuchos::rcpFromRef(in_pb);
  if(isSide) {
    const panzer::CellData side_cell_data(num_cells,
                                          details.subcell_index,
                                          in_pb.cellData().getCellTopology());
    pb = in_pb.copyWithCellData(side_cell_data);
  }

  const std::map<int,RCP<panzer::IntegrationRule> >& int_rules = pb->getIntegrationRules();

  details.ir_degrees = rcp(new std::vector<int>(0));
  details.basis_names = rcp(new std::vector<std::string>(0));

  for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
       ir_itr != int_rules.end(); ++ir_itr) {

    details.ir_degrees->push_back(ir_itr->first);
      
    RCP<panzer::IntegrationValues<double,Intrepid::FieldContainer<double> > > iv = 
        rcp(new panzer::IntegrationValues<double,Intrepid::FieldContainer<double> >);
    
    iv->setupArrays(ir_itr->second);
    iv->evaluateValues(details.cell_vertex_coordinates);
      
    details.int_rules.push_back(iv);
      
    // Need to create all combinations of basis/ir pairings 
    const std::map<std::string,Teuchos::RCP<panzer::PureBasis> >& bases = pb->getBases();
      
    for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator b_itr = bases.begin();
        b_itr != bases.end(); ++b_itr) {
	
      RCP<panzer::BasisIRLayout> b_layout = rcp(new panzer::BasisIRLayout(b_itr->second,*ir_itr->second));
      details.basis_names->push_back(b_layout->name());
      
      RCP<panzer::BasisValues<double,Intrepid::FieldContainer<double> > > bv = 
          rcp(new panzer::BasisValues<double,Intrepid::FieldContainer<double> >);
	
      bv->setupArrays(b_layout,arrayFactory);
	
      std::size_t int_degree_index = std::distance(details.ir_degrees->begin(), 
                                                   std::find(details.ir_degrees->begin(), 
                                                             details.ir_degrees->end(), 
				                             ir_itr->second->order()));
	
      bv->evaluateValues(details.int_rules[int_degree_index]->cub_points,
                         details.int_rules[int_degree_index]->jac,
                         details.int_rules[int_degree_index]->jac_det,
                         details.int_rules[int_degree_index]->jac_inv,
                         details.int_rules[int_degree_index]->weighted_measure,
                         details.cell_vertex_coordinates);

      details.bases.push_back(bv);
    }
  }
}
void panzer::BCStrategy_Interface_DefaultImpl<EvalT>::
buildAndRegisterGatherAndOrientationEvaluators(PHX::FieldManager<panzer::Traits>& fm,
			                       const panzer::PhysicsBlock& pb,
				               const panzer::LinearObjFactory<panzer::Traits> & lof,
				               const Teuchos::ParameterList& user_data) const
{
  using Teuchos::ParameterList;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using std::vector;
  using std::map;
  using std::string;
  using std::pair;

  // Gather
  pb.buildAndRegisterGatherAndOrientationEvaluators(fm,lof,user_data);

  // Iterate over each residual contribution
  for (vector<boost::tuples::tuple<std::string,std::string,std::string,int,Teuchos::RCP<panzer::PureBasis>,Teuchos::RCP<panzer::IntegrationRule> > >::const_iterator eq = 
	 m_residual_contributions.begin(); eq != m_residual_contributions.end(); ++eq) {

    const string& residual_name = eq->get<0>();
    const string& dof_name = eq->get<1>();
    const string& flux_name = eq->get<2>();
    //const int& integration_order = eq->get<3>();
    const RCP<const panzer::PureBasis> basis = eq->get<4>();
    const RCP<const panzer::IntegrationRule> ir = eq->get<5>();

    // Normals evaluator
    {
      std::stringstream s;
      s << "Side Normal:" << pb.cellData().side();
      ParameterList p(s.str());
      p.set<std::string>("Name","Side Normal");
      p.set<int>("Side ID",pb.cellData().side());
      p.set< Teuchos::RCP<panzer::IntegrationRule> >("IR", Teuchos::rcp_const_cast<panzer::IntegrationRule>(ir));
      p.set<bool>("Normalize",true);
      
      RCP< PHX::Evaluator<panzer::Traits> > op = rcp(new panzer::Normals<EvalT,panzer::Traits>(p));
      
      this->template registerEvaluator<EvalT>(fm, op);
    }

    // Interface Residual evaluator: residual += phi n dot flux
    {
      ParameterList p("Interface Residual: " + residual_name + " to DOF: " + dof_name);
      p.set("Residual Name", residual_name);
      p.set("DOF Name",dof_name);
      p.set("Flux Name", flux_name);
      p.set("Normal Name", "Side Normal");
      p.set("Basis", basis);
      p.set("IR", ir);
      
      RCP< PHX::Evaluator<panzer::Traits> > op = 
	rcp(new panzer::InterfaceResidual<EvalT,panzer::Traits>(p));
    
      this->template registerEvaluator<EvalT>(fm, op);
    }

  }
}
Teuchos::RCP<panzer::PureBasis> 
panzer::BCStrategy_Interface_DefaultImpl<EvalT>::
getBasis(const std::string dof_name,const panzer::PhysicsBlock& side_pb) const
{
  const std::vector<std::pair<std::string,Teuchos::RCP<panzer::PureBasis> > >& dofBasisPair = side_pb.getProvidedDOFs();
  Teuchos::RCP<panzer::PureBasis> basis;
  for (std::vector<std::pair<std::string,Teuchos::RCP<panzer::PureBasis> > >::const_iterator it = 
	 dofBasisPair.begin(); it != dofBasisPair.end(); ++it) {
    if (it->first == dof_name)
      basis = it->second;
  }
  
  TEUCHOS_TEST_FOR_EXCEPTION(is_null(basis), std::runtime_error,
			     "Error the name \"" << dof_name
			     << "\" is not a valid DOF for the boundary condition:\n"
			     << this->m_bc << "\n");

  return basis;
}
Teuchos::RCP< std::vector<panzer::Workset> > 
panzer::buildWorksets(const panzer::PhysicsBlock& pb,
		      const std::vector<std::size_t>& local_cell_ids,
		      const ArrayT& vertex_coordinates)
{
  using std::vector;
  using std::string;
  using Teuchos::RCP;
  using Teuchos::rcp;

  panzer::IntrepidFieldContainerFactory arrayFactory;

  std::size_t total_num_cells = local_cell_ids.size();

  std::size_t workset_size = pb.cellData().numCells();

  Teuchos::RCP< std::vector<panzer::Workset> > worksets_ptr = 
    Teuchos::rcp(new std::vector<panzer::Workset>);
  std::vector<panzer::Workset>& worksets = *worksets_ptr;
   
  // special case for 0 elements!
  if(total_num_cells==0) {

     // Setup integration rules and basis
     RCP<vector<int> > ir_degrees = rcp(new vector<int>(0));
     RCP<vector<string> > basis_names = rcp(new vector<string>(0));
      
     worksets.resize(1);
     std::vector<panzer::Workset>::iterator i = worksets.begin();
     i->num_cells = 0;
     i->block_id = pb.elementBlockID();
     i->ir_degrees = ir_degrees;
     i->basis_names = basis_names;

     const std::map<int,RCP<panzer::IntegrationRule> >& int_rules = pb.getIntegrationRules();
     
     for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
	  ir_itr != int_rules.end(); ++ir_itr) {
         
       RCP<panzer::IntegrationValues<double,Intrepid::FieldContainer<double> > > iv = 
	 rcp(new panzer::IntegrationValues<double,Intrepid::FieldContainer<double> >);
	 
       iv->setupArrays(ir_itr->second);

       ir_degrees->push_back(ir_itr->first);
       i->int_rules.push_back(iv);
     }

     const std::map<std::string,Teuchos::RCP<panzer::PureBasis> >& bases= pb.getBases();

     // Need to create all combinations of basis/ir pairings 
     for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
	  ir_itr != int_rules.end(); ++ir_itr) {

       for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator b_itr = bases.begin();
	    b_itr != bases.end(); ++b_itr) {

	 RCP<panzer::BasisIRLayout> b_layout = rcp(new panzer::BasisIRLayout(b_itr->second,*ir_itr->second));
	 
	 RCP<panzer::BasisValues<double,Intrepid::FieldContainer<double> > > bv = 
	   rcp(new panzer::BasisValues<double,Intrepid::FieldContainer<double> >);
	 
	 bv->setupArrays(b_layout,arrayFactory);

	 basis_names->push_back(b_layout->name());
	 i->bases.push_back(bv);
       }

     }

     i->details.push_back(Teuchos::rcpFromRef(*i));

     return worksets_ptr;
  } // end special case

  {
    std::size_t num_worksets = total_num_cells / workset_size;
    bool last_set_is_full = true;
    std::size_t last_workset_size = total_num_cells % workset_size;
    if (last_workset_size != 0) {
      num_worksets += 1;
      last_set_is_full = false;
    }    

    worksets.resize(num_worksets);
    std::vector<panzer::Workset>::iterator i;
    for (i = worksets.begin(); i != worksets.end(); ++i)
      i->num_cells = workset_size;
	 
    if (!last_set_is_full) {
      worksets.back().num_cells = last_workset_size;
    }
  }

  // assign workset cell local ids
  std::vector<std::size_t>::const_iterator local_begin = local_cell_ids.begin();
  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
    std::vector<std::size_t>::const_iterator begin_iter = local_begin;
    std::vector<std::size_t>::const_iterator end_iter = begin_iter + wkst->num_cells;
    local_begin = end_iter;
    wkst->cell_local_ids.assign(begin_iter,end_iter);
    wkst->cell_vertex_coordinates.resize(workset_size,
					 vertex_coordinates.dimension(1),
					 vertex_coordinates.dimension(2));
    wkst->block_id = pb.elementBlockID();
    wkst->subcell_dim = pb.cellData().baseCellDimension();
    wkst->subcell_index = 0;
    wkst->details.push_back(Teuchos::rcpFromRef(*wkst));
  }
  
  TEUCHOS_ASSERT(local_begin == local_cell_ids.end());

  // Copy cell vertex coordinates into local workset arrays
  std::size_t offset = 0;
  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
    for (std::size_t cell = 0; cell < wkst->num_cells; ++cell)
      for (std::size_t vertex = 0; vertex < Teuchos::as<std::size_t>(vertex_coordinates.dimension(1)); ++ vertex)
	for (std::size_t dim = 0; dim < Teuchos::as<std::size_t>(vertex_coordinates.dimension(2)); ++ dim)
	  wkst->cell_vertex_coordinates(cell,vertex,dim) = vertex_coordinates(cell + offset,vertex,dim);

    offset += wkst->num_cells;
  }

  TEUCHOS_ASSERT(offset == Teuchos::as<std::size_t>(vertex_coordinates.dimension(0)));
  
  // Set ir and basis arrayskset
  RCP<vector<int> > ir_degrees = rcp(new vector<int>(0));
  RCP<vector<string> > basis_names = rcp(new vector<string>(0));
  for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
    wkst->ir_degrees = ir_degrees;
    wkst->basis_names = basis_names;
  }

  const std::map<int,RCP<panzer::IntegrationRule> >& int_rules = pb.getIntegrationRules();

  for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
       ir_itr != int_rules.end(); ++ir_itr) {
    
    ir_degrees->push_back(ir_itr->first);

    for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
      
      RCP<panzer::IntegrationValues<double,Intrepid::FieldContainer<double> > > iv = 
	rcp(new panzer::IntegrationValues<double,Intrepid::FieldContainer<double> >);
    
      iv->setupArrays(ir_itr->second);
      iv->evaluateValues(wkst->cell_vertex_coordinates);
      
      wkst->int_rules.push_back(iv);

    }
  }

  const std::map<std::string,Teuchos::RCP<panzer::PureBasis> >& bases= pb.getBases();
     

  // Need to create all combinations of basis/ir pairings 

  // Loop over ir
  for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
       ir_itr != int_rules.end(); ++ir_itr) {
    
    // Loop over basis
    for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator b_itr = bases.begin();
	 b_itr != bases.end(); ++b_itr) {
      
      RCP<panzer::BasisIRLayout> b_layout = rcp(new panzer::BasisIRLayout(b_itr->second,*ir_itr->second));
      basis_names->push_back(b_layout->name());
      
      // Loop over worksets
      for (std::vector<panzer::Workset>::iterator wkst = worksets.begin(); wkst != worksets.end(); ++wkst) {
	
	RCP<panzer::BasisValues<double,Intrepid::FieldContainer<double> > > bv = 
	  rcp(new panzer::BasisValues<double,Intrepid::FieldContainer<double> >);
	
	bv->setupArrays(b_layout,arrayFactory);
	
	std::size_t int_degree_index = 
	  std::distance(ir_degrees->begin(), 
			std::find(ir_degrees->begin(), 
				  ir_degrees->end(), 
				  ir_itr->second->order()));
	
	bv->evaluateValues(wkst->int_rules[int_degree_index]->cub_points,
			   wkst->int_rules[int_degree_index]->jac,
			   wkst->int_rules[int_degree_index]->jac_det,
			   wkst->int_rules[int_degree_index]->jac_inv,
			   wkst->int_rules[int_degree_index]->weighted_measure,
			   wkst->cell_vertex_coordinates);

	wkst->bases.push_back(bv);

      }
      
    }
    
  }

  return worksets_ptr;
}
std::vector<panzer::Workset>::iterator
panzer::buildEdgeWorksets(const std::vector<std::size_t> & cell_indices,
                          const panzer::PhysicsBlock & pb_a,
	 	          const std::vector<std::size_t>& local_cell_ids_a,
		          const std::vector<std::size_t>& local_side_ids_a,
		          const ArrayT& vertex_coordinates_a,
                          const panzer::PhysicsBlock & pb_b,
	      	          const std::vector<std::size_t>& local_cell_ids_b,
		          const std::vector<std::size_t>& local_side_ids_b,
		          const ArrayT& vertex_coordinates_b,
                          std::vector<Workset>::iterator beg)
{
  std::vector<Workset>::iterator wkst = beg;
 
  std::size_t current_cell_index = 0;
  while (current_cell_index<cell_indices.size()) {
    std::size_t workset_size = pb_a.cellData().numCells();

    // allocate workset details (associate one with the workset
    // object itself)
    wkst->details.resize(2);
    wkst->details[0] = Teuchos::rcpFromRef(*wkst);
    wkst->details[1] = Teuchos::rcp(new panzer::WorksetDetails);

    wkst->subcell_dim = pb_a.cellData().baseCellDimension()-1;

    wkst->details[0]->subcell_index = local_side_ids_a[cell_indices[current_cell_index]];
    wkst->details[0]->block_id = pb_a.elementBlockID();
    wkst->details[0]->cell_vertex_coordinates.resize(workset_size,
                                                    vertex_coordinates_a.dimension(1),
                                                    vertex_coordinates_a.dimension(2));

    wkst->details[1]->subcell_index = local_side_ids_b[cell_indices[current_cell_index]];
    wkst->details[1]->block_id = pb_b.elementBlockID();
    wkst->details[1]->cell_vertex_coordinates.resize(workset_size,
                                                    vertex_coordinates_a.dimension(1),
                                                    vertex_coordinates_a.dimension(2));

    std::size_t remaining_cells = cell_indices.size()-current_cell_index;
    if(remaining_cells<workset_size)
      workset_size = remaining_cells;

    // this is the true number of cells in this workset
    wkst->num_cells = workset_size;
    wkst->details[0]->cell_local_ids.resize(workset_size);
    wkst->details[1]->cell_local_ids.resize(workset_size);

    for(std::size_t cell=0;cell<workset_size; cell++,current_cell_index++) {

      wkst->details[0]->cell_local_ids[cell] = local_cell_ids_a[cell_indices[current_cell_index]];
      wkst->details[1]->cell_local_ids[cell] = local_cell_ids_b[cell_indices[current_cell_index]];

      for (std::size_t vertex = 0; vertex < Teuchos::as<std::size_t>(vertex_coordinates_a.dimension(1)); ++ vertex) {
	for (std::size_t dim = 0; dim < Teuchos::as<std::size_t>(vertex_coordinates_a.dimension(2)); ++ dim) {
          wkst->details[0]->cell_vertex_coordinates(cell,vertex,dim) = vertex_coordinates_a(cell_indices[current_cell_index],vertex,dim);
          wkst->details[1]->cell_vertex_coordinates(cell,vertex,dim) = vertex_coordinates_b(cell_indices[current_cell_index],vertex,dim);
        }
      }
    }

    // fill the BasisValues and IntegrationValues arrays
    std::size_t max_workset_size = pb_a.cellData().numCells();
    populateValueArrays(max_workset_size,true,pb_a,*wkst->details[0]); // populate "side" values
    populateValueArrays(max_workset_size,true,pb_b,*wkst->details[1]);

    wkst++;
  }

  return wkst;
}
Teuchos::RCP< std::vector<panzer::Workset> > 
panzer::buildEdgeWorksets(const panzer::PhysicsBlock & pb_a,
	  	          const std::vector<std::size_t>& local_cell_ids_a,
		          const std::vector<std::size_t>& local_side_ids_a,
		          const ArrayT& vertex_coordinates_a,
                          const panzer::PhysicsBlock & pb_b,
		          const std::vector<std::size_t>& local_cell_ids_b,
		          const std::vector<std::size_t>& local_side_ids_b,
		          const ArrayT& vertex_coordinates_b)
{
  using std::vector;
  using std::string;
  using Teuchos::RCP;
  using Teuchos::rcp;

  panzer::IntrepidFieldContainerFactory arrayFactory;

  std::size_t total_num_cells_a = local_cell_ids_a.size();
  std::size_t total_num_cells_b = local_cell_ids_b.size();

  TEUCHOS_ASSERT(total_num_cells_a==total_num_cells_b);
  TEUCHOS_ASSERT(local_side_ids_a.size() == local_cell_ids_a.size());
  TEUCHOS_ASSERT(local_side_ids_a.size() == static_cast<std::size_t>(vertex_coordinates_a.dimension(0)));
  TEUCHOS_ASSERT(local_side_ids_b.size() == local_cell_ids_b.size());
  TEUCHOS_ASSERT(local_side_ids_b.size() == static_cast<std::size_t>(vertex_coordinates_b.dimension(0)));

  std::size_t total_num_cells = total_num_cells_a;

  std::size_t workset_size = pb_a.cellData().numCells();

  Teuchos::RCP< std::vector<panzer::Workset> > worksets_ptr = 
    Teuchos::rcp(new std::vector<panzer::Workset>);
  std::vector<panzer::Workset>& worksets = *worksets_ptr;
   
  // special case for 0 elements!
  if(total_num_cells==0) {

     // Setup integration rules and basis
     RCP<vector<int> > ir_degrees = rcp(new vector<int>(0));
     RCP<vector<string> > basis_names = rcp(new vector<string>(0));
      
     worksets.resize(1);
     std::vector<panzer::Workset>::iterator i = worksets.begin();

     i->details.resize(2);
     i->details[0] = Teuchos::rcpFromRef(*i);
     i->details[0]->block_id = pb_a.elementBlockID();
     i->details[1] = Teuchos::rcp(new panzer::WorksetDetails);
     i->details[1]->block_id = pb_b.elementBlockID();

     i->num_cells = 0;
     i->ir_degrees = ir_degrees;
     i->basis_names = basis_names;

     const std::map<int,RCP<panzer::IntegrationRule> >& int_rules = pb_a.getIntegrationRules();
     
     for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
	  ir_itr != int_rules.end(); ++ir_itr) {
         
       RCP<panzer::IntegrationValues<double,Intrepid::FieldContainer<double> > > iv = 
	 rcp(new panzer::IntegrationValues<double,Intrepid::FieldContainer<double> >);
	 
       iv->setupArrays(ir_itr->second);

       ir_degrees->push_back(ir_itr->first);
       i->int_rules.push_back(iv);
     }

     const std::map<std::string,Teuchos::RCP<panzer::PureBasis> >& bases = pb_a.getBases();

     // Need to create all combinations of basis/ir pairings 
     for (std::map<int,RCP<panzer::IntegrationRule> >::const_iterator ir_itr = int_rules.begin();
	  ir_itr != int_rules.end(); ++ir_itr) {

       for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator b_itr = bases.begin();
	    b_itr != bases.end(); ++b_itr) {

	 RCP<panzer::BasisIRLayout> b_layout = rcp(new panzer::BasisIRLayout(b_itr->second,*ir_itr->second));
	 
	 RCP<panzer::BasisValues<double,Intrepid::FieldContainer<double> > > bv = 
	   rcp(new panzer::BasisValues<double,Intrepid::FieldContainer<double> >);
	 
	 bv->setupArrays(b_layout,arrayFactory);

	 basis_names->push_back(b_layout->name());
	 i->bases.push_back(bv);
       }

     }

     return worksets_ptr;
  } // end special case

  // This collects all the elements that share the same sub cell pairs, this makes it easier to
  // build the required worksets
  // key is the pair of local face indices, value is a vector of cell indices that satisfy this pair
  std::map<std::pair<unsigned,unsigned>,std::vector<std::size_t> > element_list;
  for (std::size_t cell=0; cell < local_cell_ids_a.size(); ++cell)
    element_list[std::make_pair<unsigned,unsigned>(local_side_ids_a[cell],local_side_ids_b[cell])].push_back(cell);

  // this is the lone iterator that will be used to loop over the element edge list
  std::map<std::pair<unsigned,unsigned>,std::vector<std::size_t> >::const_iterator edge;

  // figure out how many worksets will be needed, resize workset vector accordingly
  std::size_t num_worksets = 0;
  for(edge=element_list.begin(); edge!=element_list.end();++edge) {
    std::size_t num_worksets_for_edge = edge->second.size() / workset_size;
    std::size_t last_workset_size = edge->second.size() % workset_size;
    if(last_workset_size!=0)
      num_worksets_for_edge += 1;

    num_worksets += num_worksets_for_edge;
  }
  worksets.resize(num_worksets);

  // fill the worksets
  std::vector<Workset>::iterator current_workset = worksets.begin();
  for(edge=element_list.begin(); edge!=element_list.end();++edge) {
    // loop over each workset
    const std::vector<std::size_t> & cell_indices = edge->second;
    
    current_workset = buildEdgeWorksets(cell_indices,
                                       pb_a,local_cell_ids_a,local_side_ids_a,vertex_coordinates_a,
                                       pb_b,local_cell_ids_b,local_side_ids_b,vertex_coordinates_b,
                                       current_workset);
  }

  // sanity check
  TEUCHOS_ASSERT(current_workset==worksets.end());

  return worksets_ptr;
}
Teuchos::RCP<std::map<unsigned,panzer::Workset> >
panzer::buildBCWorkset(const panzer::PhysicsBlock & volume_pb,
		       const std::vector<std::size_t>& local_cell_ids,
		       const std::vector<std::size_t>& local_side_ids,
		       const ArrayT& vertex_coordinates)
{
  using std::vector;
  using std::map;
  using std::string;
  using Teuchos::RCP;
  using Teuchos::rcp;

  // key is local face index, value is workset with all elements
  // for that local face
  Teuchos::RCP<std::map<unsigned,panzer::Workset> > worksets_ptr = 
    Teuchos::rcp(new std::map<unsigned,panzer::Workset>);

  // All elements of boundary condition should go into one workset.
  // However due to design of Intrepid (requires same basis for all
  // cells), we have to separate the workset based on the local side
  // index.  Each workset for a boundary condition is associated with
  // a local side for the element
  
  // std::cout << "local_side_ids.size() = " << local_side_ids.size() 
  // 	    << std::endl;

  TEUCHOS_ASSERT(local_side_ids.size() == local_cell_ids.size());
  TEUCHOS_ASSERT(local_side_ids.size() == static_cast<std::size_t>(vertex_coordinates.dimension(0)));

  // key is local face index, value is a pair of cell index and vector of element local ids
  std::map<unsigned,std::vector<std::pair<std::size_t,std::size_t> > > element_list;
  for (std::size_t cell=0; cell < local_cell_ids.size(); ++cell)
    element_list[local_side_ids[cell]].push_back(std::make_pair(cell,local_cell_ids[cell])); 

  std::map<unsigned,panzer::Workset>& worksets = *worksets_ptr;

  // create worksets 
  std::map<unsigned,std::vector<std::pair<std::size_t,std::size_t> > >::const_iterator side;
  for (side = element_list.begin(); side != element_list.end(); ++side) {

    std::vector<std::size_t>& cell_local_ids = worksets[side->first].cell_local_ids;
    Intrepid::FieldContainer<double> & coords = worksets[side->first].cell_vertex_coordinates;
    coords.resize(side->second.size(),vertex_coordinates.dimension(1),vertex_coordinates.dimension(2));
    for (std::size_t cell = 0; cell < side->second.size(); ++cell) {
      cell_local_ids.push_back(side->second[cell].second);

      for (std::size_t vertex = 0; vertex < Teuchos::as<std::size_t>(vertex_coordinates.dimension(1)); ++ vertex)
	for (std::size_t dim = 0; dim < Teuchos::as<std::size_t>(vertex_coordinates.dimension(2)); ++ dim)
	  coords(cell,vertex,dim) = vertex_coordinates(side->second[cell].first,vertex,dim);
    }
    worksets[side->first].num_cells = worksets[side->first].cell_local_ids.size();
    worksets[side->first].block_id = volume_pb.elementBlockID();
    worksets[side->first].subcell_dim = volume_pb.cellData().baseCellDimension() - 1;
    worksets[side->first].subcell_index = side->first;
    worksets[side->first].details.push_back(Teuchos::rcpFromRef(worksets[side->first]));
  }

  // setup the integration rules and bases
  for (std::map<unsigned,panzer::Workset>::iterator wkst = worksets.begin();
       wkst != worksets.end(); ++wkst) {

    populateValueArrays(wkst->second.num_cells,true,volume_pb,wkst->second); // populate "side" values
  }

  return worksets_ptr;
}
void Example::BCStrategy_Interface_WeakDirichletMatch<EvalT>::
buildAndRegisterEvaluators(PHX::FieldManager<panzer::Traits>& fm,
			   const panzer::PhysicsBlock& pb,
			   const panzer::ClosureModelFactory_TemplateManager<panzer::Traits>& factory,
			   const Teuchos::ParameterList& models,
			   const Teuchos::ParameterList& user_data) const
{
  using Teuchos::ParameterList;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using std::string; 

  const std::vector<boost::tuples::tuple<string,string,string,int,Teuchos::RCP<panzer::PureBasis>,
    Teuchos::RCP<panzer::IntegrationRule> > > data = this->getResidualContributionData();

  string residual_name = data[0].get<0>();
  string dof_name = data[0].get<1>();
  string diff_name = data[0].get<2>();

  RCP<panzer::IntegrationRule> ir = data[0].get<5>();
  RCP<const panzer::FieldLayoutLibrary> fll = pb.getFieldLibrary()->buildFieldLayoutLibrary(*ir);
  RCP<panzer::BasisIRLayout> basis = fll->lookupLayout(dof_name);

  if (this->getDetailsIndex() == 0) {
    const std::string
      dof_grad_name = dof_name + "_gradient",
      cancel_natural_name = dof_name + "_cancel",
      my_normal_name = "My_Normal",
      sum_contributions_name = "Sum_Contributions";
    // Weak Dirichlet match.
    {
      { // Get values on my side.
        ParameterList p("My DOF");
        p.set("Name", dof_name);
        p.set("Basis", basis); 
        p.set("IR", ir);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::DOF<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
      { // Other DOF - my DOF.
        ParameterList p("other DOF - my DOF");
        p.set("Sum Name", diff_name);
        setSumValues(p, other_dof_name, 1, dof_name, -1);
        p.set("Data Layout", ir->dl_scalar);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::Sum<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
    }
    // Cancel my natural (Neumann) BC.
    {
      { // Normal.
        ParameterList p("My Side Normal");
        p.set("Name", my_normal_name);
        p.set("Side ID", pb.cellData().side());
        p.set("IR", ir);
        p.set("Normalize", true);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::Normals<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
      { // Gradient.
        ParameterList p("My DOF gradient");
        p.set("Name", dof_name);
        p.set("Gradient Name", dof_grad_name);
        p.set("Basis", basis); 
        p.set("IR", ir);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::DOFGradient<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
      { // dot(DOF gradient, normal).
        ParameterList p("dot(my DOF gradient, my normal)");
        p.set("Result Name", cancel_natural_name);
        p.set("Vector A Name", dof_grad_name);
        p.set("Vector B Name", my_normal_name);
        p.set("Point Rule", Teuchos::rcp_dynamic_cast<const panzer::PointRule>(ir));
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::DotProduct<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
    }
    // Add contributions to the residual.
    {
      { // Weak Dirichlet Match + Cancel Neumann
        ParameterList p("Weak Dirichlet Match + Cancel Neumann");
        p.set("Sum Name", sum_contributions_name);
        setSumValues(p, diff_name, 1e5, cancel_natural_name, -1);
        p.set("Data Layout", ir->dl_scalar);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::Sum<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
      {
        ParameterList p("Weak Dirichlet Match And Cancel Neumann Residual");
        p.set("Residual Name", residual_name);
        p.set("Value Name", sum_contributions_name);
        p.set("Basis", basis);
        p.set("IR", ir);
        p.set("Multiplier", 1.0);
        const RCP< PHX::Evaluator<panzer::Traits> >
          op = rcp(new panzer::Integrator_BasisTimesScalar<EvalT,panzer::Traits>(p));
        this->template registerEvaluator<EvalT>(fm, op);
      }
    }
  } else {
    { // Get values on other side.
      ParameterList p("Other DOF");
      p.set("Name", dof_name);
      p.set("Basis", basis); 
      p.set("IR", ir);
      const RCP< PHX::Evaluator<panzer::Traits> >
        op = rcp(new panzer::DOF<EvalT,panzer::Traits>(p));
      this->template registerEvaluator<EvalT>(fm, op);
    }
  }
}