void PHX::registerEvaluators(const Teuchos::RCP< std::vector< Teuchos::RCP<PHX::Evaluator_TemplateManager<Traits> > > >& providers, PHX::FieldManager<Traits>& fm)
{
  // Loop over each provider template manager
  typename std::vector< Teuchos::RCP<Evaluator_TemplateManager<Traits> > >::iterator 
    tm = providers->begin();
  for (; tm != providers->end(); ++tm) {
    
    // Loop over Evaluation Types
    typename PHX::FieldManager<Traits>::iterator vmit = fm.begin();
    typename Evaluator_TemplateManager<Traits>::iterator vpit = 
      (*tm)->begin();
    for (; vpit != (*tm)->end(); ++vpit) {
      Teuchos::RCP<PHX::Evaluator<Traits> > vp =
	Teuchos::rcp_dynamic_cast<PHX::Evaluator<Traits> >(vpit.rcp());
      fm.registerEvaluator(vmit, vp);
      ++vmit;
    } 
  }

}
int
main(int ac, char* av[])
{
  KokkosGuard kokkos(ac, av);

  typedef PHX::MDField<PHAL::AlbanyTraits::Residual::ScalarT>::size_type
                                                size_type;
  typedef PHAL::AlbanyTraits::Residual          Residual;
  typedef PHAL::AlbanyTraits::Residual::ScalarT ScalarT;
  typedef PHAL::AlbanyTraits                    Traits;
  std::cout.precision(15);
  //
  // Create a command line processor and parse command line options
  //
  Teuchos::CommandLineProcessor command_line_processor;

  command_line_processor.setDocString(
      "Material Point Simulator.\n"
      "For testing material models in LCM.\n");

  std::string input_file = "materials.xml";
  command_line_processor.setOption("input", &input_file, "Input File Name");

  std::string timing_file = "timing.csv";
  command_line_processor.setOption("timing", &timing_file, "Timing File Name");

  int workset_size = 1;
  command_line_processor.setOption("wsize", &workset_size, "Workset Size");

  int num_pts = 1;
  command_line_processor.setOption(
      "npoints", &num_pts, "Number of Gaussian Points");

  size_t memlimit = 1024;  // 1GB heap limit by default
  command_line_processor.setOption(
      "memlimit", &memlimit, "Heap memory limit in MB for CUDA kernels");

  // Throw a warning and not error for unrecognized options
  command_line_processor.recogniseAllOptions(true);

  // Don't throw exceptions for errors
  command_line_processor.throwExceptions(false);

  // Parse command line
  Teuchos::CommandLineProcessor::EParseCommandLineReturn parse_return =
      command_line_processor.parse(ac, av);

  std::ofstream tout(timing_file.c_str());

  if (parse_return == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED) {
    return 0;
  }

  if (parse_return != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL) {
    return 1;
  }

  util::TimeMonitor& tmonitor =
      util::PerformanceContext::instance().timeMonitor();
  Teuchos::RCP<Teuchos::Time> total_time   = tmonitor["MPS: Total Time"];
  Teuchos::RCP<Teuchos::Time> compute_time = tmonitor["MPS: Compute Time"];

  //
  // Process material.xml file
  // Read into materialDB and get material model name
  //

  // A mpi object must be instantiated before using the comm to read
  // material file
  Teuchos::GlobalMPISession        mpi_session(&ac, &av);
  Teuchos::RCP<const Teuchos_Comm> commT =
      Albany::createTeuchosCommFromMpiComm(Albany_MPI_COMM_WORLD);

  Teuchos::RCP<Albany::MaterialDatabase> material_db;
  material_db = Teuchos::rcp(new Albany::MaterialDatabase(input_file, commT));

  // Get the name of the material model to be used (and make sure there is one)
  std::string element_block_name = "Block0";
  std::string material_model_name;
  material_model_name =
      material_db->getElementBlockSublist(element_block_name, "Material Model")
          .get<std::string>("Model Name");
  TEUCHOS_TEST_FOR_EXCEPTION(
      material_model_name.length() == 0,
      std::logic_error,
      "A material model must be defined for block: " + element_block_name);

  //
  // Preloading stage setup
  // set up evaluators, create field and state managers
  //

  // Set up the data layout
  // const int workset_size = 1;
  const int                           num_dims     = 3;
  const int                           num_vertices = 8;
  const int                           num_nodes    = 8;
  const Teuchos::RCP<Albany::Layouts> dl = Teuchos::rcp(new Albany::Layouts(
      workset_size, num_vertices, num_nodes, num_pts, num_dims));

  // create field name strings
  LCM::FieldNameMap                                field_name_map(false);
  Teuchos::RCP<std::map<std::string, std::string>> fnm =
      field_name_map.getMap();

  //---------------------------------------------------------------------------
  // Deformation gradient
  // initially set the deformation gradient to the identity

  Teuchos::ArrayRCP<ScalarT> def_grad(workset_size * num_pts * 9);
  for (int i = 0; i < workset_size; ++i) {
    for (int j = 0; j < num_pts; ++j) {
      int base = i * num_pts * 9 + j * 9;
      for (int k = 0; k < 9; ++k) def_grad[base + k] = 0.0;

      def_grad[base + 0] = 1.0;
      def_grad[base + 4] = 1.0;
      def_grad[base + 8] = 1.0;
    }
  }
  // SetField evaluator, which will be used to manually assign a value
  // to the def_grad field
  Teuchos::ParameterList setDefGradP("SetFieldDefGrad");
  setDefGradP.set<std::string>("Evaluated Field Name", "F");
  setDefGradP.set<Teuchos::RCP<PHX::DataLayout>>(
      "Evaluated Field Data Layout", dl->qp_tensor);
  setDefGradP.set<Teuchos::ArrayRCP<ScalarT>>("Field Values", def_grad);
  auto setFieldDefGrad =
      Teuchos::rcp(new LCM::SetField<Residual, Traits>(setDefGradP));

  //---------------------------------------------------------------------------
  // Det(deformation gradient)
  Teuchos::ArrayRCP<ScalarT> detdefgrad(workset_size * num_pts);
  for (int i = 0; i < workset_size * num_pts; ++i) detdefgrad[i] = 1.0;
  // SetField evaluator, which will be used to manually assign a value
  // to the detdefgrad field
  Teuchos::ParameterList setDetDefGradP("SetFieldDetDefGrad");
  setDetDefGradP.set<std::string>("Evaluated Field Name", "J");
  setDetDefGradP.set<Teuchos::RCP<PHX::DataLayout>>(
      "Evaluated Field Data Layout", dl->qp_scalar);
  setDetDefGradP.set<Teuchos::ArrayRCP<ScalarT>>("Field Values", detdefgrad);
  auto setFieldDetDefGrad =
      Teuchos::rcp(new LCM::SetField<Residual, Traits>(setDetDefGradP));

  //---------------------------------------------------------------------------
  // Small strain tensor
  // initially set the strain tensor to zeros

  Teuchos::ArrayRCP<ScalarT> strain(workset_size * num_pts * 9);
  for (int i = 0; i < workset_size; ++i) {
    for (int j = 0; j < num_pts; ++j) {
      int base = i * num_pts * 9 + j * 9;
      for (int k = 0; k < 9; ++k) strain[base + k] = 0.0;
    }
  }

  // SetField evaluator, which will be used to manually assign a value
  // to the strain field
  Teuchos::ParameterList setStrainP("SetFieldStrain");
  setStrainP.set<std::string>("Evaluated Field Name", "Strain");
  setStrainP.set<Teuchos::RCP<PHX::DataLayout>>(
      "Evaluated Field Data Layout", dl->qp_tensor);
  setStrainP.set<Teuchos::ArrayRCP<ScalarT>>("Field Values", strain);
  auto setFieldStrain =
      Teuchos::rcp(new LCM::SetField<Residual, Traits>(setStrainP));
  //---------------------------------------------------------------------------
  // Instantiate a field manager
  PHX::FieldManager<Traits> fieldManager;

  // Instantiate a field manager for States
  PHX::FieldManager<Traits> stateFieldManager;

  // Register the evaluators with the field manager
  fieldManager.registerEvaluator<Residual>(setFieldDefGrad);
  fieldManager.registerEvaluator<Residual>(setFieldDetDefGrad);
  fieldManager.registerEvaluator<Residual>(setFieldStrain);

  // Register the evaluators with the state field manager
  stateFieldManager.registerEvaluator<Residual>(setFieldDefGrad);
  stateFieldManager.registerEvaluator<Residual>(setFieldDetDefGrad);
  stateFieldManager.registerEvaluator<Residual>(setFieldStrain);

  // Instantiate a state manager
  Albany::StateManager stateMgr;

  // extract the Material ParameterList for use below
  std::string matName = material_db->getElementBlockParam<std::string>(
      element_block_name, "material");
  Teuchos::ParameterList& paramList =
      material_db->getElementBlockSublist(element_block_name, matName);
  Teuchos::ParameterList& mpsParams =
      paramList.sublist("Material Point Simulator");

  // Get loading parameters from .xml file
  std::string load_case =
      mpsParams.get<std::string>("Loading Case Name", "uniaxial");
  int    number_steps = mpsParams.get<int>("Number of Steps", 10);
  double step_size    = mpsParams.get<double>("Step Size", 1.0e-2);

  std::cout << "Loading parameters:"
            << "\n  number of steps: " << number_steps
            << "\n  step_size      : " << step_size << std::endl;

  // determine if temperature is being used
  bool have_temperature = mpsParams.get<bool>("Use Temperature", false);
  std::cout << "have_temp: " << have_temperature << std::endl;
  //---------------------------------------------------------------------------
  // Temperature (optional)
  if (have_temperature) {
    Teuchos::ArrayRCP<ScalarT> temperature(workset_size);
    ScalarT                    temp = mpsParams.get<double>("Temperature", 1.0);
    for (int i = 0; i < workset_size * num_pts; ++i) temperature[0] = temp;
    // SetField evaluator, which will be used to manually assign a value
    // to the detdefgrad field
    Teuchos::ParameterList setTempP("SetFieldTemperature");
    setTempP.set<std::string>("Evaluated Field Name", "Temperature");
    setTempP.set<Teuchos::RCP<PHX::DataLayout>>(
        "Evaluated Field Data Layout", dl->qp_scalar);
    setTempP.set<Teuchos::ArrayRCP<ScalarT>>("Field Values", temperature);
    auto setFieldTemperature =
        Teuchos::rcp(new LCM::SetField<Residual, Traits>(setTempP));
    fieldManager.registerEvaluator<Residual>(setFieldTemperature);
    stateFieldManager.registerEvaluator<Residual>(setFieldTemperature);
  }

  //---------------------------------------------------------------------------
  // Time step
  Teuchos::ArrayRCP<ScalarT> delta_time(1);
  delta_time[0] = step_size;
  Teuchos::ParameterList setDTP("SetFieldTimeStep");
  setDTP.set<std::string>("Evaluated Field Name", "Delta Time");
  setDTP.set<Teuchos::RCP<PHX::DataLayout>>(
      "Evaluated Field Data Layout", dl->workset_scalar);
  setDTP.set<Teuchos::ArrayRCP<ScalarT>>("Field Values", delta_time);
  auto setFieldDT = Teuchos::rcp(new LCM::SetField<Residual, Traits>(setDTP));
  fieldManager.registerEvaluator<Residual>(setFieldDT);
  stateFieldManager.registerEvaluator<Residual>(setFieldDT);

  // check if the material wants the tangent to be computed
  bool check_stability;
  check_stability = mpsParams.get<bool>("Check Stability", false);
  paramList.set<bool>("Compute Tangent", check_stability);

  std::cout << "Check stability = " << check_stability << std::endl;

  //---------------------------------------------------------------------------
  // std::cout << "// Constitutive Model Parameters"
  //<< std::endl;
  Teuchos::ParameterList cmpPL;
  paramList.set<Teuchos::RCP<std::map<std::string, std::string>>>(
      "Name Map", fnm);
  cmpPL.set<Teuchos::ParameterList*>("Material Parameters", &paramList);
  if (have_temperature) {
    cmpPL.set<std::string>("Temperature Name", "Temperature");
    paramList.set<bool>("Have Temperature", true);
  }
  auto CMP = Teuchos::rcp(
      new LCM::ConstitutiveModelParameters<Residual, Traits>(cmpPL, dl));
  fieldManager.registerEvaluator<Residual>(CMP);
  stateFieldManager.registerEvaluator<Residual>(CMP);

  //---------------------------------------------------------------------------
  // std::cout << "// Constitutive Model Interface Evaluator"
  // << std::endl;
  Teuchos::ParameterList cmiPL;
  cmiPL.set<Teuchos::ParameterList*>("Material Parameters", &paramList);
  if (have_temperature) {
    cmiPL.set<std::string>("Temperature Name", "Temperature");
  }
  Teuchos::RCP<LCM::ConstitutiveModelInterface<Residual, Traits>> CMI =
      Teuchos::rcp(
          new LCM::ConstitutiveModelInterface<Residual, Traits>(cmiPL, dl));
  fieldManager.registerEvaluator<Residual>(CMI);
  stateFieldManager.registerEvaluator<Residual>(CMI);

  // Set the evaluated fields as required
  for (std::vector<Teuchos::RCP<PHX::FieldTag>>::const_iterator it =
           CMI->evaluatedFields().begin();
       it != CMI->evaluatedFields().end();
       ++it) {
    fieldManager.requireField<Residual>(**it);
  }

  // register state variables
  Teuchos::RCP<Teuchos::ParameterList> p;
  Teuchos::RCP<PHX::Evaluator<Traits>> ev;
  for (int sv(0); sv < CMI->getNumStateVars(); ++sv) {
    CMI->fillStateVariableStruct(sv);
    p = stateMgr.registerStateVariable(
        CMI->getName(),
        CMI->getLayout(),
        dl->dummy,
        element_block_name,
        CMI->getInitType(),
        CMI->getInitValue(),
        CMI->getStateFlag(),
        CMI->getOutputFlag());
    ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
    fieldManager.registerEvaluator<Residual>(ev);
    stateFieldManager.registerEvaluator<Residual>(ev);
  }

  //---------------------------------------------------------------------------
  if (check_stability) {
    std::string parametrization_type =
        mpsParams.get<std::string>("Parametrization Type", "Spherical");

    double parametrization_interval =
        mpsParams.get<double>("Parametrization Interval", 0.05);

    std::cout << "Bifurcation Check in Material Point Simulator:" << std::endl;
    std::cout << "Parametrization Type: " << parametrization_type << std::endl;

    Teuchos::ParameterList bcPL;
    bcPL.set<Teuchos::ParameterList*>("Material Parameters", &paramList);
    bcPL.set<std::string>("Parametrization Type Name", parametrization_type);
    bcPL.set<double>("Parametrization Interval Name", parametrization_interval);
    bcPL.set<std::string>("Material Tangent Name", "Material Tangent");
    bcPL.set<std::string>("Ellipticity Flag Name", "Ellipticity_Flag");
    bcPL.set<std::string>("Bifurcation Direction Name", "Direction");
    bcPL.set<std::string>("Min detA Name", "Min detA");
    Teuchos::RCP<LCM::BifurcationCheck<Residual, Traits>> BC =
        Teuchos::rcp(new LCM::BifurcationCheck<Residual, Traits>(bcPL, dl));
    fieldManager.registerEvaluator<Residual>(BC);
    stateFieldManager.registerEvaluator<Residual>(BC);

    // register the ellipticity flag
    p = stateMgr.registerStateVariable(
        "Ellipticity_Flag",
        dl->qp_scalar,
        dl->dummy,
        element_block_name,
        "scalar",
        0.0,
        false,
        true);
    ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
    fieldManager.registerEvaluator<Residual>(ev);
    stateFieldManager.registerEvaluator<Residual>(ev);

    // register the direction
    p = stateMgr.registerStateVariable(
        "Direction",
        dl->qp_vector,
        dl->dummy,
        element_block_name,
        "scalar",
        0.0,
        false,
        true);
    ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
    fieldManager.registerEvaluator<Residual>(ev);
    stateFieldManager.registerEvaluator<Residual>(ev);

    // register min(det(A))
    p = stateMgr.registerStateVariable(
        "Min detA",
        dl->qp_scalar,
        dl->dummy,
        element_block_name,
        "scalar",
        0.0,
        false,
        true);
    ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
    fieldManager.registerEvaluator<Residual>(ev);
    stateFieldManager.registerEvaluator<Residual>(ev);
  }

  //---------------------------------------------------------------------------
  // std::cout << "// register deformation gradient"
  // << std::endl;
  p = stateMgr.registerStateVariable(
      "F",
      dl->qp_tensor,
      dl->dummy,
      element_block_name,
      "identity",
      1.0,
      true,
      true);
  ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
  fieldManager.registerEvaluator<Residual>(ev);
  stateFieldManager.registerEvaluator<Residual>(ev);
  //---------------------------------------------------------------------------
  // std::cout << "// register small strain tensor"
  // << std::endl;
  p = stateMgr.registerStateVariable(
      "Strain",
      dl->qp_tensor,
      dl->dummy,
      element_block_name,
      "scalar",
      0.0,
      false,
      true);
  ev = Teuchos::rcp(new PHAL::SaveStateField<Residual, Traits>(*p));
  fieldManager.registerEvaluator<Residual>(ev);
  stateFieldManager.registerEvaluator<Residual>(ev);
  //---------------------------------------------------------------------------
  //
  Traits::SetupData setupData = "Test String";
  // std::cout << "Calling postRegistrationSetup" << std::endl;
  fieldManager.postRegistrationSetup(setupData);

  // std::cout << "// set the required fields for the state manager"
  //<< std::endl;
  Teuchos::RCP<PHX::DataLayout> dummy =
      Teuchos::rcp(new PHX::MDALayout<Dummy>(0));
  std::vector<std::string> responseIDs =
      stateMgr.getResidResponseIDsToRequire(element_block_name);
  std::vector<std::string>::const_iterator it;
  for (it = responseIDs.begin(); it != responseIDs.end(); it++) {
    const std::string&                              responseID = *it;
    PHX::Tag<PHAL::AlbanyTraits::Residual::ScalarT> res_response_tag(
        responseID, dummy);
    stateFieldManager.requireField<PHAL::AlbanyTraits::Residual>(
        res_response_tag);
  }
  stateFieldManager.postRegistrationSetup("");

  // std::cout << "Process using 'dot -Tpng -O <name>'\n";
  fieldManager.writeGraphvizFile<Residual>("FM", true, true);
  stateFieldManager.writeGraphvizFile<Residual>("SFM", true, true);

  //---------------------------------------------------------------------------
  // grab the output file name
  //
  std::string output_file =
      mpsParams.get<std::string>("Output File Name", "output.exo");

  //---------------------------------------------------------------------------
  // Create discretization, as required by the StateManager
  //
  Teuchos::RCP<Teuchos::ParameterList> discretizationParameterList =
      Teuchos::rcp(new Teuchos::ParameterList("Discretization"));
  discretizationParameterList->set<int>("1D Elements", workset_size);
  discretizationParameterList->set<int>("2D Elements", 1);
  discretizationParameterList->set<int>("3D Elements", 1);
  discretizationParameterList->set<std::string>("Method", "STK3D");
  discretizationParameterList->set<int>("Number Of Time Derivatives", 0);
  discretizationParameterList->set<std::string>(
      "Exodus Output File Name", output_file);
  discretizationParameterList->set<int>("Workset Size", workset_size);
  Teuchos::RCP<Tpetra_Map>    mapT = Teuchos::rcp(new Tpetra_Map(
      workset_size * num_dims * num_nodes,
      0,
      commT,
      Tpetra::LocallyReplicated));
  Teuchos::RCP<Tpetra_Vector> solution_vectorT =
      Teuchos::rcp(new Tpetra_Vector(mapT));

  int numberOfEquations = 3;
  Albany::AbstractFieldContainer::FieldContainerRequirements req;

  Teuchos::RCP<Albany::AbstractSTKMeshStruct> stkMeshStruct =
      Teuchos::rcp(new Albany::TmplSTKMeshStruct<3>(
          discretizationParameterList, Teuchos::null, commT));
  stkMeshStruct->setFieldAndBulkData(
      commT,
      discretizationParameterList,
      numberOfEquations,
      req,
      stateMgr.getStateInfoStruct(),
      stkMeshStruct->getMeshSpecs()[0]->worksetSize);

  Teuchos::RCP<Albany::AbstractDiscretization> discretization =
      Teuchos::rcp(new Albany::STKDiscretization(
          discretizationParameterList, stkMeshStruct, commT));

  //---------------------------------------------------------------------------
  // Associate the discretization with the StateManager
  //
  stateMgr.setupStateArrays(discretization);

  //---------------------------------------------------------------------------
  // Create a workset
  //
  PHAL::Workset workset;
  workset.numCells = workset_size;
  workset.stateArrayPtr =
      &stateMgr.getStateArray(Albany::StateManager::ELEM, 0);

  // create MDFields
  PHX::MDField<ScalarT, Cell, QuadPoint, Dim, Dim> stressField(
      "Cauchy_Stress", dl->qp_tensor);

  // construct the final deformation gradient based on the loading case
  std::vector<ScalarT> F_vector(9, 0.0);
  if (load_case == "uniaxial") {
    F_vector[0] = 1.0 + number_steps * step_size;
    F_vector[4] = 1.0;
    F_vector[8] = 1.0;
  } else if (load_case == "simple-shear") {
    F_vector[0] = 1.0;
    F_vector[1] = number_steps * step_size;
    F_vector[4] = 1.0;
    F_vector[8] = 1.0;
  } else if (load_case == "hydrostatic") {
    F_vector[0] = 1.0 + number_steps * step_size;
    F_vector[4] = 1.0 + number_steps * step_size;
    F_vector[8] = 1.0 + number_steps * step_size;
  } else if (load_case == "general") {
    F_vector =
        mpsParams.get<Teuchos::Array<double>>("Deformation Gradient Components")
            .toVector();
  } else {
    TEUCHOS_TEST_FOR_EXCEPTION(
        true,
        std::runtime_error,
        "Improper Loading Case in Material Point Simulator block");
  }

  minitensor::Tensor<ScalarT> F_tensor(3, &F_vector[0]);
  minitensor::Tensor<ScalarT> log_F_tensor = minitensor::log(F_tensor);

  std::cout << "F\n" << F_tensor << std::endl;
  // std::cout << "log F\n" << log_F_tensor << std::endl;

  //
  // Setup loading scenario and instantiate evaluatFields
  //
  PHX::MDField<ScalarT, Cell, QuadPoint> minDetA("Min detA", dl->qp_scalar);
  PHX::MDField<ScalarT, Cell, QuadPoint, Dim> direction(
      "Direction", dl->qp_vector);

  // Bifurcation check parameters
  double mu_0                  = 0;
  double mu_k                  = 0;
  int    bifurcationTime_rough = number_steps;
  bool   bifurcation_flag      = false;

  for (int istep(0); istep <= number_steps; ++istep) {
    util::TimeGuard total_time_guard(total_time);
    // std::cout << "****** in MPS step " << istep << " ****** " << std::endl;
    // alpha \in [0,1]
    double alpha = double(istep) / number_steps;

    // std::cout << "alpha: " << alpha << std::endl;
    minitensor::Tensor<ScalarT> scaled_log_F_tensor = alpha * log_F_tensor;
    minitensor::Tensor<ScalarT> current_F =
        minitensor::exp(scaled_log_F_tensor);

    // std::cout << "scaled log F\n" << scaled_log_F_tensor << std::endl;
    // std::cout << "current F\n" << current_F << std::endl;

    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) { def_grad[3 * i + j] = current_F(i, j); }
    }

    // jacobian
    detdefgrad[0] = minitensor::det(current_F);

    // small strain tensor
    minitensor::Tensor<ScalarT> current_strain;
    current_strain = 0.5 * (current_F + minitensor::transpose(current_F)) -
                     minitensor::eye<ScalarT>(3);

    for (int i = 0; i < 3; ++i) {
      for (int j = 0; j < 3; ++j) { strain[3 * i + j] = current_strain(i, j); }
    }
    // std::cout << "current strain\n" << current_strain << std::endl;

    // Call the evaluators, evaluateFields() is the function that
    // computes stress based on deformation gradient
    compute_time->start();
    fieldManager.preEvaluate<Residual>(workset);
    fieldManager.evaluateFields<Residual>(workset);
    fieldManager.postEvaluate<Residual>(workset);
    compute_time->stop();

    stateFieldManager.getFieldData<Residual>(stressField);

    // Call the state field manager
    // std::cout << "+++ calling the stateFieldManager\n";
    compute_time->start();
    stateFieldManager.preEvaluate<Residual>(workset);
    stateFieldManager.evaluateFields<Residual>(workset);
    stateFieldManager.postEvaluate<Residual>(workset);
    compute_time->stop();

    stateMgr.updateStates();

    // output to the exodus file
    // Don't include this in timing data...
    total_time->stop();
    discretization->writeSolutionT(
        *solution_vectorT, Teuchos::as<double>(istep));

    // if check for bifurcation, adaptive step
    total_time->start();
    if (check_stability) {
      // get current minDet(A)
      stateFieldManager.getFieldData<Residual>(minDetA);

      if (istep == 0) { mu_0 = minDetA(0, 0); }

      if (minDetA(0, 0) <= 0 && !bifurcation_flag) {
        mu_k                  = minDetA(0, 0);
        bifurcationTime_rough = istep;
        bifurcation_flag      = true;

        // adaptive step begin
        std::cout << "\nAdaptive step begin - step " << istep << std::endl;

        // initialization for adaptive step
        double tol              = 1E-8;
        double alpha_local      = 1.0;
        double alpha_local_step = 0.5;

        int k            = 1;
        int maxIteration = 50;

        // small strain tensor
        minitensor::Tensor<ScalarT> current_strain;

        // iteration begin
        while (((mu_k <= 0) || (std::abs(mu_k / mu_0) > tol))) {
          alpha =
              double(bifurcationTime_rough - 1 + alpha_local) / number_steps;

          minitensor::Tensor<ScalarT> scaled_log_F_tensor =
              alpha * log_F_tensor;
          minitensor::Tensor<ScalarT> current_F =
              minitensor::exp(scaled_log_F_tensor);

          for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
              def_grad[3 * i + j] = current_F(i, j);
            }
          }

          // jacobian
          detdefgrad[0] = minitensor::det(current_F);

          current_strain =
              0.5 * (current_F + minitensor::transpose(current_F)) -
              minitensor::eye<ScalarT>(3);

          for (int i = 0; i < 3; ++i) {
            for (int j = 0; j < 3; ++j) {
              strain[3 * i + j] = current_strain(i, j);
            }
          }

          // Call the evaluators, evaluateFields() is the function that
          // computes stress based on deformation gradient
          fieldManager.preEvaluate<Residual>(workset);
          fieldManager.evaluateFields<Residual>(workset);
          fieldManager.postEvaluate<Residual>(workset);

          // Call the state field manager
          // std::cout << "+++ calling the stateFieldManager\n";
          stateFieldManager.preEvaluate<Residual>(workset);
          stateFieldManager.evaluateFields<Residual>(workset);
          stateFieldManager.postEvaluate<Residual>(workset);

          stateFieldManager.getFieldData<Residual>(minDetA);

          stateFieldManager.getFieldData<Residual>(direction);

          mu_k = minDetA(0, 0);

          if (mu_k > 0) {
            alpha_local += alpha_local_step;
          } else {
            alpha_local -= alpha_local_step;
          }

          alpha_local_step /= 2;

          k = k + 1;

          if (k >= maxIteration) {
            std::cout
                << "Adaptive step for bifurcation check not converging after "
                << k << " iterations" << std::endl;
            break;
          }

        }  // adaptive step iteration end

      }  // end adaptive step

    }  // end check bifurcation

    stateMgr.updateStates();

    //
    if (bifurcation_flag) {
      // break the loading step after adaptive time step loop
      break;
    }

    //

  }  // end loading steps

  // Summarize with AlbanyUtil performance monitors
  if (tout) {
    util::PerformanceContext::instance().timeMonitor().summarize(tout);
    tout.close();
  }
}
TEUCHOS_UNIT_TEST(response_assembly, test)
{
  typedef Traits::Residual EvalT;

  // build global (or serial communicator)
  #ifdef HAVE_MPI
     Teuchos::RCP<Teuchos::Comm<int> > comm = Teuchos::rcp(new Teuchos::MpiComm<int>(Teuchos::opaqueWrapper(MPI_COMM_WORLD)));
  #else
     Teuchos::RCP<Teuchos::Comm<int> > comm = Teuchos::rcp(new Teuchos::SerialComm<int>);
  #endif
 
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::rcp_dynamic_cast;

  // panzer::pauseToAttach();

  int worksetSize = 10;
  Teuchos::ParameterList mainParam;
  mainParam.set<int>("Workset Size", worksetSize);

  // build basic field manager
  PHX::FieldManager<Traits> fm;
  {
     RCP<PHX::Evaluator<Traits> > testEval 
        = rcp(new TestEvaluator<EvalT,Traits>(mainParam));
     fm.registerEvaluator<EvalT>(testEval);
  }

  std::vector<std::string> fields, testFields;
  fields.push_back("Dog");
  fields.push_back("Horse");

  RCP<WorksetContainer> wkstContainer = Teuchos::rcp(new WorksetContainer);

  RCP<ResponseLibrary<Traits> > rLibrary 
        = Teuchos::rcp(new ResponseLibrary<Traits>(wkstContainer,Teuchos::null,Teuchos::null));
  rLibrary->defineDefaultAggregators();

  RCP<ResponseContainerBase<Traits> > container
        = Teuchos::rcp(new ResponseContainer<EvalT,Traits>(rLibrary));

  ResponseId dResp  = buildResponse("Dog","Functional");
  ResponseId hResp  = buildResponse("Horse","Functional");
  ResponseId hResp2 = buildResponse("Horse","Max");       // should be able to add
  ResponseId cResp  = buildResponse("Cat","Functional"); // not added
  container->reserve(dResp);
  container->reserve(hResp);
  // container->reserve(hResp2);
  container->reserve(hResp); // You can reserve things multiple times, should
                            // not increased number of reserved items

  // TEST_EQUALITY(container->getReserved().size(),3);
  TEST_EQUALITY(container->getReserved().size(),2);
  TEST_ASSERT(container->contains(dResp));
  TEST_ASSERT(container->contains(hResp));
  // TEST_ASSERT(container->contains(hResp2));
  TEST_ASSERT(!container->contains(cResp));

  PhysicsBlock pb; // need for testing purposes (default constructor does nothing!)
  container->buildResponseDataObjs();
  container->registerResponses(fm,pb,mainParam);
  
  // evaluate on block 0
  {
     Teuchos::RCP<panzer::Workset> workset = Teuchos::rcp(new panzer::Workset);
     workset->num_cells = worksetSize; workset->block_id = "block_0";

     panzer::Traits::SetupData setupData;
     setupData.worksets_ = rcp(new std::vector<panzer::Workset>);
     setupData.worksets_->push_back(*workset);

     panzer::GlobalEvaluationDataContainer preEvalData;

     fm.postRegistrationSetup(setupData);
     fm.writeGraphvizFile();
     fm.preEvaluate<EvalT>(preEvalData);
     fm.evaluateFields<EvalT>(*workset);
     fm.postEvaluate<EvalT>(0);
  }

  double sum_dog = 0.0;
  double sum_horse = 0.0;
  for(int i=0;i<worksetSize;i++) {
     sum_dog += double(i)+1.0; 
     sum_horse += -double(i)-5.5; 
  }

  {
     Teuchos::RCP<ResponseData<Traits> > data = container->getResponseData("Functional");

     panzer::Response<panzer::Traits> dResp_o(dResp),
                                      hResp_o(hResp);
     data->fillResponse("Dog",dResp_o);
     data->fillResponse("Horse",hResp_o);
     TEST_EQUALITY(dResp_o.getValue(),sum_dog);
     TEST_EQUALITY(hResp_o.getValue(),sum_horse);
  }

  {
     Teuchos::RCP<ResponseData<Traits> > data = container->getResponseData("Functional");
     container->globalReduction(*comm);

     panzer::Response<panzer::Traits> dResp_o(dResp),
                                      hResp_o(hResp);
     data->fillResponse("Dog",dResp_o);
     data->fillResponse("Horse",hResp_o);

     TEST_EQUALITY(dResp_o.getValue(),comm->getSize()*sum_dog);
     TEST_EQUALITY(hResp_o.getValue(),comm->getSize()*sum_horse);
  }
}
Example #4
0
  TEUCHOS_UNIT_TEST(gather_orientation, gather_constr)
  {

    const std::size_t workset_size = 4;
    const std::string fieldName_q1 = "U";
    const std::string fieldName_qedge1 = "V";

    Teuchos::RCP<panzer_stk_classic::STK_Interface> mesh = buildMesh(2,2);

    // build input physics block
    Teuchos::RCP<panzer::PureBasis> basis_q1 = buildBasis(workset_size,"Q1");
    Teuchos::RCP<panzer::PureBasis> basis_qedge1 = buildBasis(workset_size,"QEdge1");

    Teuchos::RCP<Teuchos::ParameterList> ipb = Teuchos::parameterList();
    testInitialization(ipb);

    const int default_int_order = 1;
    std::string eBlockID = "eblock-0_0";    
    Teuchos::RCP<user_app::MyFactory> eqset_factory = Teuchos::rcp(new user_app::MyFactory);
    panzer::CellData cellData(workset_size,mesh->getCellTopology("eblock-0_0"));
    Teuchos::RCP<panzer::GlobalData> gd = panzer::createGlobalData();
    Teuchos::RCP<panzer::PhysicsBlock> physicsBlock = 
      Teuchos::rcp(new PhysicsBlock(ipb,eBlockID,default_int_order,cellData,eqset_factory,gd,false));

    Teuchos::RCP<std::vector<panzer::Workset> > work_sets = panzer_stk_classic::buildWorksets(*mesh,*physicsBlock); 
    TEST_EQUALITY(work_sets->size(),1);

    // build connection manager and field manager
    const Teuchos::RCP<panzer::ConnManager<int,int> > conn_manager = Teuchos::rcp(new panzer_stk_classic::STKConnManager<int>(mesh));
    RCP<panzer::DOFManager<int,int> > dofManager = Teuchos::rcp(new panzer::DOFManager<int,int>(conn_manager,MPI_COMM_WORLD));
    dofManager->addField(fieldName_q1,Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis_q1->getIntrepid2Basis())));
    dofManager->addField(fieldName_qedge1,Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis_qedge1->getIntrepid2Basis())));
    dofManager->setOrientationsRequired(true);
    dofManager->buildGlobalUnknowns();

    // setup field manager, add evaluator under test
    /////////////////////////////////////////////////////////////
 
    PHX::FieldManager<panzer::Traits> fm;

    Teuchos::RCP<PHX::FieldTag> evalField_q1, evalField_qedge1;
    {
       Teuchos::RCP<std::vector<std::string> > dofNames = Teuchos::rcp(new std::vector<std::string>);
       dofNames->push_back(fieldName_q1);

       Teuchos::ParameterList pl;
       pl.set("Indexer Names",dofNames);
       pl.set("DOF Names",dofNames);
       pl.set("Basis",basis_q1);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator  
          = Teuchos::rcp(new panzer::GatherOrientation<panzer::Traits::Residual,panzer::Traits,int,int>(dofManager,pl));

       TEST_EQUALITY(evaluator->evaluatedFields().size(),1);
       evalField_q1 = evaluator->evaluatedFields()[0];

       TEST_EQUALITY(evalField_q1->name(),basis_q1->name()+" Orientation");
       TEST_EQUALITY(evalField_q1->dataLayout().dimension(0),basis_q1->functional->dimension(0));
       TEST_EQUALITY(evalField_q1->dataLayout().dimension(1),basis_q1->functional->dimension(1));

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
       fm.requireField<panzer::Traits::Residual>(*evaluator->evaluatedFields()[0]);
    }
    {
       Teuchos::RCP<std::vector<std::string> > dofNames = Teuchos::rcp(new std::vector<std::string>);
       dofNames->push_back(fieldName_qedge1);

       Teuchos::ParameterList pl;
       pl.set("Indexer Names",dofNames);
       pl.set("DOF Names",dofNames);
       pl.set("Basis",basis_qedge1);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator  
          = Teuchos::rcp(new panzer::GatherOrientation<panzer::Traits::Residual,panzer::Traits,int,int>(dofManager,pl));

       TEST_EQUALITY(evaluator->evaluatedFields().size(),1);
       evalField_qedge1 = evaluator->evaluatedFields()[0];

       TEST_EQUALITY(evalField_qedge1->name(),basis_qedge1->name()+" Orientation");
       TEST_EQUALITY(evalField_qedge1->dataLayout().dimension(0),basis_qedge1->functional->dimension(0));
       TEST_EQUALITY(evalField_qedge1->dataLayout().dimension(1),basis_qedge1->functional->dimension(1));

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
       fm.requireField<panzer::Traits::Residual>(*evaluator->evaluatedFields()[0]);
    }

    panzer::Traits::SetupData sd;
    fm.postRegistrationSetup(sd);

    // run tests
    /////////////////////////////////////////////////////////////

    panzer::Workset & workset = (*work_sets)[0];
    workset.alpha = 0.0;
    workset.beta = 0.0;
    workset.time = 0.0;
    workset.evaluate_transient_terms = false;

    fm.evaluateFields<panzer::Traits::Residual>(workset);

    // <cell,basis>
    PHX::MDField<panzer::Traits::Residual::ScalarT> 
       fieldData_q1(evalField_q1->name(),basis_q1->functional);
    // <cell,basis>
    PHX::MDField<panzer::Traits::Residual::ScalarT> 
       fieldData_qedge1(evalField_qedge1->name(),basis_qedge1->functional);

    fm.getFieldData<panzer::Traits::Residual::ScalarT,panzer::Traits::Residual>(fieldData_q1);
    fm.getFieldData<panzer::Traits::Residual::ScalarT,panzer::Traits::Residual>(fieldData_qedge1);

    for(int i=0;i<fieldData_q1.size();i++) {
       TEST_EQUALITY(fieldData_q1[i],1);
    }

    for(int i=0;i<fieldData_qedge1.dimension(0);i++) {
       TEST_EQUALITY(fieldData_qedge1(i,0), 1);
       TEST_EQUALITY(fieldData_qedge1(i,1), 1);
       TEST_EQUALITY(fieldData_qedge1(i,2),-1);
       TEST_EQUALITY(fieldData_qedge1(i,3),-1);
    }
  }
  TEUCHOS_UNIT_TEST(block_assembly, scatter_dirichlet_residual)
  {
    PHX::KokkosDeviceSession session;

#ifdef HAVE_MPI
    Teuchos::RCP<Epetra_Comm> eComm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD));
