diff --git a/dune/elasticity/assemblers/localadolcstiffness.hh b/dune/elasticity/assemblers/localadolcstiffness.hh index 5c02eb4f3635f712dd6d7fd94c18765506514324..5ac66171a2336ea9bb0d458194cb27db93f72830 100644 --- a/dune/elasticity/assemblers/localadolcstiffness.hh +++ b/dune/elasticity/assemblers/localadolcstiffness.hh @@ -27,8 +27,12 @@ class LocalADOLCStiffness public: // accepts ADOL_C's "adouble" only - LocalADOLCStiffness(std::shared_ptr<Dune::Elasticity::LocalEnergy<LocalView, adouble>> energy) + // useHessian2: there are different basic drivers for computing the hessian by ADOL-C, namely "hessian" and "hessian2". + // They yield the same results, but "hessian2" seems to be faster. The user can switch to "hessian" with + // useHessian2=false. See ADOL-C spec for more info about the drivers + LocalADOLCStiffness(std::shared_ptr<Dune::Elasticity::LocalEnergy<LocalView, adouble>> energy, bool useHessian2 = true) : localEnergy_(energy) + , useHessian2_(useHessian2) {} /** \brief Compute the energy at the current configuration */ @@ -45,6 +49,7 @@ public: Dune::Matrix<double>& localHessian); std::shared_ptr<Dune::Elasticity::LocalEnergy<LocalView, adouble>> localEnergy_; + const bool useHessian2_; }; @@ -110,29 +115,41 @@ assembleGradientAndHessian(const LocalView& localView, localHessian.setSize(nDoubles,nDoubles); - std::vector<double> v(nDoubles); - std::vector<double> w(nDoubles); - - std::fill(v.begin(), v.end(), 0.0); - - for (size_t i=0; i<nDoubles; i++) + // allocate raw doubles: ADOL-C requires "**double" arguments + double* rawHessian[nDoubles]; + for(size_t i=0; i<nDoubles; i++) { - // Evaluate Hessian multiplied with the i-th canonical basis vector (i.e.: the i-th column of the Hessian) - v[i] = 1.; + // we need only the lower half of the hessian, thus allocate i+1 doubles only + rawHessian[i] = (double*)malloc((i+1)*sizeof(double)); + } + + // ADOL-C error code + int rc; - int rc= 3; - MINDEC(rc, hess_vec(rank, nDoubles, const_cast<double*>(localConfiguration.data()), v.data(), w.data())); // ADOL-C won't accept pointers with const values - if (rc < 0) - DUNE_THROW(Dune::Exception, "ADOL-C has returned with error code " << rc << "!"); + // ADOL-C won't accept pointers with const values, therefore the const_cast + if ( useHessian2_ ) + rc = hessian2(rank,nDoubles,const_cast<double*>(localConfiguration.data()),rawHessian); + else + rc = hessian(rank,nDoubles,const_cast<double*>(localConfiguration.data()),rawHessian); - for (size_t j=0; j<nDoubles; j++) - localHessian[i][j] = w[j]; + if (rc < 0) + DUNE_THROW(Dune::Exception, "ADOL-C has returned with error code " << rc << "!"); - // Make v the null vector again - v[i] = 0.; + // copy the raw values to the localHessian + for (size_t i=0; i<nDoubles; i++) + { + for (size_t j=0; j<i; j++) + { + // we can only access the lower half of rawHessian! + localHessian[i][j] = rawHessian[i][j]; + localHessian[j][i] = rawHessian[i][j]; + } + localHessian[i][i] = rawHessian[i][i]; } - // TODO: implement ADOLC_VECTOR_MODE variant + // don't forget the clean everything up + for(size_t i=0; i<nDoubles; i++) + free(rawHessian[i]); } } // namespace Dune::Elasticity