void StVenantKirchhoffModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields)
{
  // extract dependent MDFields
  PHX::MDField<ScalarT> def_grad = *dep_fields["F"];
  PHX::MDField<ScalarT> J = *dep_fields["J"];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];
  // extract evaluated MDFields
  std::string cauchy = (*field_name_map_)["Cauchy_Stress"];
  PHX::MDField<ScalarT> stress = *eval_fields[cauchy];
  ScalarT lambda;
  ScalarT mu;

  Intrepid::Tensor<ScalarT> F(num_dims_), C(num_dims_), sigma(num_dims_);
  Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
  Intrepid::Tensor<ScalarT> S(num_dims_), E(num_dims_);

  for (int cell(0); cell < workset.numCells; ++cell) {
    for (int pt(0); pt < num_pts_; ++pt) {
      lambda = (elastic_modulus(cell, pt) * poissons_ratio(cell, pt))
          / (1. + poissons_ratio(cell, pt))
          / (1 - 2 * poissons_ratio(cell, pt));
      mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt)));
      F.fill(def_grad,cell, pt,0,0);
      C = F * transpose(F);
      E = 0.5 * ( C - I );
      S = lambda * Intrepid::trace(E) * I + 2.0 * mu * E;
      sigma = (1.0 / Intrepid::det(F) ) * F * S * Intrepid::transpose(F);
      for (int i = 0; i < num_dims_; ++i) {
        for (int j = 0; j < num_dims_; ++j) {
          stress(cell, pt, i, j) = sigma(i, j);
        }
      }
    }
  }
}
void HyperelasticDamageModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields)
{
  // extract dependent MDFields
  PHX::MDField<ScalarT> def_grad = *dep_fields["F"];
  PHX::MDField<ScalarT> J = *dep_fields["J"];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];
  PHX::MDField<ScalarT> delta_time = *dep_fields["Delta Time"];
  // extract evaluated MDFields
  std::string cauchy = (*field_name_map_)["Cauchy_Stress"];
  PHX::MDField<ScalarT> stress = *eval_fields[cauchy];
  PHX::MDField<ScalarT> alpha = *eval_fields["alpha"];
  PHX::MDField<ScalarT> damage;
  if (!have_damage_) {
    damage = *eval_fields["local damage"];
  }
  PHX::MDField<ScalarT> source = *eval_fields["Damage_Source"];
  //get state variables
  Albany::MDArray alpha_old = (*workset.stateArrayPtr)["alpha_old"];
  ScalarT kappa;
  ScalarT mu, mubar;
  ScalarT Jm53, Jm23;
  ScalarT smag;
  ScalarT energy;
  ScalarT dt = delta_time(0);

  Intrepid::Tensor<ScalarT> F(num_dims_), b(num_dims_), sigma(num_dims_);
  Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
  Intrepid::Tensor<ScalarT> s(num_dims_), n(num_dims_);

  for (int cell(0); cell < workset.numCells; ++cell) {
    for (int pt(0); pt < num_pts_; ++pt) {
      kappa = elastic_modulus(cell, pt)
          / (3. * (1. - 2. * poissons_ratio(cell, pt)));
      mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt)));
      Jm53 = std::pow(J(cell, pt), -5. / 3.);
      Jm23 = Jm53 * J(cell, pt);

      F.fill(def_grad,cell, pt,0,0);
      b = F * transpose(F);
      mubar = (1.0 / 3.0) * mu * Jm23 * Intrepid::trace(b);
      sigma = 0.5 * kappa * (J(cell, pt) - 1. / J(cell, pt)) * I
          + mu * Jm53 * Intrepid::dev(b);

      energy = 0.5 * kappa
          * (0.5 * (J(cell, pt) * J(cell, pt) - 1.0) - std::log(J(cell, pt)))
          + 0.5 * mu * (Jm23 * Intrepid::trace(b) - 3.0);

      if (have_temperature_) {
        ScalarT delta_temp = temperature_(cell, pt) - ref_temperature_;
        energy += heat_capacity_
            * ((delta_temp) - temperature_(cell, pt)
                * std::log(temperature_(cell, pt) / ref_temperature_))
            - 3.0 * expansion_coeff_ * (J(cell, pt) - 1.0 / J(cell, pt))
                * delta_temp;
        sigma -= expansion_coeff_ * (1.0 + 1.0 / (J(cell, pt) * J(cell, pt)))
            * delta_temp * I;
      }

      alpha(cell, pt) = std::max((ScalarT) alpha_old(cell, pt), energy);

      source(cell, pt) = (max_damage_ / damage_saturation_)
          * std::exp(-alpha(cell, pt) / damage_saturation_)
          * (alpha(cell, pt) - alpha_old(cell, pt)) / dt;

      if (!have_damage_) {
        damage(cell, pt) = max_damage_
            * (1.0 - std::exp(-alpha(cell, pt) / damage_saturation_));
      }

      for (int i = 0; i < num_dims_; ++i) {
        for (int j = 0; j < num_dims_; ++j) {
          stress(cell, pt, i, j) = (1.0 - damage(cell, pt)) * sigma(i, j);
        }
      }
    }
  }
}
Esempio n. 3
0
void DruckerPragerModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields)
{
  // extract dependent MDFields
  PHX::MDField<ScalarT> strain = *dep_fields["Strain"];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];
   
  // retrieve appropriate field name strings
  std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
  std::string strain_string = (*field_name_map_)["Strain"];
  std::string eqps_string = (*field_name_map_)["eqps"];
  std::string friction_string = (*field_name_map_)["Friction_Parameter"];
    
  // extract evaluated MDFields
  PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string];
  PHX::MDField<ScalarT> eqps = *eval_fields[eqps_string];
  PHX::MDField<ScalarT> friction = *eval_fields[friction_string];
  PHX::MDField<ScalarT> tangent = *eval_fields["Material Tangent"];
    
  // get State Variables
  Albany::MDArray strainold = (*workset.stateArrayPtr)[strain_string + "_old"];
  Albany::MDArray stressold = (*workset.stateArrayPtr)[cauchy_string + "_old"];
  Albany::MDArray eqpsold = (*workset.stateArrayPtr)[eqps_string + "_old"];
  Albany::MDArray frictionold = (*workset.stateArrayPtr)[friction_string + "_old"];

  Intrepid::Tensor<ScalarT> id(Intrepid::eye<ScalarT>(num_dims_));    
  Intrepid::Tensor4<ScalarT> id1(Intrepid::identity_1<ScalarT>(num_dims_));
  Intrepid::Tensor4<ScalarT> id2(Intrepid::identity_2<ScalarT>(num_dims_));
  Intrepid::Tensor4<ScalarT> id3(Intrepid::identity_3<ScalarT>(num_dims_));
    
  Intrepid::Tensor4<ScalarT> Celastic (num_dims_);
  Intrepid::Tensor<ScalarT> sigma(num_dims_), sigmaN(num_dims_), s(num_dims_);
  Intrepid::Tensor<ScalarT> epsilon(num_dims_), epsilonN(num_dims_);
  Intrepid::Tensor<ScalarT> depsilon(num_dims_);
  Intrepid::Tensor<ScalarT> nhat(num_dims_);
    
  ScalarT lambda, mu, kappa;
  ScalarT alpha, alphaN;
  ScalarT p, q, ptr, qtr;
  ScalarT eq, eqN, deq;
  ScalarT snorm;
  ScalarT Phi;
  
  //local unknowns and residual vectors
  std::vector<ScalarT> X(4);
  std::vector<ScalarT> R(4);
  std::vector<ScalarT> dRdX(16);
    
  for (std::size_t cell(0); cell < workset.numCells; ++cell) {
    for (std::size_t pt(0); pt < num_pts_; ++pt) {
      lambda = ( elastic_modulus(cell,pt) * poissons_ratio(cell,pt) ) 
        / ( ( 1 + poissons_ratio(cell,pt) ) * ( 1 - 2 * poissons_ratio(cell,pt) ) );
      mu = elastic_modulus(cell,pt) / ( 2 * ( 1 + poissons_ratio(cell,pt) ) );
      kappa = lambda + 2.0 * mu / 3.0;
    
      // 4-th order elasticity tensor
      Celastic = lambda * id3 + mu * (id1 + id2);
        
      // previous state (the fill doesn't work for state virable)
      //sigmaN.fill( &stressold(cell,pt,0,0) );
      //epsilonN.fill( &strainold(cell,pt,0,0) );

      for (std::size_t i(0); i < num_dims_; ++i) {
        for (std::size_t j(0); j < num_dims_; ++j) {
          sigmaN(i, j) = stressold(cell, pt, i, j);
          epsilonN(i, j) = strainold(cell, pt, i, j);
          //epsilon(i,j) = strain(cell,pt,i,j);
        }
      }
             
      epsilon.fill( &strain(cell,pt,0,0) );
      depsilon = epsilon - epsilonN;                                 
        
      alphaN = frictionold(cell,pt);
      eqN = eqpsold(cell,pt);
        
      // trial state
      sigma = sigmaN + Intrepid::dotdot(Celastic,depsilon);
      ptr = Intrepid::trace(sigma) / 3.0;
      s = sigma - ptr * id;
      snorm = Intrepid::dotdot(s,s);  
      if(snorm > 0) snorm = std::sqrt(snorm);
      qtr = sqrt(3.0/2.0) * snorm;

      // unit deviatoric tensor      
      if (snorm > 0){
        nhat = s / snorm;
       } else{
        nhat = id;
       }
      
      // check yielding
      Phi = qtr + alphaN * ptr - Cf_;
      
      alpha = alphaN;
      p = ptr;
      q = qtr;
      deq = 0.0;
      if(Phi > 1.0e-12) {// plastic yielding  
        
        // initialize local unknown vector
        X[0] = ptr;
        X[1] = qtr;
        X[2] = alpha;
        X[3] = deq;
         
        LocalNonlinearSolver<EvalT, Traits> solver;
        int iter = 0;
        ScalarT norm_residual0(0.0), norm_residual(0.0), relative_residual(0.0);
          
        // local N-R loop
        while (true) {
              
          ResidualJacobian(X, R, dRdX, ptr, qtr, eqN, mu, kappa);
            
          norm_residual = 0.0;
            for (int i = 0; i < 4; i++)
                norm_residual += R[i] * R[i];
          norm_residual = std::sqrt(norm_residual);
            
          if (iter == 0)
            norm_residual0 = norm_residual;
             
          if (norm_residual0 != 0)
              relative_residual = norm_residual / norm_residual0;
          else
              relative_residual = norm_residual0;
            
          //std::cout << iter << " "
          //<< Sacado::ScalarValue<ScalarT>::eval(norm_residual)
            //<< " " << Sacado::ScalarValue<ScalarT>::eval(relative_residual)
            //<< std::endl;
            
          if (relative_residual < 1.0e-11 || norm_residual < 1.0e-11)
              break;
            
          if (iter > 20)
              break;
            
          // call local nonlinear solver
          solver.solve(dRdX, X, R);
            
          iter++;           
              
        } // end of local N-R loop        

      // compute sensitivity information w.r.t. system parameters
      // and pack the sensitivity back to X
      solver.computeFadInfo(dRdX, X, R);        
      
      // update
      p = X[0];
      q = X[1];
      alpha = X[2];
      deq = X[3];
    
      }//end plastic yielding      
          
      eq = eqN + deq;
        
      s = sqrt(2.0/3.0) * q * nhat;
      sigma = s + p * id;
      
      eqps(cell, pt) = eq;
      friction(cell,pt) = alpha;
        
      for (std::size_t i(0); i < num_dims_; ++i) {
        for (std::size_t j(0); j < num_dims_; ++j) {
              stress(cell,pt,i,j) = sigma(i, j);
            }
        }      
         
    }// end loop over pt
  } //  end loop over cell
}
void ElasticDamageModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> eval_fields)
{
  //bool print = false;
  //if (typeid(ScalarT) == typeid(RealType)) print = true;
  //cout.precision(15);

  // extract dependent MDFields
  PHX::MDField<ScalarT> strain = *dep_fields["Strain"];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];

  // retrieve appropriate field name strings
  std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
  std::string energy_string = (*field_name_map_)["Matrix_Energy"];
  std::string damage_string = (*field_name_map_)["Matrix_Damage"];
  std::string tangent_string = (*field_name_map_)["Material Tangent"];

  // extract evaluated MDFields
  PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string];
  PHX::MDField<ScalarT> energy = *eval_fields[energy_string];
  PHX::MDField<ScalarT> damage = *eval_fields[damage_string];
  PHX::MDField<ScalarT> tangent;
    
  if(compute_tangent_) {
    tangent = *eval_fields[tangent_string];
  }

  // previous state
  Albany::MDArray energy_old =
      (*workset.stateArrayPtr)[energy_string + "_old"];

  ScalarT mu, lame;
  ScalarT alpha, damage_deriv;

  // Define some tensors for use
  Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
  Intrepid::Tensor<ScalarT> epsilon(num_dims_), sigma(num_dims_);

  Intrepid::Tensor4<ScalarT> Ce(num_dims_);
  Intrepid::Tensor4<ScalarT> id4(num_dims_);
  Intrepid::Tensor4<ScalarT> id3(Intrepid::identity_3<ScalarT>(num_dims_));

  id4 = 0.5 * (Intrepid::identity_1<ScalarT>(num_dims_)
      + Intrepid::identity_2<ScalarT>(num_dims_));

  for (int cell = 0; cell < workset.numCells; ++cell) {
    for (int pt = 0; pt < num_pts_; ++pt) {
      // local parameters
      mu = elastic_modulus(cell, pt)
          / (2.0 * (1.0 + poissons_ratio(cell, pt)));
      lame = elastic_modulus(cell, pt) * poissons_ratio(cell, pt)
          / (1.0 + poissons_ratio(cell, pt))
          / (1.0 - 2.0 * poissons_ratio(cell, pt));

      // small strain tensor
      epsilon.fill(strain,cell, pt,0,0);

      // undamaged elasticity tensor
      Ce = lame * id3 + 2.0 * mu * id4;

      // undamaged energy
      energy(cell, pt) =
          0.5 * Intrepid::dotdot(Intrepid::dotdot(epsilon, Ce), epsilon);

      // undamaged Cauchy stress
      sigma = Intrepid::dotdot(Ce, epsilon);

      // maximum thermodynamic force
      alpha = energy_old(cell, pt);
      if (energy(cell, pt) > alpha) alpha = energy(cell, pt);

      // damage term
      damage(cell, pt) = max_damage_
          * (1 - std::exp(-alpha / saturation_));

      // derivative of damage w.r.t alpha
      damage_deriv =
          max_damage_ / saturation_ * std::exp(-alpha / saturation_);

      // tangent for matrix considering damage
      if(compute_tangent_) {
        Ce = (1.0 - damage(cell, pt)) * Ce
          - damage_deriv * Intrepid::tensor(sigma, sigma);
      }

      // total Cauchy stress
      for (int i(0); i < num_dims_; ++i) {
        for (int j(0); j < num_dims_; ++j) {
          stress(cell, pt, i, j) =
              (1.0 - damage(cell, pt)) * sigma(i, j);
        }
      }

      // total tangent
      if(compute_tangent_) {
        for (int i(0); i < num_dims_; ++i) {
          for (int j(0); j < num_dims_; ++j) {
            for (int k(0); k < num_dims_; ++k) {
              for (int l(0); l < num_dims_; ++l) {

                tangent(cell, pt, i, j, k, l) = Ce(i, j, k, l);

              }
            }
          }
        }
      }// compute_tangent_

    } // pt
  } // cell
}
void AnisotropicHyperelasticDamageModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT>>> eval_fields)
{
  bool print = false;
  //if (typeid(ScalarT) == typeid(RealType)) print = true;
  //cout.precision(15);

  // retrive appropriate field name strings
  std::string F_string = (*field_name_map_)["F"];
  std::string J_string = (*field_name_map_)["J"];
  std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
  std::string matrix_energy_string = (*field_name_map_)["Matrix_Energy"];
  std::string f1_energy_string = (*field_name_map_)["F1_Energy"];
  std::string f2_energy_string = (*field_name_map_)["F2_Energy"];
  std::string matrix_damage_string = (*field_name_map_)["Matrix_Damage"];
  std::string f1_damage_string = (*field_name_map_)["F1_Damage"];
  std::string f2_damage_string = (*field_name_map_)["F2_Damage"];

  // extract dependent MDFields
  PHX::MDField<ScalarT> def_grad = *dep_fields[F_string];
  PHX::MDField<ScalarT> J = *dep_fields[J_string];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];

  // extract evaluated MDFields
  PHX::MDField<ScalarT> stress = *eval_fields[cauchy_string];
  PHX::MDField<ScalarT> energy_m = *eval_fields[matrix_energy_string];
  PHX::MDField<ScalarT> energy_f1 = *eval_fields[f1_energy_string];
  PHX::MDField<ScalarT> energy_f2 = *eval_fields[f2_energy_string];
  PHX::MDField<ScalarT> damage_m = *eval_fields[matrix_damage_string];
  PHX::MDField<ScalarT> damage_f1 = *eval_fields[f1_damage_string];
  PHX::MDField<ScalarT> damage_f2 = *eval_fields[f2_damage_string];

  // previous state
  Albany::MDArray energy_m_old =
      (*workset.stateArrayPtr)[matrix_energy_string + "_old"];
  Albany::MDArray energy_f1_old =
      (*workset.stateArrayPtr)[f1_energy_string + "_old"];
  Albany::MDArray energy_f2_old =
      (*workset.stateArrayPtr)[f2_energy_string + "_old"];

  ScalarT kappa, mu, Jm53, Jm23, p, I4_f1, I4_f2;
  ScalarT alpha_f1, alpha_f2, alpha_m;

  // Define some tensors for use
  Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
  Intrepid::Tensor<ScalarT> F(num_dims_), s(num_dims_), b(num_dims_), C(
      num_dims_);
  Intrepid::Tensor<ScalarT> sigma_m(num_dims_), sigma_f1(num_dims_), sigma_f2(
      num_dims_);
  Intrepid::Tensor<ScalarT> M1dyadM1(num_dims_), M2dyadM2(num_dims_);
  Intrepid::Tensor<ScalarT> S0_f1(num_dims_), S0_f2(num_dims_);

  Intrepid::Vector<ScalarT> M1(num_dims_), M2(num_dims_);

  for (int cell = 0; cell < workset.numCells; ++cell) {
    for (int pt = 0; pt < num_pts_; ++pt) {
      // local parameters
      kappa = elastic_modulus(cell, pt)
          / (3. * (1. - 2. * poissons_ratio(cell, pt)));
      mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt)));
      Jm53 = std::pow(J(cell, pt), -5. / 3.);
      Jm23 = std::pow(J(cell, pt), -2. / 3.);
      F.fill(def_grad,cell, pt,0,0);

      // compute deviatoric stress
      b = F * Intrepid::transpose(F);
      s = mu * Jm53 * Intrepid::dev(b);
      // compute pressure
      p = 0.5 * kappa * (J(cell, pt) - 1. / (J(cell, pt)));

      sigma_m = s + p * I;

      // compute energy for M
      energy_m(cell, pt) = 0.5 * kappa
          * (0.5 * (J(cell, pt) * J(cell, pt) - 1.0) - std::log(J(cell, pt)))
          + 0.5 * mu * (Jm23 * Intrepid::trace(b) - 3.0);

      // damage term in M
      alpha_m = energy_m_old(cell, pt);
      if (energy_m(cell, pt) > alpha_m) alpha_m = energy_m(cell, pt);

      damage_m(cell, pt) = max_damage_m_
          * (1 - std::exp(-alpha_m / saturation_m_));

      //-----------compute stress in Fibers

      // Right Cauchy-Green Tensor C = F^{T} * F
      C = Intrepid::transpose(F) * F;

      // Fiber orientation vectors
      //
      // fiber 1
      for (int i = 0; i < num_dims_; ++i) {
        M1(i) = direction_f1_[i];
      }
      M1 = M1 / norm(M1);

      // fiber 2
      for (int i = 0; i < num_dims_; ++i) {
        M2(i) = direction_f2_[i];
      }
      M2 = M2 / norm(M2);

      // Anisotropic invariants I4 = M_{i} * C * M_{i}
      I4_f1 = Intrepid::dot(M1, Intrepid::dot(C, M1));
      I4_f2 = Intrepid::dot(M2, Intrepid::dot(C, M2));
      M1dyadM1 = Intrepid::dyad(M1, M1);
      M2dyadM2 = Intrepid::dyad(M2, M2);

      // undamaged stress (2nd PK stress)
      S0_f1 = (4.0 * k_f1_ * (I4_f1 - 1.0)
          * std::exp(q_f1_ * (I4_f1 - 1) * (I4_f1 - 1))) * M1dyadM1;
      S0_f2 = (4.0 * k_f2_ * (I4_f2 - 1.0)
          * std::exp(q_f2_ * (I4_f2 - 1) * (I4_f2 - 1))) * M2dyadM2;

      // compute energy for fibers
      energy_f1(cell, pt) = k_f1_
          * (std::exp(q_f1_ * (I4_f1 - 1) * (I4_f1 - 1)) - 1) / q_f1_;
      energy_f2(cell, pt) = k_f2_
          * (std::exp(q_f2_ * (I4_f2 - 1) * (I4_f2 - 1)) - 1) / q_f2_;

      // Fiber Cauchy stress
      sigma_f1 = (1.0 / J(cell, pt))
          * Intrepid::dot(F, Intrepid::dot(S0_f1, Intrepid::transpose(F)));
      sigma_f2 = (1.0 / J(cell, pt))
          * Intrepid::dot(F, Intrepid::dot(S0_f2, Intrepid::transpose(F)));

      // maximum thermodynamic forces
      alpha_f1 = energy_f1_old(cell, pt);
      alpha_f2 = energy_f2_old(cell, pt);

      if (energy_f1(cell, pt) > alpha_f1) alpha_f1 = energy_f1(cell, pt);

      if (energy_f2(cell, pt) > alpha_f2) alpha_f2 = energy_f2(cell, pt);

      // damage term in fibers
      damage_f1(cell, pt) = max_damage_f1_
          * (1 - std::exp(-alpha_f1 / saturation_f1_));
      damage_f2(cell, pt) = max_damage_f2_
          * (1 - std::exp(-alpha_f2 / saturation_f2_));

      // total Cauchy stress (M, Fibers)
      for (int i(0); i < num_dims_; ++i) {
        for (int j(0); j < num_dims_; ++j) {
          stress(cell, pt, i, j) =
              volume_fraction_m_ * (1 - damage_m(cell, pt)) * sigma_m(i, j)
                  + volume_fraction_f1_ * (1 - damage_f1(cell, pt))
                      * sigma_f1(i, j)
                  + volume_fraction_f2_ * (1 - damage_f2(cell, pt))
                      * sigma_f2(i, j);
        }
      }

      if (print) {
        std::cout << "  matrix damage: " << damage_m(cell, pt) << std::endl;
        std::cout << "  matrix energy: " << energy_m(cell, pt) << std::endl;
        std::cout << "  fiber1 damage: " << damage_f1(cell, pt) << std::endl;
        std::cout << "  fiber1 energy: " << energy_f1(cell, pt) << std::endl;
        std::cout << "  fiber2 damage: " << damage_f2(cell, pt) << std::endl;
        std::cout << "  fiber2 energy: " << energy_f2(cell, pt) << std::endl;
      }
    } // pt
  } // cell
}
void ElastoViscoplasticModel<EvalT, Traits>::
computeState(typename Traits::EvalData workset,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > dep_fields,
    std::map<std::string, Teuchos::RCP<PHX::MDField<ScalarT> > > eval_fields)
{
  std::string cauchy_string = (*field_name_map_)["Cauchy_Stress"];
  std::string Fp_string = (*field_name_map_)["Fp"];
  std::string eqps_string = (*field_name_map_)["eqps"];
  std::string eps_ss_string = (*field_name_map_)["eps_ss"];
  std::string kappa_string = (*field_name_map_)["isotropic_hardening"];
  std::string source_string = (*field_name_map_)["Mechanical_Source"];
  std::string F_string = (*field_name_map_)["F"];
  std::string J_string = (*field_name_map_)["J"];

  // extract dependent MDFields
  PHX::MDField<ScalarT> def_grad_field = *dep_fields[F_string];
  PHX::MDField<ScalarT> J = *dep_fields[J_string];
  PHX::MDField<ScalarT> poissons_ratio = *dep_fields["Poissons Ratio"];
  PHX::MDField<ScalarT> elastic_modulus = *dep_fields["Elastic Modulus"];
  PHX::MDField<ScalarT> yield_strength = *dep_fields["Yield Strength"];
  PHX::MDField<ScalarT> hardening_modulus = *dep_fields["Hardening Modulus"];
  PHX::MDField<ScalarT> recovery_modulus = *dep_fields["Recovery Modulus"];
  PHX::MDField<ScalarT> flow_exp = *dep_fields["Flow Rule Exponent"];
  PHX::MDField<ScalarT> flow_coeff = *dep_fields["Flow Rule Coefficient"];
  PHX::MDField<ScalarT> delta_time = *dep_fields["Delta Time"];

  // extract evaluated MDFields
  PHX::MDField<ScalarT> stress_field = *eval_fields[cauchy_string];
  PHX::MDField<ScalarT> Fp_field = *eval_fields[Fp_string];
  PHX::MDField<ScalarT> eqps_field = *eval_fields[eqps_string];
  PHX::MDField<ScalarT> eps_ss_field = *eval_fields[eps_ss_string];
  PHX::MDField<ScalarT> kappa_field = *eval_fields[kappa_string];
  PHX::MDField<ScalarT> source_field;
  if (have_temperature_) {
    source_field = *eval_fields[source_string];
  }

  // get State Variables
  Albany::MDArray Fp_field_old     = (*workset.stateArrayPtr)[Fp_string + "_old"];
  Albany::MDArray eqps_field_old   = (*workset.stateArrayPtr)[eqps_string + "_old"];
  Albany::MDArray eps_ss_field_old = (*workset.stateArrayPtr)[eps_ss_string + "_old"];
  Albany::MDArray kappa_field_old  = (*workset.stateArrayPtr)[kappa_string + "_old"];

  // define constants
  RealType sq23(std::sqrt(2. / 3.));
  RealType sq32(std::sqrt(3. / 2.));

  // pre-define some tensors that will be re-used below
  Intrepid::Tensor<ScalarT> F(num_dims_), be(num_dims_);
  Intrepid::Tensor<ScalarT> s(num_dims_), sigma(num_dims_);
  Intrepid::Tensor<ScalarT> N(num_dims_), A(num_dims_);
  Intrepid::Tensor<ScalarT> expA(num_dims_), Fpnew(num_dims_);
  Intrepid::Tensor<ScalarT> I(Intrepid::eye<ScalarT>(num_dims_));
  Intrepid::Tensor<ScalarT> Fpn(num_dims_), Cpinv(num_dims_), Fpinv(num_dims_);

  for (std::size_t cell(0); cell < workset.numCells; ++cell) {
    for (std::size_t pt(0); pt < num_pts_; ++pt) {
      ScalarT bulk = elastic_modulus(cell, pt)
          / (3. * (1. - 2. * poissons_ratio(cell, pt)));
      ScalarT mu = elastic_modulus(cell, pt) / (2. * (1. + poissons_ratio(cell, pt)));
      ScalarT Y = yield_strength(cell, pt);
      ScalarT Jm23 = std::pow(J(cell, pt), -2. / 3.);

      // assign local state variables
      //
      //ScalarT kappa = kappa_field(cell,pt);
      ScalarT kappa_old = kappa_field_old(cell,pt);
      ScalarT eps_ss = eps_ss_field(cell,pt);
      ScalarT eps_ss_old = eps_ss_field_old(cell,pt);
      ScalarT eqps_old = eqps_field_old(cell,pt);

      // fill local tensors
      //
      F.fill(&def_grad_field(cell, pt, 0, 0));
      for (std::size_t i(0); i < num_dims_; ++i) {
        for (std::size_t j(0); j < num_dims_; ++j) {
          Fpn(i, j) = ScalarT(Fp_field_old(cell, pt, i, j));
        }
      }

      // compute trial state
      // compute the Kirchhoff stress in the current configuration
      //
      Cpinv = Intrepid::inverse(Fpn) * Intrepid::transpose(Intrepid::inverse(Fpn));
      be = Jm23 * F * Cpinv * Intrepid::transpose(F);
      s = mu * Intrepid::dev(be);
      ScalarT smag = Intrepid::norm(s);
      ScalarT mubar = Intrepid::trace(be) * mu / (num_dims_);
      
      // check yield condition
      //
      ScalarT Phi = sq32 * smag - ( Y + kappa_old );

      std::cout << "======== Phi: " << Phi << std::endl;
      std::cout << "======== eps: " << std::numeric_limits<RealType>::epsilon() << std::endl;

      if (Phi > std::numeric_limits<RealType>::epsilon()) {

        // return mapping algorithm
        //
        bool converged = false;
        int iter = 0;
        RealType max_norm = std::numeric_limits<RealType>::min();

        // hardening and recovery parameters
        //
        ScalarT H = hardening_modulus(cell, pt);
        ScalarT Rd = recovery_modulus(cell, pt);

        // flow rule temperature dependent parameters
        //
        ScalarT f = flow_coeff(cell,pt);
        ScalarT n = flow_exp(cell,pt);

        // This solver deals with Sacado type info
        //
        LocalNonlinearSolver<EvalT, Traits> solver;

        // create some vectors to store solver data
        //
        std::vector<ScalarT> R(2);
        std::vector<ScalarT> dRdX(4);
        std::vector<ScalarT> X(2);

        // initial guess
        X[0] = 0.0;
        X[1] = eps_ss_old;

        // create a copy of be as a Fad
        Intrepid::Tensor<Fad> beF(num_dims_);
        for (std::size_t i = 0; i < num_dims_; ++i) {
          for (std::size_t j = 0; j < num_dims_; ++j) {
            beF(i, j) = be(i, j);
          }
        }
        Fad two_mubarF = 2.0 * Intrepid::trace(beF) * mu / (num_dims_);
        //Fad sq32F = std::sqrt(3.0/2.0);
        // FIXME this seems to be necessary to get PhiF to compile below
        // need to look into this more, it appears to be a conflict
        // between the Intrepid::norm and FadType operations
        //
        Fad smagF = smag;

        while (!converged) {

          // set up data types
          //
          std::vector<Fad> XFad(2);
          std::vector<Fad> RFad(2);
          std::vector<ScalarT> Xval(2);
          for (std::size_t i = 0; i < 2; ++i) {
            Xval[i] = Sacado::ScalarValue<ScalarT>::eval(X[i]);
            XFad[i] = Fad(2, i, Xval[i]);
          }

          // get solution vars
          //
          Fad dgamF = XFad[0];
          Fad eps_ssF = XFad[1];

          // compute yield function
          //
          Fad eqps_rateF = 0.0;
          if (delta_time(0) > 0) eqps_rateF = sq23 * dgamF / delta_time(0);
          Fad rate_termF = 1.0 + std::asinh( std::pow(eqps_rateF / f, n));
          Fad kappaF = two_mubarF * eps_ssF;
          Fad PhiF = sq32 * (smagF - two_mubarF * dgamF) - ( Y + kappaF ) * rate_termF;

          // compute the hardening residual
          //
          Fad eps_resF = eps_ssF - eps_ss_old - (H - Rd*eps_ssF) * dgamF;

          // for convenience put the residuals into a container
          //
          RFad[0] = PhiF;
          RFad[1] = eps_resF;

          // extract the values of the residuals
          //
          for (int i = 0; i < 2; ++i)
            R[i] = RFad[i].val();

          // extract the sensitivities of the residuals
          //
          for (int i = 0; i < 2; ++i)
            for (int j = 0; j < 2; ++j)
              dRdX[i + 2 * j] = RFad[i].dx(j);

          // this call invokes the solver and updates the solution in X
          //
          solver.solve(dRdX, X, R);

          // compute the norm of the residual
          //
          RealType R0 = Sacado::ScalarValue<ScalarT>::eval(R[0]); 
          RealType R1 = Sacado::ScalarValue<ScalarT>::eval(R[1]);
          RealType norm_res = std::sqrt(R0*R0 + R1*R1);
          max_norm = std::max(norm_res, max_norm);
            
          // check against too many inerations
          //
          TEUCHOS_TEST_FOR_EXCEPTION(iter == 30, std::runtime_error,
                                     std::endl <<
                                     "Error in ElastoViscoplastic return mapping\n" <<
                                     "iter count = " << iter << "\n" << std::endl);

          // check for a sufficiently small residual
          //
          std::cout << "======== norm_res : " << norm_res << std::endl;
          if ( (norm_res/max_norm < 1.e-12) || (norm_res < 1.e-12) )
            converged = true;

          // increment the iteratio counter
          //
          iter++;
        }

        solver.computeFadInfo(dRdX, X, R);
        ScalarT dgam = X[0];
        ScalarT eps_ss = X[1];
        ScalarT kappa = 2.0 * mubar * eps_ss;

        std::cout << "======== dgam : " << dgam << std::endl;
        std::cout << "======== e_ss : " << eps_ss << std::endl;
        std::cout << "======== kapp : " << kappa << std::endl;

        // plastic direction
        N = (1 / smag) * s;

        // update s
        s -= 2 * mubar * dgam * N;

        // update state variables
        eps_ss_field(cell, pt) = eps_ss;
        eqps_field(cell,pt) = eqps_old + sq23 * dgam;
        kappa_field(cell,pt) = kappa;

        // mechanical source
        // FIXME this is not correct, just a placeholder
        //
        if (have_temperature_ && delta_time(0) > 0) {
          source_field(cell, pt) = (sq23 * dgam / delta_time(0))
            * (Y + kappa) / (density_ * heat_capacity_);
        }

        // exponential map to get Fpnew
        //
        A = dgam * N;
        expA = Intrepid::exp(A);
        Fpnew = expA * Fpn;
        for (std::size_t i(0); i < num_dims_; ++i) {
          for (std::size_t j(0); j < num_dims_; ++j) {
            Fp_field(cell, pt, i, j) = Fpnew(i, j);
          }
        }
      } else {
        // we are not yielding, variables do not evolve
        //
        eps_ss_field(cell, pt) = eps_ss_old;
        eqps_field(cell,pt) = eqps_old;
        kappa_field(cell,pt) = kappa_old;
        if (have_temperature_) source_field(cell, pt) = 0.0;
        for (std::size_t i(0); i < num_dims_; ++i) {
          for (std::size_t j(0); j < num_dims_; ++j) {
            Fp_field(cell, pt, i, j) = Fpn(i, j);
          }
        }
      }

      // compute pressure
      ScalarT p = 0.5 * bulk * (J(cell, pt) - 1. / (J(cell, pt)));

      // compute stress
      sigma = p * I + s / J(cell, pt);
      for (std::size_t i(0); i < num_dims_; ++i) {
        for (std::size_t j(0); j < num_dims_; ++j) {
          stress_field(cell, pt, i, j) = sigma(i, j);
        }
      }
    }
  }

  if (have_temperature_) {
    for (std::size_t cell(0); cell < workset.numCells; ++cell) {
      for (std::size_t pt(0); pt < num_pts_; ++pt) {
        F.fill(&def_grad_field(cell,pt,0,0));
        ScalarT J = Intrepid::det(F);
        sigma.fill(&stress_field(cell,pt,0,0));
        sigma -= 3.0 * expansion_coeff_ * (1.0 + 1.0 / (J*J))
          * (temperature_(cell,pt) - ref_temperature_) * I;
        for (std::size_t i = 0; i < num_dims_; ++i) {
          for (std::size_t j = 0; j < num_dims_; ++j) {
            stress_field(cell, pt, i, j) = sigma(i, j);
          }
        }
      }
    }
  }
}