#else
    Teuchos::RCP<Epetra_Comm> eComm = Teuchos::rcp(new Epetra_SerialComm());
#endif

    int myRank = eComm->MyPID();

    const std::size_t workset_size = 4;
    const std::string fieldName1_q1 = "U";
    const std::string fieldName2_q1 = "V";
    const std::string fieldName_qedge1 = "B";

    Teuchos::RCP<panzer_stk_classic::STK_Interface> mesh = buildMesh(2,2);

    // build input physics block
    Teuchos::RCP<panzer::PureBasis> basis_q1 = buildBasis(workset_size,"Q1");
    Teuchos::RCP<panzer::PureBasis> basis_qedge1 = buildBasis(workset_size,"QEdge1");

    Teuchos::RCP<Teuchos::ParameterList> ipb = Teuchos::parameterList();
    testInitialization(ipb);

    const int default_int_order = 1;
    std::string eBlockID = "eblock-0_0";    
    Teuchos::RCP<user_app::MyFactory> eqset_factory = Teuchos::rcp(new user_app::MyFactory);
    panzer::CellData cellData(workset_size,mesh->getCellTopology("eblock-0_0"));
    Teuchos::RCP<panzer::GlobalData> gd = panzer::createGlobalData();
    Teuchos::RCP<panzer::PhysicsBlock> physicsBlock = 
      Teuchos::rcp(new PhysicsBlock(ipb,eBlockID,default_int_order,cellData,eqset_factory,gd,false));

    Teuchos::RCP<std::vector<panzer::Workset> > work_sets = panzer_stk_classic::buildWorksets(*mesh,*physicsBlock); 
    TEST_EQUALITY(work_sets->size(),1);

    // build connection manager and field manager
    const Teuchos::RCP<panzer::ConnManager<int,int> > conn_manager = Teuchos::rcp(new panzer_stk_classic::STKConnManager<int>(mesh));
    RCP<panzer::BlockedDOFManager<int,int> > dofManager = Teuchos::rcp(new panzer::BlockedDOFManager<int,int>(conn_manager,MPI_COMM_WORLD));

    dofManager->addField(fieldName1_q1,Teuchos::rcp(new panzer::IntrepidFieldPattern(basis_q1->getIntrepidBasis())));
    dofManager->addField(fieldName2_q1,Teuchos::rcp(new panzer::IntrepidFieldPattern(basis_q1->getIntrepidBasis())));
    dofManager->addField(fieldName_qedge1,Teuchos::rcp(new panzer::IntrepidFieldPattern(basis_qedge1->getIntrepidBasis())));

    std::vector<std::vector<std::string> > fieldOrder(3);
    fieldOrder[0].push_back(fieldName1_q1);
    fieldOrder[1].push_back(fieldName_qedge1);
    fieldOrder[2].push_back(fieldName2_q1);
    dofManager->setFieldOrder(fieldOrder);

    // dofManager->setOrientationsRequired(true);
    dofManager->buildGlobalUnknowns();

    // setup linear object factory
    /////////////////////////////////////////////////////////////

    Teuchos::RCP<BlockedEpetraLinearObjFactory<panzer::Traits,int> > be_lof 
       = Teuchos::rcp(new BlockedEpetraLinearObjFactory<panzer::Traits,int>(eComm.getConst(),dofManager));
    Teuchos::RCP<LinearObjFactory<panzer::Traits> > lof = be_lof;
    Teuchos::RCP<LinearObjContainer> dd_loc = be_lof->buildGhostedLinearObjContainer();
    Teuchos::RCP<LinearObjContainer> loc = be_lof->buildGhostedLinearObjContainer();
    be_lof->initializeGhostedContainer(LinearObjContainer::F,*dd_loc);
    dd_loc->initialize();

    be_lof->initializeGhostedContainer(LinearObjContainer::X | LinearObjContainer::F,*loc);
    loc->initialize();

    Teuchos::RCP<BlockedEpetraLinearObjContainer> b_dd_loc = Teuchos::rcp_dynamic_cast<BlockedEpetraLinearObjContainer>(dd_loc);
    Teuchos::RCP<BlockedEpetraLinearObjContainer> b_loc = Teuchos::rcp_dynamic_cast<BlockedEpetraLinearObjContainer>(loc);
    Teuchos::RCP<Thyra::ProductVectorBase<double> > p_vec = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(b_loc->get_x());
    Thyra::assign(p_vec->getNonconstVectorBlock(0).ptr(),123.0+myRank);
    Thyra::assign(p_vec->getNonconstVectorBlock(1).ptr(),456.0+myRank);
    Thyra::assign(p_vec->getNonconstVectorBlock(2).ptr(),789.0+myRank);

    // setup field manager, add evaluator under test
    /////////////////////////////////////////////////////////////
 
    PHX::FieldManager<panzer::Traits> fm;

    std::string resName = "";
    Teuchos::RCP<std::map<std::string,std::string> > names_map =
       Teuchos::rcp(new std::map<std::string,std::string>);
    names_map->insert(std::make_pair(fieldName1_q1,resName+fieldName1_q1));
    names_map->insert(std::make_pair(fieldName2_q1,resName+fieldName2_q1));
    names_map->insert(std::make_pair(fieldName_qedge1,resName+fieldName_qedge1));

    // evaluators under test
    {
       using Teuchos::RCP;
       using Teuchos::rcp;
       RCP<std::vector<std::string> > names = rcp(new std::vector<std::string>);
       names->push_back(resName+fieldName1_q1);
       names->push_back(resName+fieldName2_q1);

       Teuchos::ParameterList pl; 
       pl.set("Scatter Name", "ScatterQ1");
       pl.set("Basis", basis_q1);
       pl.set("Dependent Names", names);
       pl.set("Dependent Map", names_map);
       pl.set("Side Subcell Dimension", 1);
       pl.set("Local Side ID", 2);
       pl.set("Check Apply BC", false);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator = lof->buildScatterDirichlet<panzer::Traits::Residual>(pl);

       TEST_EQUALITY(evaluator->evaluatedFields().size(),1);

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
       fm.requireField<panzer::Traits::Residual>(*evaluator->evaluatedFields()[0]);
    }
    {
       using Teuchos::RCP;
       using Teuchos::rcp;
       RCP<std::vector<std::string> > names = rcp(new std::vector<std::string>);
       names->push_back(resName+fieldName_qedge1);

       Teuchos::ParameterList pl; 
       pl.set("Scatter Name", "ScatterQEdge1");
       pl.set("Basis", basis_qedge1);
       pl.set("Dependent Names", names);
       pl.set("Dependent Map", names_map);
       pl.set("Side Subcell Dimension", 1);
       pl.set("Local Side ID", 2);
       pl.set("Check Apply BC", false);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator = lof->buildScatterDirichlet<panzer::Traits::Residual>(pl);

       TEST_EQUALITY(evaluator->evaluatedFields().size(),1);

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
       fm.requireField<panzer::Traits::Residual>(*evaluator->evaluatedFields()[0]);
    }

    // support evaluators
    {
       using Teuchos::RCP;
       using Teuchos::rcp;
       RCP<std::vector<std::string> > names = rcp(new std::vector<std::string>);
       names->push_back(fieldName1_q1);
       names->push_back(fieldName2_q1);

       Teuchos::ParameterList pl; 
       pl.set("Basis", basis_q1);
       pl.set("DOF Names",names);
       pl.set("Indexer Names",names);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator = lof->buildGather<panzer::Traits::Residual>(pl);

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
    }
    {
       using Teuchos::RCP;
       using Teuchos::rcp;
       RCP<std::vector<std::string> > names = rcp(new std::vector<std::string>);
       names->push_back(fieldName_qedge1);

       Teuchos::ParameterList pl; 
       pl.set("Basis", basis_qedge1);
       pl.set("DOF Names",names);
       pl.set("Indexer Names",names);

       Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator = lof->buildGather<panzer::Traits::Residual>(pl);

       fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
    }

    std::vector<PHX::index_size_type> derivative_dimensions;
    derivative_dimensions.push_back(12);
    fm.setKokkosExtendedDataTypeDimensions<panzer::Traits::Jacobian>(derivative_dimensions);

    panzer::Traits::SetupData sd;
    fm.postRegistrationSetup(sd);

    // panzer::Traits::PED ped;
    // ped.dirichletData.ghostedCounter = dd_loc;
    // fm.preEvaluate<panzer::Traits::Residual>(ped);
    panzer::Traits::PreEvalData ped;
    ped.gedc.addDataObject("Dirichlet Counter",dd_loc);
    ped.gedc.addDataObject("Solution Gather Container",loc);
    ped.gedc.addDataObject("Residual Scatter Container",loc);
    fm.preEvaluate<panzer::Traits::Residual>(ped);


    // run tests
    /////////////////////////////////////////////////////////////

    panzer::Workset & workset = (*work_sets)[0];
    workset.alpha = 0.0;
    workset.beta = 2.0; // derivatives multiplied by 2
    workset.time = 0.0;
    workset.evaluate_transient_terms = false;

    fm.evaluateFields<panzer::Traits::Residual>(workset);

    // test Residual fields
    std::size_t dd_count = 0;
    Teuchos::ArrayRCP<const double> data, dd_data;
    Teuchos::RCP<const Thyra::ProductVectorBase<double> > f_vec = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(b_loc->get_f());
    Teuchos::RCP<const Thyra::ProductVectorBase<double> > dd_vec = Teuchos::rcp_dynamic_cast<Thyra::ProductVectorBase<double> >(b_dd_loc->get_f());

    // check all the residual values. This is kind of crappy test since it simply checks twice the target
    // value and the target. Its this way because you add two entries across elements.

    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(f_vec->getVectorBlock(0))->getLocalData(Teuchos::ptrFromRef(data));
    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(dd_vec->getVectorBlock(0))->getLocalData(Teuchos::ptrFromRef(dd_data));
    TEST_EQUALITY(data.size(),b_loc->getMapForBlock(0)->NumMyElements());
    TEST_EQUALITY(data.size(),dd_data.size());
    dd_count = 0;
    for(int i=0;i<data.size();i++) {
 
       double target = 123.0+myRank;
       if(dd_data[i]==0.0)
       {  TEST_EQUALITY(data[i],0.0); }
       else
       {  TEST_EQUALITY(data[i],target); dd_count++; }
    }
    TEST_EQUALITY(dd_count,2*workset.num_cells); // there are 2 nodes on the side and the sides are not shared

    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(f_vec->getVectorBlock(1))->getLocalData(Teuchos::ptrFromRef(data));
    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(dd_vec->getVectorBlock(1))->getLocalData(Teuchos::ptrFromRef(dd_data));
    TEST_EQUALITY(data.size(),b_loc->getMapForBlock(1)->NumMyElements());
    TEST_EQUALITY(data.size(),dd_data.size());
    dd_count = 0;
    for(int i=0;i<data.size();i++) {
 
       double target = 456.0+myRank;
       if(dd_data[i]==0.0)
       {  TEST_EQUALITY(data[i],0.0); }
       else
       {  TEST_EQUALITY(data[i],target); dd_count++; }
    }
    TEST_EQUALITY(dd_count,workset.num_cells); // there are 2 nodes on the side and the sides are not shared

    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(f_vec->getVectorBlock(2))->getLocalData(Teuchos::ptrFromRef(data));
    Teuchos::rcp_dynamic_cast<const Thyra::SpmdVectorBase<double> >(dd_vec->getVectorBlock(2))->getLocalData(Teuchos::ptrFromRef(dd_data));
    TEST_EQUALITY(data.size(),b_loc->getMapForBlock(2)->NumMyElements());
    TEST_EQUALITY(data.size(),dd_data.size());
    dd_count = 0;
    for(int i=0;i<data.size();i++) {
 
       double target = 789.0+myRank;
       if(dd_data[i]==0.0)
       {  TEST_EQUALITY(data[i],0.0); }
       else
       {  TEST_EQUALITY(data[i],target); dd_count++; }
    }
    TEST_EQUALITY(dd_count,2*workset.num_cells); // there are 2 nodes on the side and the sides are not shared

  }
