Skip to content

Commit

Permalink
Piro/ROL: Adding and testing Hessian support to thyra adapters (#7534)
Browse files Browse the repository at this point in the history
* Piro: modified gradient checks
      added Hessian checks

* Piro/ROL: Thyra adapter, finite difference Hessian
     implemented second-order FD Hessian

* Piro: modified Tpetra Analysis test A
      added Hessian derivatives
      modified test to make constraint Hessian non trivial.

* ROL: Thyra adapters, added Hessian implementation

* Piro: Using ROL Primal vector space
      for testing purposes

* Piro: use the setHessianSupports function

* Piro: remove double spaces

* ROL: update the Doxygen to be consistent with the function arguments.

* Piro: update Hessian related names

* ROL: update Hessian related names

* ROL: use finite diff. if derivatives are not supported

* Piro: resolves a compatibility issue when Np > 1

* Piro: resolves a compatibility issue when Np > 1

Co-authored-by: kliegeois <kimliegeois@ymail.com>
  • Loading branch information
mperego and kliegeois authored Jun 30, 2020
1 parent c717b45 commit d11ccea
Show file tree
Hide file tree
Showing 7 changed files with 1,048 additions and 173 deletions.
254 changes: 159 additions & 95 deletions packages/piro/src/Piro_PerformAnalysis.cpp

Large diffs are not rendered by default.

219 changes: 196 additions & 23 deletions packages/piro/test/MockModelEval_A_Tpetra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ MockModelEval_A_Tpetra::createOutArgsImpl() const
Thyra::ModelEvaluatorBase::OUT_ARG_DgDx, 0, Thyra::ModelEvaluatorBase::DERIV_MV_GRADIENT_FORM);
result.setSupports(Thyra::ModelEvaluatorBase::OUT_ARG_DgDp, 0, 0, Thyra::ModelEvaluatorBase::DERIV_MV_GRADIENT_FORM);

result.setSupports(
Thyra::ModelEvaluatorBase::OUT_ARG_DgDx, 0, Thyra::ModelEvaluatorBase::DERIV_MV_GRADIENT_FORM);

result.setHessianSupports(true);

return result;
}

