void DruckerPragerModel<EvalT, Traits>::ResidualJacobian(std::vector<ScalarT> & X, std::vector<ScalarT> & R, std::vector<ScalarT> & dRdX, const ScalarT ptr, const ScalarT qtr, const ScalarT eqN, const ScalarT mu, const ScalarT kappa) { std::vector<DFadType> Rfad(4); std::vector<DFadType> Xfad(4); // initialize DFadType local unknown vector Xfad // Note that since Xfad is a temporary variable // that gets changed within local iterations // when we initialize Xfad, we only pass in the values of X, // NOT the system sensitivity information std::vector<ScalarT> Xval(4); for (std::size_t i = 0; i < 4; ++i) { Xval[i] = Sacado::ScalarValue<ScalarT>::eval(X[i]); Xfad[i] = DFadType(4, i, Xval[i]); } DFadType pFad = Xfad[0]; DFadType qFad = Xfad[1]; DFadType alphaFad = Xfad[2]; DFadType deqFad = Xfad[3]; DFadType betaFad = alphaFad - b0_; // check this DFadType eqFad = eqN + deqFad; // (eqFad + deqFad??) // have to break down 3.0 * mu * deqFad; // other wise there wil be compiling error DFadType dq = deqFad; dq = mu * dq; dq = 3.0 * dq; // local system of equations Rfad[0] = pFad - ptr + kappa * betaFad * deqFad; Rfad[1] = qFad - qtr + dq; Rfad[2] = alphaFad - (a0_ + a1_ * eqFad * std::exp(a2_ * pFad - a3_ * eqFad)); Rfad[3] = qFad + alphaFad * pFad - Cf_; // get ScalarT Residual for (int i = 0; i < 4; i++) R[i] = Rfad[i].val(); // get local Jacobian for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) dRdX[i + 4 * j] = Rfad[i].dx(j); }// end of ResidualJacobian
void Constraint<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(const Matrix& P, Matrix& Projected) const { // We check only row maps. Column may be different. TEUCHOS_TEST_FOR_EXCEPTION(!P.getRowMap()->isSameAs(*Projected.getRowMap()), Exceptions::Incompatible, "Row maps are incompatible"); const size_t NSDim = X_->getNumVectors(); const size_t numRows = P.getNodeNumRows(); const Map& colMap = *P.getColMap(); const Map& PColMap = *Projected.getColMap(); Projected.resumeFill(); Teuchos::ArrayView<const LO> indices, pindices; Teuchos::ArrayView<const SC> values, pvalues; Teuchos::Array<SC> valuesAll(colMap.getNodeNumElements()), newValues; LO invalid = Teuchos::OrdinalTraits<LO>::invalid(); LO oneLO = Teuchos::OrdinalTraits<LO>::one(); SC zero = Teuchos::ScalarTraits<SC> ::zero(); SC one = Teuchos::ScalarTraits<SC> ::one(); std::vector<const SC*> Xval(NSDim); for (size_t j = 0; j < NSDim; j++) Xval[j] = X_->getData(j).get(); for (size_t i = 0; i < numRows; i++) { P .getLocalRowView(i, indices, values); Projected.getLocalRowView(i, pindices, pvalues); size_t nnz = indices.size(); // number of nonzeros in the supplied matrix size_t pnnz = pindices.size(); // number of nonzeros in the constrained matrix newValues.resize(pnnz); // Step 1: fix stencil // Projected *must* already have the correct stencil // Step 2: copy correct stencil values // The algorithm is very similar to the one used in the calculation of // Frobenius dot product, see src/Transfers/Energy-Minimization/Solvers/MueLu_CGSolver_def.hpp // NOTE: using extra array allows us to skip the search among indices for (size_t j = 0; j < nnz; j++) valuesAll[indices[j]] = values[j]; for (size_t j = 0; j < pnnz; j++) { LO ind = colMap.getLocalElement(PColMap.getGlobalElement(pindices[j])); // FIXME: we could do that before the full loop just once if (ind != invalid) // index indices[j] is part of template, copy corresponding value newValues[j] = valuesAll[ind]; else newValues[j] = zero; } for (size_t j = 0; j < nnz; j++) valuesAll[indices[j]] = zero; // Step 3: project to the space Teuchos::SerialDenseMatrix<LO,SC>& XXtInv = XXtInv_[i]; Teuchos::SerialDenseMatrix<LO,SC> locX(NSDim, pnnz, false); for (size_t j = 0; j < pnnz; j++) for (size_t k = 0; k < NSDim; k++) locX(k,j) = Xval[k][pindices[j]]; Teuchos::SerialDenseVector<LO,SC> val(pnnz, false), val1(NSDim, false), val2(NSDim, false); for (size_t j = 0; j < pnnz; j++) val[j] = newValues[j]; Teuchos::BLAS<LO,SC> blas; // val1 = locX * val; blas.GEMV(Teuchos::NO_TRANS, NSDim, pnnz, one, locX.values(), locX.stride(), val.values(), oneLO, zero, val1.values(), oneLO); // val2 = XXtInv * val1 blas.GEMV(Teuchos::NO_TRANS, NSDim, NSDim, one, XXtInv.values(), XXtInv.stride(), val1.values(), oneLO, zero, val2.values(), oneLO); // val = X^T * val2 blas.GEMV(Teuchos::CONJ_TRANS, NSDim, pnnz, one, locX.values(), locX.stride(), val2.values(), oneLO, zero, val.values(), oneLO); for (size_t j = 0; j < pnnz; j++) newValues[j] -= val[j]; Projected.replaceLocalValues(i, pindices, newValues); } Projected.fillComplete(Projected.getDomainMap(), Projected.getRangeMap()); //FIXME: maps needed? }
void Constraint<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Setup(const MultiVector& B, const MultiVector& Bc, RCP<const CrsGraph> Ppattern) { const size_t NSDim = Bc.getNumVectors(); Ppattern_ = Ppattern; size_t numRows = Ppattern_->getNodeNumRows(); XXtInv_.resize(numRows); RCP<const Import> importer = Ppattern_->getImporter(); X_ = MultiVectorFactory::Build(Ppattern_->getColMap(), NSDim); if (!importer.is_null()) X_->doImport(Bc, *importer, Xpetra::INSERT); else *X_ = Bc; std::vector<const SC*> Xval(NSDim); for (size_t j = 0; j < NSDim; j++) Xval[j] = X_->getData(j).get(); SC zero = Teuchos::ScalarTraits<SC>::zero(); SC one = Teuchos::ScalarTraits<SC>::one(); Teuchos::BLAS <LO,SC> blas; Teuchos::LAPACK<LO,SC> lapack; LO lwork = 3*NSDim; ArrayRCP<LO> IPIV(NSDim); ArrayRCP<SC> WORK(lwork); for (size_t i = 0; i < numRows; i++) { Teuchos::ArrayView<const LO> indices; Ppattern_->getLocalRowView(i, indices); size_t nnz = indices.size(); XXtInv_[i] = Teuchos::SerialDenseMatrix<LO,SC>(NSDim, NSDim, false/*zeroOut*/); Teuchos::SerialDenseMatrix<LO,SC>& XXtInv = XXtInv_[i]; if (NSDim == 1) { SC d = zero; for (size_t j = 0; j < nnz; j++) d += Xval[0][indices[j]] * Xval[0][indices[j]]; XXtInv(0,0) = one/d; } else { Teuchos::SerialDenseMatrix<LO,SC> locX(NSDim, nnz, false/*zeroOut*/); for (size_t j = 0; j < nnz; j++) for (size_t k = 0; k < NSDim; k++) locX(k,j) = Xval[k][indices[j]]; // XXtInv_ = (locX*locX^T)^{-1} blas.GEMM(Teuchos::NO_TRANS, Teuchos::CONJ_TRANS, NSDim, NSDim, nnz, one, locX.values(), locX.stride(), locX.values(), locX.stride(), zero, XXtInv.values(), XXtInv.stride()); LO info; // Compute LU factorization using partial pivoting with row exchanges lapack.GETRF(NSDim, NSDim, XXtInv.values(), XXtInv.stride(), IPIV.get(), &info); // Use the computed factorization to compute the inverse lapack.GETRI(NSDim, XXtInv.values(), XXtInv.stride(), IPIV.get(), WORK.get(), lwork, &info); } } }
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); } } } } } }