TEUCHOS_UNIT_TEST(basis_time_vector, residual)
{
    PHX::KokkosDeviceSession session;

    const std::size_t workset_size = 1;
    const std::string fieldName_q1 = "TEMPERATURE";
    const std::string fieldName_qedge1 = "ION_TEMPERATURE";

    Teuchos::RCP<panzer_stk_classic::STK_Interface> mesh = buildMesh(1,1);

    // build input physics block
    Teuchos::RCP<panzer::PureBasis> basis_q1 = buildBasis(workset_size,"Q1");
    Teuchos::RCP<panzer::PureBasis> basis_qedge1 = buildBasis(workset_size,"QEdge1");

    Teuchos::RCP<Teuchos::ParameterList> ipb = Teuchos::parameterList();
    testInitialization(ipb);

    const int default_int_order = 1;
    std::string eBlockID = "eblock-0_0";
    Teuchos::RCP<user_app::MyFactory> eqset_factory = Teuchos::rcp(new user_app::MyFactory);
    panzer::CellData cellData(workset_size,mesh->getCellTopology("eblock-0_0"));
    Teuchos::RCP<panzer::GlobalData> gd = panzer::createGlobalData();
    Teuchos::RCP<panzer::PhysicsBlock> physicsBlock =
        Teuchos::rcp(new PhysicsBlock(ipb,eBlockID,default_int_order,cellData,eqset_factory,gd,false));

    Teuchos::RCP<panzer::IntegrationRule> ir = buildIR(workset_size,4);
    Teuchos::RCP<panzer::BasisIRLayout> layout_qedge1 = Teuchos::rcp(new panzer::BasisIRLayout(basis_qedge1,*ir));

    // build connection manager and field manager
    const Teuchos::RCP<panzer::ConnManager<int,int> > conn_manager = Teuchos::rcp(new panzer_stk_classic::STKConnManager<int>(mesh));
    RCP<panzer::DOFManager<int,int> > dofManager = Teuchos::rcp(new panzer::DOFManager<int,int>(conn_manager,MPI_COMM_WORLD));
    dofManager->addField(fieldName_q1,Teuchos::rcp(new panzer::IntrepidFieldPattern(basis_q1->getIntrepidBasis())));
    dofManager->addField(fieldName_qedge1,Teuchos::rcp(new panzer::IntrepidFieldPattern(basis_qedge1->getIntrepidBasis())));
    dofManager->setOrientationsRequired(true);
    dofManager->buildGlobalUnknowns();

    // build worksets
    std::vector<Teuchos::RCP<panzer::PhysicsBlock> > physicsBlocks;
    physicsBlocks.push_back(physicsBlock); // pushing back singular

    panzer::WorksetContainer wkstContainer(Teuchos::rcp(new panzer_stk_classic::WorksetFactory(mesh)),physicsBlocks,workset_size);
    wkstContainer.setGlobalIndexer(dofManager);

    Teuchos::RCP<std::vector<panzer::Workset> > work_sets = wkstContainer.getVolumeWorksets(physicsBlock->elementBlockID());
    TEST_EQUALITY(work_sets->size(),1);

    // setup field manager, add evaluator under test
    /////////////////////////////////////////////////////////////

    PHX::FieldManager<panzer::Traits> fm;

    {
        Teuchos::ParameterList pl;
        pl.set("Name","Integrand");
        pl.set("IR",ir);
        pl.set("Is Vector",true);
        pl.set<Teuchos::RCP<const PointEvaluation<panzer::Traits::Residual::ScalarT> > >("Point Evaluator",
                Teuchos::rcp(new BilinearPointEvaluator));

        Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator
            = Teuchos::rcp(new PointEvaluator<panzer::Traits::Residual,panzer::Traits>(pl));

        fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
    }

    {
        Teuchos::ParameterList pl;
        pl.set("Residual Name","Residual");
        pl.set("Value Name","Integrand");
        pl.set("Test Field Name",fieldName_qedge1);
        pl.set("Basis",layout_qedge1);
        pl.set("IR",ir);
        pl.set<double>("Multiplier", 1.0);
        Teuchos::RCP<const std::vector<std::string> > vec
            = Teuchos::rcp(new std::vector<std::string>);
        pl.set("Field Multipliers", vec);

        Teuchos::RCP<PHX::Evaluator<panzer::Traits> > evaluator
            = Teuchos::rcp(new panzer::Integrator_BasisTimesVector<panzer::Traits::Residual,panzer::Traits>(pl));

        fm.registerEvaluator<panzer::Traits::Residual>(evaluator);
        fm.requireField<panzer::Traits::Residual>(*evaluator->evaluatedFields()[0]);
    }

    std::vector<PHX::index_size_type> derivative_dimensions;
    derivative_dimensions.push_back(8);
    fm.setKokkosExtendedDataTypeDimensions<panzer::Traits::Jacobian>(derivative_dimensions);

    panzer::Traits::SetupData sd;
    sd.worksets_ = work_sets;
    fm.postRegistrationSetup(sd);

    // run tests
    /////////////////////////////////////////////////////////////

    panzer::Workset & workset = (*work_sets)[0];
    workset.alpha = 0.0;
    workset.beta = 0.0;
    workset.time = 0.0;
    workset.evaluate_transient_terms = false;

    fm.evaluateFields<panzer::Traits::Residual>(workset);

    PHX::MDField<panzer::Traits::Residual::ScalarT,panzer::Cell,panzer::BASIS>
    fieldData_qedge1("Residual",basis_qedge1->functional);

    fm.getFieldData<panzer::Traits::Residual::ScalarT,panzer::Traits::Residual>(fieldData_qedge1);

    TEST_EQUALITY(fieldData_qedge1.dimension(0),1);
    TEST_EQUALITY(fieldData_qedge1.dimension(1),4);

    // Transformation is [x,y] = F[x_ref,y_ref] = 0.5*[1,1]+0.5*[1,0;0,1]*[x_ref,y_ref]
    // therefore transformation matrix is DF^{-T} = 2*[1,0;0,1]
    // so curl vector u_ref:Ref_coord=>Ref_Vec transforms with
    //
    //           u(x,y)=DF^{-T}*u_ref(F^{-1}(x,y))

    TEST_FLOATING_EQUALITY(fieldData_qedge1(0,0),5.0/12.0,1e-5);        // 0 edge basis is [(1-y_ref)/4, 0]
    TEST_FLOATING_EQUALITY(fieldData_qedge1(0,2),3.0/4.0,1e-5);         // 2 edge basis is [(1+y_ref)/4, 0]

    // these two have sign changes because of the mesh topology!
    TEST_FLOATING_EQUALITY(fieldData_qedge1(0,1),0.428925006266,1e-5);  // 1 edge basis is [(1+x_ref)/4, 0]
    TEST_FLOATING_EQUALITY(fieldData_qedge1(0,3),0.344719536524,1e-5);  // 3 edge basis is [(1-x_ref)/4, 0]
}