Expand Down Expand Up @@ -311,50 +316,125 @@ void MockModelEval_A_Tpetra::evalModelImpl(

const Teuchos::RCP<Thyra::MultiVectorBase<double>> dgdx_base =
outArgs.get_DgDx(0).getMultiVector();
const Teuchos::RCP<Tpetra_MultiVector> dgdx_out =
Teuchos::nonnull(dgdx_base) ?
ConverterT::getTpetraMultiVector(dgdx_base) :
Teuchos::null;
const Teuchos::RCP<Tpetra_MultiVector> dgdx_out =
Teuchos::nonnull(dgdx_base) ?
ConverterT::getTpetraMultiVector(dgdx_base) :
Teuchos::null;

const Teuchos::RCP<const Tpetra_MultiVector> p_direction =
Teuchos::nonnull(inArgs.get_p_direction(0)) ?
ConverterT::getConstTpetraMultiVector(inArgs.get_p_direction(0)):
Teuchos::null;


const Teuchos::RCP<const Tpetra_Vector> lag_multiplier_f_in =
Teuchos::nonnull(inArgs.get_f_multiplier()) ?
ConverterT::getConstTpetraVector(inArgs.get_f_multiplier()) :
Teuchos::null;

auto f_hess_xx_v = outArgs.get_hess_vec_prod_f_xx();
const Teuchos::RCP<Tpetra_MultiVector> f_hess_xx_v_out =
Teuchos::nonnull(f_hess_xx_v) ?
ConverterT::getTpetraMultiVector(f_hess_xx_v) :
Teuchos::null;

auto f_hess_xp_v = outArgs.get_hess_vec_prod_f_xp(0);
const Teuchos::RCP<Tpetra_MultiVector> f_hess_xp_v_out =
Teuchos::nonnull(f_hess_xp_v) ?
ConverterT::getTpetraMultiVector(f_hess_xp_v) :
Teuchos::null;

auto f_hess_px_v = outArgs.get_hess_vec_prod_f_px(0);
const Teuchos::RCP<Tpetra_MultiVector> f_hess_px_v_out =
Teuchos::nonnull(f_hess_px_v) ?
ConverterT::getTpetraMultiVector(f_hess_px_v) :
Teuchos::null;

auto f_hess_pp_v = outArgs.get_hess_vec_prod_f_pp(0,0);
const Teuchos::RCP<Tpetra_MultiVector> f_hess_pp_v_out =
Teuchos::nonnull(f_hess_pp_v) ?
ConverterT::getTpetraMultiVector(f_hess_pp_v) :
Teuchos::null;

const Teuchos::RCP<const Tpetra_MultiVector> x_direction =
Teuchos::nonnull(inArgs.get_x_direction()) ?
ConverterT::getConstTpetraMultiVector(inArgs.get_x_direction()):
Teuchos::null;


const Teuchos::RCP<const Tpetra_Vector> lag_multiplier_g_in =
Teuchos::nonnull(inArgs.get_g_multiplier(0)) ?
ConverterT::getConstTpetraVector(inArgs.get_g_multiplier(0)) :
Teuchos::null;

auto g_hess_xx_v = outArgs.get_hess_vec_prod_g_xx(0);
const Teuchos::RCP<Tpetra_MultiVector> g_hess_xx_v_out =
Teuchos::nonnull(g_hess_xx_v) ?
ConverterT::getTpetraMultiVector(g_hess_xx_v) :
Teuchos::null;

auto g_hess_xp_v = outArgs.get_hess_vec_prod_g_xp(0,0);
const Teuchos::RCP<Tpetra_MultiVector> g_hess_xp_v_out =
Teuchos::nonnull(g_hess_xp_v) ?
ConverterT::getTpetraMultiVector(g_hess_xp_v) :
Teuchos::null;

auto g_hess_px_v = outArgs.get_hess_vec_prod_g_px(0,0);
const Teuchos::RCP<Tpetra_MultiVector> g_hess_px_v_out =
Teuchos::nonnull(g_hess_px_v) ?
ConverterT::getTpetraMultiVector(g_hess_px_v) :
Teuchos::null;

auto g_hess_pp_v = outArgs.get_hess_vec_prod_g_pp(0,0,0);
const Teuchos::RCP<Tpetra_MultiVector> g_hess_pp_v_out =
Teuchos::nonnull(g_hess_pp_v) ?
ConverterT::getTpetraMultiVector(g_hess_pp_v) :
Teuchos::null;

auto x = x_in->getData();
auto p = p_vec->getData();

double x0;
for (int i=0; i<myVecLength; i++) {
if( x_in->getMap()->getGlobalElement(i) == 0) {
x0 = x[i];
TEUCHOS_ASSERT(comm->getRank() == 0);
}
}
comm->broadcast(0, sizeof(double), (char*)(&x0));

if (f_out != Teuchos::null) {
f_out->putScalar(0.0);
auto f_out_data = f_out->getDataNonConst();
for (int i=0; i<myVecLength; i++) {
int gid = x_in->getMap()->getGlobalElement(i);

if (gid==0) {// f_0 = (x_0)^3 - p_0
if (gid==0) { // f_0 = (x_0)^3 - p_0
f_out_data[i] = x[i] * x[i] * x[i] - p[0];
for (int j=0; j<myVecLength; j++)
if(i != j)
f_out_data[j] -= 0.5*(x[i] - p[0]);
}
else // f_i = x_i - (i+p_1) - 0.5*(x_0 - p_0) (for i != 0)
f_out_data[i] += x[i] - (gid + p[1]);
else // f_i = x_i * (1 + x_0 - p_0^(1/3)) - (i+p_1) - 0.5*(x_0 - p_0), (for i != 0)
f_out_data[i] = x[i] - (gid + p[1]) - 0.5*(x0 - p[0]) + x[i] * (x0 - std::cbrt(p[0]));
}
auto f = f_out->getData();
}
if (W_out != Teuchos::null) {
Teuchos::RCP<Tpetra_CrsMatrix> W_out_crs =
Teuchos::rcp_dynamic_cast<Tpetra_CrsMatrix>(W_out, true);
W_out_crs->resumeFill();
W_out_crs->setAllToScalar(0.0);

double diag=0, extra_diag=-0.5;
double diag=0, extra_diag=0;
for (int i=0; i<myVecLength; i++) {
int gid = x_in->getMap()->getGlobalElement(i);
auto gid = x_in->getMap()->getGlobalElement(i);
if(gid==0) {
diag = 3.0 * x[i] * x[i];
diag = 3.0 * x0 * x0;
W_out_crs->replaceLocalValues(i, 1, &diag, &i);
for (int j=0; j<myVecLength; j++)
if(i != j)
W_out_crs->replaceLocalValues(j, 1, &extra_diag, &i);
}
else {
diag = 1.0;
diag = 1.0 + x0 - std::cbrt(p[0]);
W_out_crs->replaceLocalValues(i, 1, &diag, &i);
decltype(gid) col = 0;
extra_diag = -0.5 + x[i];
W_out_crs->replaceGlobalValues(gid, 1, &extra_diag, &col);
}
}
if(!Teuchos::nonnull(x_dot_in))
Expand All @@ -369,12 +449,11 @@ void MockModelEval_A_Tpetra::evalModelImpl(
const int gid = x_in->getMap()->getGlobalElement(i);
if (gid==0) {
dfdp_out_data_0[i] = -1.0;
for (int j=0; j<myVecLength; j++)
if(i != j)
dfdp_out_data_0[j] = 0.5;
}
else
else {
dfdp_out_data_0[i] = 0.5 - x[i] / (3.0 * std::cbrt(p[0]*p[0]));
dfdp_out_data_1[i] = -1.0;
}
}
}

Expand All @@ -400,6 +479,100 @@ void MockModelEval_A_Tpetra::evalModelImpl(
dgdp_out->getVectorNonConst(0)->getDataNonConst()[1] = -term1;
}

if (Teuchos::nonnull(f_hess_xx_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(x_direction));

double x_direction_0;
for (int i=0; i<myVecLength; i++) {
if( x_in->getMap()->getGlobalElement(i) == 0) {
x_direction_0 = x_direction->getVector(0)->getData()[i];
TEUCHOS_ASSERT(comm->getRank() == 0);
}
}

double temp= lag_multiplier_f_in->dot(*x_direction->getVector(0));
comm->broadcast(0, sizeof(double), (char*)(&x_direction_0));

f_hess_xx_v_out->getVectorNonConst(0)->putScalar(0);
for (int i=0; i<myVecLength; i++) {
if (x_in->getMap()->getGlobalElement(i)==0){
f_hess_xx_v_out->getVectorNonConst(0)->getDataNonConst()[i] =
(6.0* x[i] - 1.0) *lag_multiplier_f_in->getData()[i] * x_direction->getVector(0)->getData()[i] + temp;
}
else {
f_hess_xx_v_out->getVectorNonConst(0)->getDataNonConst()[i] = x_direction_0 * lag_multiplier_f_in->getData()[i];
}
}
}

if (Teuchos::nonnull(f_hess_xp_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(p_direction));
f_hess_xp_v_out->getVectorNonConst(0)->putScalar(0);
for (int i=0; i<myVecLength; i++) {
if (x_in->getMap()->getGlobalElement(i)!=0){
f_hess_xp_v_out->getVectorNonConst(0)->getDataNonConst()[i] =
- p_direction->getVector(0)->getData()[0]*lag_multiplier_f_in->getData()[i]/(3.0* std::cbrt(p[0]*p[0]));
}
}
}

if (Teuchos::nonnull(f_hess_px_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(x_direction));
f_hess_px_v_out->getVectorNonConst(0)->putScalar(0);
Tpetra_Vector temp_vec(lag_multiplier_f_in->getMap());
for (int i=0; i<myVecLength; i++) {
if (x_in->getMap()->getGlobalElement(i)==0)
temp_vec.getDataNonConst()[i] = 0;
else
temp_vec.getDataNonConst()[i] = lag_multiplier_f_in->getData()[i];
}
double temp= temp_vec.dot(*x_direction->getVector(0));
f_hess_px_v_out->getVectorNonConst(0)->getDataNonConst()[0] = -temp/(3.0* std::cbrt(p[0]*p[0]));
}

if (Teuchos::nonnull(f_hess_pp_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(p_direction));
f_hess_pp_v_out->getVectorNonConst(0)->putScalar(0);
Tpetra_Vector temp_vec(lag_multiplier_f_in->getMap());
for (int i=0; i<myVecLength; i++) {
if (x_in->getMap()->getGlobalElement(i)==0)
temp_vec.getDataNonConst()[i] = 0;
else
temp_vec.getDataNonConst()[i] = lag_multiplier_f_in->getData()[i];
}
double temp = temp_vec.dot(*x_in);
f_hess_pp_v_out->getVectorNonConst(0)->getDataNonConst()[0] = 2.0*p_direction->getVector(0)->getData()[0]*temp/(9.0* std::cbrt(std::pow(p[0],5)));
}

double mult = Teuchos::nonnull(lag_multiplier_g_in) ? lag_multiplier_g_in->getData()[0] : 1.0;
if (Teuchos::nonnull(g_hess_xx_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(x_direction));
term1 = x_direction->getVector(0)->meanValue() * vecLength;
for (int j=0; j<myVecLength; j++)
g_hess_xx_v_out->getVectorNonConst(0)->getDataNonConst()[j] = mult*term1;
}

if (Teuchos::nonnull(g_hess_xp_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(p_direction));
const auto direction_p = p_direction->getVector(0)->getData();
for (int j=0; j<myVecLength; j++)
g_hess_xp_v_out->getVectorNonConst(0)->getDataNonConst()[j] = - mult*(direction_p[0]+direction_p[1]);
}

if (Teuchos::nonnull(g_hess_px_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(x_direction));
term1 = x_direction->getVector(0)->meanValue() * vecLength;
g_hess_px_v_out->getVectorNonConst(0)->getDataNonConst()[0] = - mult*term1;
g_hess_px_v_out->getVectorNonConst(0)->getDataNonConst()[1] = - mult*term1;
}

if (Teuchos::nonnull(g_hess_pp_v_out)) {
TEUCHOS_ASSERT(Teuchos::nonnull(p_direction));
const auto direction_p = p_direction->getVector(0)->getData();
g_hess_pp_v_out->getVectorNonConst(0)->getDataNonConst()[0] = mult*(2.0*direction_p[0]+direction_p[1]);
g_hess_pp_v_out->getVectorNonConst(0)->getDataNonConst()[1] = mult*(direction_p[0]+direction_p[1]);
}

// Modify for time dependent (implicit time integration or eigensolves)
if (Teuchos::nonnull(x_dot_in)) {
// Velocity provided: Time dependent problem
Expand Down Expand Up @@ -446,7 +619,7 @@ MockModelEval_A_Tpetra::createInArgsImpl() const
result.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_alpha, true);
result.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_beta, true);

result.set_Np(1);
result.set_Np_Ng(1,1);

return result;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/piro/test/MockModelEval_A_Tpetra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,11 @@ typedef Thyra::TpetraOperatorVectorExtraction<
* g = 0.5*(Sum(x)-Sum(p)-12)^2 + 0.5*(p0-1)^2
* subject to:
* f_0 = (x_0)^3 - p_0 = 0
* f_i = x_i^3 - (i+3)*(i+p_1)^2 for i != 0
* f_i = x_i * (1 + x_0 - p_0^(1/3)) - (i+p_1) - 0.5*(x_0 - p_0), (for i != 0)
*
* solution is p = (1,3).
*/


class MockModelEval_A_Tpetra
: public Thyra::ModelEvaluatorDefaultBase<double>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@
<!--Parameter name="Uniform Parameter Guess" type="double" value="2.0"/ -->
<!--Parameter name="Min And Max Of Random Parameter Guess" type="Array(double)" value="{1.0, 3.0}"/ -->

<Parameter name="Check Gradient" type="bool" value="false" />
<Parameter name="Check Gradient" type="bool" value="true" />
<Parameter name="Number Of Gradient Checks" type="int" value="1" />

<Parameter name="Test Vector" type="bool" value="false" />
Expand All @@ -179,7 +179,7 @@
<Parameter name="Bound Constrained" type="bool" value="true" />
<Parameter name="epsilon bound" type="double" value="1e-4" />

<Parameter name="Step Method" type="string" value="Line Search" />
<Parameter name="Step Method" type="string" value="Trust Region" />
<Parameter name="Full Space" type="bool" value="false" />
<Parameter name="Use NOX Solver" type="bool" value="true" />

Expand Down Expand Up @@ -291,10 +291,10 @@

<!-- =========== STATUS TEST SUBLIST =========== -->
<ParameterList name="Status Test">
<Parameter name="Gradient Tolerance" type="double" value="1.e-10" />
<Parameter name="Gradient Tolerance" type="double" value="1.e-8" />
<Parameter name="Constraint Tolerance" type="double" value="1.e-10" />
<Parameter name="Step Tolerance" type="double" value="1.e-14" />
<Parameter name="Iteration Limit" type="int" value="1000" />
<Parameter name="Iteration Limit" type="int" value="10" />
</ParameterList>
</ParameterList>
</ParameterList>
Expand Down
Loading

0 comments on commit d11ccea

Please sign in to comment.