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"); }
void FiniteStrainPlasticBase::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) { // Calculate RHS and Jacobian std::vector<Real> rhs; calculateRHS(stress, intnl_old, intnl, pm, delta_dp, rhs); std::vector<std::vector<Real> > jac; calculateJacobian(stress, intnl, pm, E_inv, jac); // prepare for LAPACKgesv_ routine provided by PETSc (at least since PETSc 3.0.0) 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 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.resize(numberOfYieldFunctions()); for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha) dpm[alpha] = rhs[ind++]; dintnl.resize(numberOfInternalParameters()); for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a) dintnl[a] = rhs[ind++]; }
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"; }
void MultiPlasticityDebugger::fdJacobian(const RankTwoTensor & stress, const std::vector<Real> & intnl_old, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankTwoTensor & delta_dp, const RankFourTensor & E_inv, bool eliminate_ld, std::vector<std::vector<Real>> & jac) { std::vector<bool> active; active.assign(_num_surfaces, true); std::vector<bool> deactivated_due_to_ld; std::vector<bool> deactivated_due_to_ld_ep; std::vector<Real> orig_rhs; calculateRHS(stress, intnl_old, intnl, pm, delta_dp, orig_rhs, active, eliminate_ld, deactivated_due_to_ld); // this calculates RHS, and also set deactivated_due_to_ld. // The latter stays fixed for the rest of this routine unsigned int whole_system_size = 6 + _num_surfaces + _num_models; unsigned int system_size = orig_rhs.size(); // will be = whole_system_size if eliminate_ld = false, since all active=true jac.resize(system_size); for (unsigned row = 0; row < system_size; ++row) jac[row].assign(system_size, 0); std::vector<Real> rhs_ep; unsigned col = 0; RankTwoTensor stressep; RankTwoTensor delta_dpep; Real ep = _fspb_debug_stress_change; for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j <= i; ++j) { stressep = stress; stressep(i, j) += ep; if (i != j) stressep(j, i) += ep; delta_dpep = delta_dp; for (unsigned k = 0; k < 3; ++k) for (unsigned l = 0; l < 3; ++l) { delta_dpep(k, l) -= E_inv(k, l, i, j) * ep; if (i != j) delta_dpep(k, l) -= E_inv(k, l, j, i) * ep; } active.assign(_num_surfaces, true); calculateRHS(stressep, intnl_old, intnl, pm, delta_dpep, rhs_ep, active, false, deactivated_due_to_ld_ep); unsigned row = 0; for (unsigned dof = 0; dof < whole_system_size; ++dof) if (dof_included(dof, deactivated_due_to_ld)) { jac[row][col] = -(rhs_ep[dof] - orig_rhs[row]) / ep; // remember jacobian = -d(rhs)/d(something) row++; } col++; // all of the first 6 columns are dof_included since they're stresses } std::vector<Real> pmep; pmep.resize(_num_surfaces); for (unsigned surface = 0; surface < _num_surfaces; ++surface) pmep[surface] = pm[surface]; for (unsigned surface = 0; surface < _num_surfaces; ++surface) { if (!dof_included(6 + surface, deactivated_due_to_ld)) continue; ep = _fspb_debug_pm_change[surface]; pmep[surface] += ep; active.assign(_num_surfaces, true); calculateRHS( stress, intnl_old, intnl, pmep, delta_dp, rhs_ep, active, false, deactivated_due_to_ld_ep); unsigned row = 0; for (unsigned dof = 0; dof < whole_system_size; ++dof) if (dof_included(dof, deactivated_due_to_ld)) { jac[row][col] = -(rhs_ep[dof] - orig_rhs[row]) / ep; // remember jacobian = -d(rhs)/d(something) row++; } pmep[surface] -= ep; col++; } std::vector<Real> intnlep; intnlep.resize(_num_models); for (unsigned model = 0; model < _num_models; ++model) intnlep[model] = intnl[model]; for (unsigned model = 0; model < _num_models; ++model) { if (!dof_included(6 + _num_surfaces + model, deactivated_due_to_ld)) continue; ep = _fspb_debug_intnl_change[model]; intnlep[model] += ep; active.assign(_num_surfaces, true); calculateRHS( stress, intnl_old, intnlep, pm, delta_dp, rhs_ep, active, false, deactivated_due_to_ld_ep); unsigned row = 0; for (unsigned dof = 0; dof < whole_system_size; ++dof) if (dof_included(dof, deactivated_due_to_ld)) { jac[row][col] = -(rhs_ep[dof] - orig_rhs[row]) / ep; // remember jacobian = -d(rhs)/d(something) row++; } intnlep[model] -= ep; col++; } }
void FiniteStrainPlasticBase::fdJacobian(const RankTwoTensor & stress, const std::vector<Real> & intnl_old, const std::vector<Real> & intnl, const std::vector<Real> & pm, const RankTwoTensor & delta_dp, const RankFourTensor & E_inv, std::vector<std::vector<Real> > & jac) { std::vector<Real> orig_rhs; calculateRHS(stress, intnl_old, intnl, pm, delta_dp, orig_rhs); unsigned int system_size = orig_rhs.size(); jac.resize(system_size); for (unsigned row = 0 ; row < system_size ; ++row) jac[row].resize(system_size); std::vector<Real> rhs_ep; unsigned col = 0; RankTwoTensor stressep; RankTwoTensor delta_dpep; Real ep = _fspb_debug_stress_change; for (unsigned i = 0 ; i < 3 ; ++i) for (unsigned j = 0 ; j <= i ; ++j) { stressep = stress; stressep(i, j) += ep; if (i != j) stressep(j, i) += ep; delta_dpep = delta_dp; for (unsigned k = 0; k < 3 ; ++k) for (unsigned l = 0 ; l < 3 ; ++l) { delta_dpep(k, l) -= E_inv(k, l, i, j)*ep; if (i != j) delta_dpep(k, l) -= E_inv(k, l, j, i)*ep; } calculateRHS(stressep, intnl_old, intnl, pm, delta_dpep, rhs_ep); for (unsigned row = 0 ; row < system_size ; ++row) jac[row][col] = -(rhs_ep[row] - orig_rhs[row])/ep; // remember jacobian = -d(rhs)/d(something) col++; } std::vector<Real> pmep; pmep.resize(numberOfYieldFunctions()); for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha) pmep[alpha] = pm[alpha]; for (unsigned alpha = 0 ; alpha < numberOfYieldFunctions() ; ++alpha) { ep = _fspb_debug_pm_change[alpha]; pmep[alpha] += ep; calculateRHS(stress, intnl_old, intnl, pmep, delta_dp, rhs_ep); for (unsigned row = 0 ; row < system_size ; ++row) jac[row][col] = -(rhs_ep[row] - orig_rhs[row])/ep; // remember jacobian = -d(rhs)/d(something) pmep[alpha] -= ep; col++; } std::vector<Real> intnlep; intnlep.resize(numberOfInternalParameters()); for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a) intnlep[a] = intnl[a]; for (unsigned a = 0 ; a < numberOfInternalParameters() ; ++a) { ep = _fspb_debug_intnl_change[a]; intnlep[a] += ep; calculateRHS(stress, intnl_old, intnlep, pm, delta_dp, rhs_ep); for (unsigned row = 0 ; row < system_size ; ++row) jac[row][col] = -(rhs_ep[row] - orig_rhs[row])/ep; // remember jacobian = -d(rhs)/d(something) intnlep[a] -= ep; col++; } }