Esempio n. 1
0
void
MultiPlasticityLinearSystem::nrStep(const RankTwoTensor & stress, const std::vector<Real> & intnl_old, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankFourTensor & E_inv, const RankTwoTensor & delta_dp, RankTwoTensor & dstress, std::vector<Real> & dpm, std::vector<Real> & dintnl, const std::vector<bool> & active, std::vector<bool> & deactivated_due_to_ld)
{
  // Calculate RHS and Jacobian
  std::vector<Real> rhs;
  calculateRHS(stress, intnl_old, intnl, pm, delta_dp, rhs, active, true, deactivated_due_to_ld);

  std::vector<std::vector<Real> > jac;
  calculateJacobian(stress, intnl, pm, E_inv, active, deactivated_due_to_ld, jac);


  // prepare for LAPACKgesv_ routine provided by PETSc
  int system_size = rhs.size();

  std::vector<double> a(system_size*system_size);
  // Fill in the a "matrix" by going down columns
  unsigned ind = 0;
  for (int col = 0 ; col < system_size ; ++col)
    for (int row = 0 ; row < system_size ; ++row)
      a[ind++] = jac[row][col];

  int nrhs = 1;
  std::vector<int> ipiv(system_size);
  int info;
  LAPACKgesv_(&system_size, &nrhs, &a[0], &system_size, &ipiv[0], &rhs[0], &system_size, &info);

  if (info != 0)
    mooseError("In solving the linear system in a Newton-Raphson process, the PETSC LAPACK gsev routine returned with error code " << info);



  // Extract the results back to dstress, dpm and dintnl
  std::vector<bool> active_not_deact(_num_surfaces);
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    active_not_deact[surface] = (active[surface] && !deactivated_due_to_ld[surface]);

  unsigned int dim = 3;
  ind = 0;

  for (unsigned i = 0 ; i < dim ; ++i)
    for (unsigned j = 0 ; j <= i ; ++j)
      dstress(i, j) = dstress(j, i) = rhs[ind++];
  dpm.assign(_num_surfaces, 0);
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_not_deact[surface])
      dpm[surface] = rhs[ind++];
  dintnl.assign(_num_models, 0);
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (anyActiveSurfaces(model, active_not_deact))
      dintnl[model] = rhs[ind++];

  mooseAssert(static_cast<int>(ind) == system_size, "Incorrect extracting of changes from NR solution in nrStep");
}
Esempio n. 2
0
bool
MultiPlasticityDebugger::dof_included(unsigned int dof, const std::vector<bool> & deactivated_due_to_ld)
{
  if (dof < unsigned(6))
    // these are the stress components
    return true;
  unsigned eff_dof = dof - 6;
  if (eff_dof < _num_surfaces)
    // these are the plastic multipliers, pm
    return !deactivated_due_to_ld[eff_dof];
  eff_dof -= _num_surfaces; // now we know the dof is an intnl parameter
  std::vector<bool> active_surface(_num_surfaces);
  for (unsigned surface = 0; surface < _num_surfaces; ++surface)
    active_surface[surface] = !deactivated_due_to_ld[surface];
  return anyActiveSurfaces(eff_dof, active_surface);
}
Esempio n. 3
0
void
MultiPlasticityLinearSystem::calculateJacobian(const RankTwoTensor & stress, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankFourTensor & E_inv, const std::vector<bool> & active, const std::vector<bool> & deactivated_due_to_ld, std::vector<std::vector<Real> > & jac)
{
  // see comments at the start of .h file

  mooseAssert(intnl.size() == _num_models, "Size of intnl is " << intnl.size() << " which is incorrect in calculateJacobian");
  mooseAssert(pm.size() == _num_surfaces, "Size of pm is " << pm.size() << " which is incorrect in calculateJacobian");
  mooseAssert(active.size() == _num_surfaces, "Size of active is " << active.size() << " which is incorrect in calculateJacobian");
  mooseAssert(deactivated_due_to_ld.size() == _num_surfaces, "Size of deactivated_due_to_ld is " << deactivated_due_to_ld.size() << " which is incorrect in calculateJacobian");


  unsigned ind = 0;
  unsigned active_surface_ind = 0;


  std::vector<bool> active_surface(_num_surfaces); // active and not deactivated_due_to_ld
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    active_surface[surface] = (active[surface] && !deactivated_due_to_ld[surface]);
  unsigned num_active_surface = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_surface[surface])
      num_active_surface++;

  std::vector<bool> active_model(_num_models); // whether a model has surfaces that are active and not deactivated_due_to_ld
  for (unsigned model = 0 ; model < _num_models ; ++model)
    active_model[model] = anyActiveSurfaces(model, active_surface);

  unsigned num_active_model = 0;
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (active_model[model])
      num_active_model++;

  ind = 0;
  std::vector<unsigned int> active_model_index(_num_models);
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (active_model[model])
      active_model_index[model] = ind++;
    else
      active_model_index[model] = _num_models+1; // just a dummy, that will probably cause a crash if something goes wrong



  std::vector<RankTwoTensor> df_dstress;
  dyieldFunction_dstress(stress, intnl, active_surface, df_dstress);

  std::vector<Real> df_dintnl;
  dyieldFunction_dintnl(stress, intnl, active_surface, df_dintnl);

  std::vector<RankTwoTensor> r;
  flowPotential(stress, intnl, active, r);

  std::vector<RankFourTensor> dr_dstress;
  dflowPotential_dstress(stress, intnl, active, dr_dstress);

  std::vector<RankTwoTensor> dr_dintnl;
  dflowPotential_dintnl(stress, intnl, active, dr_dintnl);

  std::vector<Real> h;
  hardPotential(stress, intnl, active, h);

  std::vector<RankTwoTensor> dh_dstress;
  dhardPotential_dstress(stress, intnl, active, dh_dstress);

  std::vector<Real> dh_dintnl;
  dhardPotential_dintnl(stress, intnl, active, dh_dintnl);




  // d(epp)/dstress = sum_{active alpha} pm[alpha]*dr_dstress
  RankFourTensor depp_dstress;
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active[surface]) // includes deactivated_due_to_ld
      depp_dstress += pm[surface]*dr_dstress[ind++];
  depp_dstress += E_inv;

  // d(epp)/dpm_{active_surface_index} = r_{active_surface_index}
  std::vector<RankTwoTensor> depp_dpm;
  depp_dpm.resize(num_active_surface);
  ind = 0;
  active_surface_ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      if (active_surface[surface]) // do not include the deactived_due_to_ld, since their pm are not dofs in the NR
        depp_dpm[active_surface_ind++] = r[ind];
      ind++;
    }
  }

  // d(epp)/dintnl_{active_model_index} = sum(pm[asdf]*dr_dintnl[fdsa])
  std::vector<RankTwoTensor> depp_dintnl;
  depp_dintnl.assign(num_active_model, RankTwoTensor());
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only include models with surfaces which are still active after deactivated_due_to_ld
        depp_dintnl[active_model_index[model_num]] += pm[surface]*dr_dintnl[ind];
      ind++;
    }
  }


  // df_dstress has been calculated above
  // df_dpm is always zero
  // df_dintnl has been calculated above, but only the active_surface+active_model stuff needs to be included in Jacobian: see below

  std::vector<RankTwoTensor> dic_dstress;
  dic_dstress.assign(num_active_model, RankTwoTensor());
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only include ic for models with active_surface (ie, if model only contains deactivated_due_to_ld don't include it)
        dic_dstress[active_model_index[model_num]] += pm[surface]*dh_dstress[ind];
      ind++;
    }
  }


  std::vector<std::vector<Real> > dic_dpm;
  dic_dpm.resize(num_active_model);
  ind = 0;
  active_surface_ind = 0;
  for (unsigned model = 0 ; model < num_active_model ; ++model)
    dic_dpm[model].assign(num_active_surface, 0);
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      if (active_surface[surface]) // only take derivs wrt active-but-not-deactivated_due_to_ld pm
      {
        unsigned int model_num = modelNumber(surface);
        // if (active_model[model_num]) // do not need this check as if the surface has active_surface, the model must be deemed active!
          dic_dpm[active_model_index[model_num]][active_surface_ind] = h[ind];
        active_surface_ind++;
      }
      ind++;
    }
  }


  std::vector<std::vector<Real> > dic_dintnl;
  dic_dintnl.resize(num_active_model);
  for (unsigned model = 0 ; model < num_active_model ; ++model)
  {
    dic_dintnl[model].assign(num_active_model, 0);
    dic_dintnl[model][model] = 1; // deriv wrt internal parameter
  }
  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
  {
    if (active[surface])
    {
      unsigned int model_num = modelNumber(surface);
      if (active_model[model_num]) // only the models that contain surfaces that are still active after deactivation_due_to_ld
        dic_dintnl[active_model_index[model_num]][active_model_index[model_num]] += pm[surface]*dh_dintnl[ind];
      ind++;
    }
  }



  unsigned int dim = 3;
  unsigned int system_size = 6 + num_active_surface + num_active_model; // "6" comes from symmeterizing epp
  jac.resize(system_size);
  for (unsigned i = 0 ; i < system_size ; ++i)
    jac[i].assign(system_size, 0);

  unsigned int row_num = 0;
  unsigned int col_num = 0;
  for (unsigned i = 0 ; i < dim ; ++i)
    for (unsigned j = 0 ; j <= i ; ++j)
    {
      for (unsigned k = 0 ; k < dim ; ++k)
        for (unsigned l = 0 ; l <= k ; ++l)
          jac[col_num][row_num++] = depp_dstress(i, j, k, l) + (k != l ? depp_dstress(i, j, l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
      for (unsigned surface = 0 ; surface < num_active_surface ; ++surface)
        jac[col_num][row_num++] = depp_dpm[surface](i, j);
      for (unsigned a = 0 ; a < num_active_model ; ++a)
        jac[col_num][row_num++] = depp_dintnl[a](i, j);
      row_num = 0;
      col_num++;
    }

  ind = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_surface[surface])
    {
      for (unsigned k = 0 ; k < dim ; ++k)
        for (unsigned l = 0 ; l <= k ; ++l)
        jac[col_num][row_num++] = df_dstress[ind](k, l) + (k != l ? df_dstress[ind](l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
      for (unsigned beta = 0 ; beta < num_active_surface ; ++beta)
        jac[col_num][row_num++] = 0; // df_dpm
      for (unsigned model = 0 ; model < _num_models ; ++model)
        if (active_model[model]) // only use df_dintnl for models in active_model
        {
          if (modelNumber(surface) == model)
            jac[col_num][row_num++] = df_dintnl[ind];
          else
            jac[col_num][row_num++] = 0;
        }
      ind++;
      row_num = 0;
      col_num++;
    }

  for (unsigned a = 0 ; a < num_active_model ; ++a)
  {
    for (unsigned k = 0 ; k < dim ; ++k)
      for (unsigned l = 0 ; l <= k ; ++l)
        jac[col_num][row_num++] = dic_dstress[a](k, l) + (k != l ? dic_dstress[a](l, k) : 0); // extra part is needed because i assume dstress(i, j) = dstress(j, i)
    for (unsigned alpha = 0 ; alpha < num_active_surface ; ++alpha)
      jac[col_num][row_num++] = dic_dpm[a][alpha];
    for (unsigned b = 0 ; b < num_active_model ; ++b)
      jac[col_num][row_num++] = dic_dintnl[a][b];
    row_num = 0;
    col_num++;
  }

  mooseAssert(col_num == system_size, "Incorrect filling of cols in Jacobian");
}
Esempio n. 4
0
void
MultiPlasticityLinearSystem::calculateRHS(const RankTwoTensor & stress, const std::vector<Real> & intnl_old, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankTwoTensor & delta_dp, std::vector<Real> & rhs, const std::vector<bool> & active, bool eliminate_ld, std::vector<bool> & deactivated_due_to_ld)
{
  // see comments at the start of .h file

  mooseAssert(intnl_old.size() == _num_models, "Size of intnl_old is " << intnl_old.size() << " which is incorrect in calculateRHS");
  mooseAssert(intnl.size() == _num_models, "Size of intnl is " << intnl.size() << " which is incorrect in calculateRHS");
  mooseAssert(pm.size() == _num_surfaces, "Size of pm is " << pm.size() << " which is incorrect in calculateRHS");
  mooseAssert(active.size() == _num_surfaces, "Size of active is " << active.size() << " which is incorrect in calculateRHS");

  std::vector<Real> f; // the yield functions
  RankTwoTensor epp; // the plastic-strain constraint ("direction constraint")
  std::vector<Real> ic; // the "internal constraints"

  std::vector<RankTwoTensor> r;
  calculateConstraints(stress, intnl_old, intnl, pm, delta_dp, f, r, epp, ic, active);

  if (eliminate_ld)
    eliminateLinearDependence(stress, intnl, f, r, active, deactivated_due_to_ld);
  else
    deactivated_due_to_ld.assign(_num_surfaces, false);

  std::vector<bool> active_not_deact(_num_surfaces);
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    active_not_deact[surface] = (active[surface] && !deactivated_due_to_ld[surface]);

  unsigned num_active_f = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active_not_deact[surface])
      num_active_f++;

  unsigned num_active_ic = 0;
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (anyActiveSurfaces(model, active_not_deact))
      num_active_ic++;


  unsigned int dim = 3;
  unsigned int system_size = 6 + num_active_f + num_active_ic; // "6" comes from symmeterizing epp, num_active_f comes from "f", num_active_f comes from "ic"

  rhs.resize(system_size);

  unsigned ind = 0;
  for (unsigned i = 0 ; i < dim ; ++i)
    for (unsigned j = 0 ; j <= i ; ++j)
      rhs[ind++] = -epp(i, j);
  unsigned active_surface = 0;
  for (unsigned surface = 0 ; surface < _num_surfaces ; ++surface)
    if (active[surface])
    {
      if (!deactivated_due_to_ld[surface])
        rhs[ind++] = -f[active_surface];
      active_surface++;
    }
  unsigned active_model = 0;
  for (unsigned model = 0 ; model < _num_models ; ++model)
    if (anyActiveSurfaces(model, active))
    {
      if (anyActiveSurfaces(model, active_not_deact))
        rhs[ind++] = -ic[active_model];
      active_model++;
    }

  mooseAssert(ind == system_size, "Incorrect filling of the rhs in calculateRHS");
}
void
MultiPlasticityDebugger::checkSolution(const RankFourTensor & E_inv)
{
  Moose::err << "\n\n+++++++++++++++++++++\nChecking the Solution\n";
  Moose::err << "(Ie, checking Ax = b)\n+++++++++++++++++++++\n";
  outputAndCheckDebugParameters();

  std::vector<bool> act;
  act.assign(_num_surfaces, true);
  std::vector<bool> deactivated_due_to_ld;
  deactivated_due_to_ld.assign(_num_surfaces, false);

  RankTwoTensor delta_dp = -E_inv * _fspb_debug_stress;

  std::vector<Real> orig_rhs;
  calculateRHS(_fspb_debug_stress,
               _fspb_debug_intnl,
               _fspb_debug_intnl,
               _fspb_debug_pm,
               delta_dp,
               orig_rhs,
               act,
               true,
               deactivated_due_to_ld);

  Moose::err << "\nb = ";
  for (unsigned i = 0; i < orig_rhs.size(); ++i)
    Moose::err << orig_rhs[i] << " ";
  Moose::err << "\n\n";

  std::vector<std::vector<Real>> jac_coded;
  calculateJacobian(_fspb_debug_stress,
                    _fspb_debug_intnl,
                    _fspb_debug_pm,
                    E_inv,
                    act,
                    deactivated_due_to_ld,
                    jac_coded);

  Moose::err
      << "Before checking Ax=b is correct, check that the Jacobians given below are equal.\n";
  Moose::err
      << "The hand-coded Jacobian is used in calculating the solution 'x', given 'b' above.\n";
  Moose::err << "Note that this only includes degrees of freedom that aren't deactivated due to "
                "linear dependence.\n";
  Moose::err << "Hand-coded Jacobian:\n";
  for (unsigned row = 0; row < jac_coded.size(); ++row)
  {
    for (unsigned col = 0; col < jac_coded.size(); ++col)
      Moose::err << jac_coded[row][col] << " ";
    Moose::err << "\n";
  }

  deactivated_due_to_ld.assign(_num_surfaces,
                               false); // this potentially gets changed by nrStep, below
  RankTwoTensor dstress;
  std::vector<Real> dpm;
  std::vector<Real> dintnl;
  nrStep(_fspb_debug_stress,
         _fspb_debug_intnl,
         _fspb_debug_intnl,
         _fspb_debug_pm,
         E_inv,
         delta_dp,
         dstress,
         dpm,
         dintnl,
         act,
         deactivated_due_to_ld);

  std::vector<bool> active_not_deact(_num_surfaces);
  for (unsigned surface = 0; surface < _num_surfaces; ++surface)
    active_not_deact[surface] = !deactivated_due_to_ld[surface];

  std::vector<Real> x;
  x.assign(orig_rhs.size(), 0);
  unsigned ind = 0;
  for (unsigned i = 0; i < 3; ++i)
    for (unsigned j = 0; j <= i; ++j)
      x[ind++] = dstress(i, j);
  for (unsigned surface = 0; surface < _num_surfaces; ++surface)
    if (active_not_deact[surface])
      x[ind++] = dpm[surface];
  for (unsigned model = 0; model < _num_models; ++model)
    if (anyActiveSurfaces(model, active_not_deact))
      x[ind++] = dintnl[model];

  mooseAssert(ind == orig_rhs.size(),
              "Incorrect extracting of changes from NR solution in the "
              "finite-difference checking of nrStep");

  Moose::err << "\nThis yields x =";
  for (unsigned i = 0; i < orig_rhs.size(); ++i)
    Moose::err << x[i] << " ";
  Moose::err << "\n";

  std::vector<std::vector<Real>> jac_fd;
  fdJacobian(_fspb_debug_stress,
             _fspb_debug_intnl,
             _fspb_debug_intnl,
             _fspb_debug_pm,
             delta_dp,
             E_inv,
             true,
             jac_fd);

  Moose::err << "\nThe finite-difference Jacobian is used to multiply by this 'x',\n";
  Moose::err << "in order to check that the solution is correct\n";
  Moose::err << "Finite-difference Jacobian:\n";
  for (unsigned row = 0; row < jac_fd.size(); ++row)
  {
    for (unsigned col = 0; col < jac_fd.size(); ++col)
      Moose::err << jac_fd[row][col] << " ";
    Moose::err << "\n";
  }

  Real L2_numer = 0;
  Real L2_denom = 0;
  for (unsigned row = 0; row < jac_coded.size(); ++row)
    for (unsigned col = 0; col < jac_coded.size(); ++col)
    {
      L2_numer += Utility::pow<2>(jac_coded[row][col] - jac_fd[row][col]);
      L2_denom += Utility::pow<2>(jac_coded[row][col] + jac_fd[row][col]);
    }
  Moose::err << "Relative L2norm of the hand-coded and finite-difference Jacobian is "
             << std::sqrt(L2_numer / L2_denom) / 0.5 << "\n";

  std::vector<Real> fd_times_x;
  fd_times_x.assign(orig_rhs.size(), 0);
  for (unsigned row = 0; row < orig_rhs.size(); ++row)
    for (unsigned col = 0; col < orig_rhs.size(); ++col)
      fd_times_x[row] += jac_fd[row][col] * x[col];

  Moose::err << "\n(Finite-difference Jacobian)*x =\n";
  for (unsigned i = 0; i < orig_rhs.size(); ++i)
    Moose::err << fd_times_x[i] << " ";
  Moose::err << "\n";
  Moose::err << "Recall that b = \n";
  for (unsigned i = 0; i < orig_rhs.size(); ++i)
    Moose::err << orig_rhs[i] << " ";
  Moose::err << "\n";

  L2_numer = 0;
  L2_denom = 0;
  for (unsigned i = 0; i < orig_rhs.size(); ++i)
  {
    L2_numer += Utility::pow<2>(orig_rhs[i] - fd_times_x[i]);
    L2_denom += Utility::pow<2>(orig_rhs[i] + fd_times_x[i]);
  }
  Moose::err << "\nRelative L2norm of these is " << std::sqrt(L2_numer / L2_denom) / 0.5 << "\n";
}