ROL
ROL_PoissonInversion.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Rapid Optimization Library (ROL) Package
4 //
5 // Copyright 2014 NTESS and the ROL contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
15 #ifndef USE_HESSVEC
16 #define USE_HESSVEC 1
17 #endif
18 
19 #ifndef ROL_POISSONINVERSION_HPP
20 #define ROL_POISSONINVERSION_HPP
21 
22 #include "ROL_StdVector.hpp"
23 #include "ROL_TestProblem.hpp"
24 #include "ROL_HelperFunctions.hpp"
25 
26 #include "Teuchos_LAPACK.hpp"
27 
28 namespace ROL {
29 namespace ZOO {
30 
33 template<class Real>
34 class Objective_PoissonInversion : public Objective<Real> {
35 
36  typedef std::vector<Real> vector;
37  typedef Vector<Real> V;
39 
40  typedef typename vector::size_type uint;
41 
42 private:
45 
46  Real hu_;
47  Real hz_;
48 
49  Real alpha_;
50 
51  Real eps_;
52  int reg_type_;
53 
54  ROL::Ptr<const vector> getVector( const V& x ) {
55 
56  return dynamic_cast<const SV&>(x).getVector();
57  }
58 
59  ROL::Ptr<vector> getVector( V& x ) {
60 
61  return dynamic_cast<SV&>(x).getVector();
62  }
63 
64 public:
65 
66  /* CONSTRUCTOR */
67  Objective_PoissonInversion(uint nz = 32, Real alpha = 1.e-4)
68  : nu_(nz-1), nz_(nz), hu_(1./((Real)nu_+1.)), hz_(hu_),
69  alpha_(alpha), eps_(1.e-4), reg_type_(2) {}
70 
71  /* REGULARIZATION DEFINITIONS */
72  Real reg_value(const Vector<Real> &z) {
73 
74 
75  ROL::Ptr<const vector> zp = getVector(z);
76 
77  Real val = 0.0;
78  for (uint i = 0; i < nz_; i++) {
79  if ( reg_type_ == 2 ) {
80  val += alpha_/2.0 * hz_ * (*zp)[i]*(*zp)[i];
81  }
82  else if ( reg_type_ == 1 ) {
83  val += alpha_ * hz_ * std::sqrt((*zp)[i]*(*zp)[i] + eps_);
84  }
85  else if ( reg_type_ == 0 ) {
86  if ( i < nz_-1 ) {
87  val += alpha_ * std::sqrt(std::pow((*zp)[i]-(*zp)[i+1],2.0)+eps_);
88  }
89  }
90  }
91  return val;
92  }
93 
94  void reg_gradient(Vector<Real> &g, const Vector<Real> &z) {
95 
96 
97  if ( reg_type_ == 2 ) {
98  g.set(z);
99  g.scale(alpha_*hz_);
100  }
101  else if ( reg_type_ == 1 ) {
102  ROL::Ptr<const vector> zp = getVector(z);
103  ROL::Ptr<vector > gp = getVector(g);
104 
105  for (uint i = 0; i < nz_; i++) {
106  (*gp)[i] = alpha_ * hz_ * (*zp)[i]/std::sqrt(std::pow((*zp)[i],2.0)+eps_);
107  }
108  }
109  else if ( reg_type_ == 0 ) {
110  ROL::Ptr<const vector> zp = getVector(z);
111  ROL::Ptr<vector> gp = getVector(g);
112 
113  Real diff = 0.0;
114  for (uint i = 0; i < nz_; i++) {
115  if ( i == 0 ) {
116  diff = (*zp)[i]-(*zp)[i+1];
117  (*gp)[i] = alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
118  }
119  else if ( i == nz_-1 ) {
120  diff = (*zp)[i-1]-(*zp)[i];
121  (*gp)[i] = -alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
122  }
123  else {
124  diff = (*zp)[i]-(*zp)[i+1];
125  (*gp)[i] = alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
126  diff = (*zp)[i-1]-(*zp)[i];
127  (*gp)[i] -= alpha_ * diff/std::sqrt(std::pow(diff,2.0)+eps_);
128  }
129  }
130  }
131  }
132 
133  void reg_hessVec(Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &z) {
134 
135 
136 
137  if ( reg_type_ == 2 ) {
138  hv.set(v);
139  hv.scale(alpha_*hz_);
140  }
141  else if ( reg_type_ == 1 ) {
142  ROL::Ptr<const vector> zp = getVector(z);
143  ROL::Ptr<const vector> vp = getVector(v);
144  ROL::Ptr<vector> hvp = getVector(hv);
145 
146  for (uint i = 0; i < nz_; i++) {
147  (*hvp)[i] = alpha_*hz_*(*vp)[i]*eps_/std::pow(std::pow((*zp)[i],2.0)+eps_,3.0/2.0);
148  }
149  }
150  else if ( reg_type_ == 0 ) {
151  ROL::Ptr<const vector> zp = getVector(z);
152  ROL::Ptr<const vector> vp = getVector(v);
153  ROL::Ptr<vector> hvp = getVector(hv);
154 
155  Real diff1 = 0.0;
156  Real diff2 = 0.0;
157  for (uint i = 0; i < nz_; i++) {
158  if ( i == 0 ) {
159  diff1 = (*zp)[i]-(*zp)[i+1];
160  diff1 = eps_/std::pow(std::pow(diff1,2.0)+eps_,3.0/2.0);
161  (*hvp)[i] = alpha_* ((*vp)[i]*diff1 - (*vp)[i+1]*diff1);
162  }
163  else if ( i == nz_-1 ) {
164  diff2 = (*zp)[i-1]-(*zp)[i];
165  diff2 = eps_/std::pow(std::pow(diff2,2.0)+eps_,3.0/2.0);
166  (*hvp)[i] = alpha_* (-(*vp)[i-1]*diff2 + (*vp)[i]*diff2);
167  }
168  else {
169  diff1 = (*zp)[i]-(*zp)[i+1];
170  diff1 = eps_/std::pow(std::pow(diff1,2.0)+eps_,3.0/2.0);
171  diff2 = (*zp)[i-1]-(*zp)[i];
172  diff2 = eps_/std::pow(std::pow(diff2,2.0)+eps_,3.0/2.0);
173  (*hvp)[i] = alpha_* (-(*vp)[i-1]*diff2 + (*vp)[i]*(diff1 + diff2) - (*vp)[i+1]*diff1);
174  }
175  }
176  }
177  }
178 
179  /* FINITE ELEMENT DEFINTIONS */
180  void apply_mass(Vector<Real> &Mf, const Vector<Real> &f ) {
181 
182 
183  ROL::Ptr<const vector> fp = getVector(f);
184  ROL::Ptr<vector> Mfp = getVector(Mf);
185 
186  for (uint i = 0; i < nu_; i++) {
187  if ( i == 0 ) {
188  (*Mfp)[i] = hu_/6.0*(4.0*(*fp)[i] + (*fp)[i+1]);
189  }
190  else if ( i == nu_-1 ) {
191  (*Mfp)[i] = hu_/6.0*((*fp)[i-1] + 4.0*(*fp)[i]);
192  }
193  else {
194  (*Mfp)[i] = hu_/6.0*((*fp)[i-1] + 4.0*(*fp)[i] + (*fp)[i+1]);
195  }
196  }
197  }
198 
200 
201 
202  ROL::Ptr<const vector> zp = getVector(z);
203  ROL::Ptr<vector> up = getVector(u);
204  ROL::Ptr<vector> bp = getVector(b);
205 
206  // Get Diagonal and Off-Diagonal Entries of PDE Jacobian
207  vector d(nu_,1.0);
208  vector o(nu_-1,1.0);
209  for ( uint i = 0; i < nu_; i++ ) {
210  d[i] = (std::exp((*zp)[i]) + std::exp((*zp)[i+1]))/hu_;
211  if ( i < nu_-1 ) {
212  o[i] *= -std::exp((*zp)[i+1])/hu_;
213  }
214  }
215 
216  // Solve Tridiagonal System Using LAPACK's SPD Tridiagonal Solver
217  Teuchos::LAPACK<int,Real> lp;
218  int info;
219  int ldb = nu_;
220  int nhrs = 1;
221  lp.PTTRF(nu_,&d[0],&o[0],&info);
222  lp.PTTRS(nu_,nhrs,&d[0],&o[0],&(*bp)[0],ldb,&info);
223  u.set(b);
224  }
225 
226  Real evaluate_target(Real x) {
227  return x*(1.0-x);
228  }
229 
231  const Vector<Real> &d, const Vector<Real> &u ) {
232 
233 
234 
235  ROL::Ptr<const vector> zp = getVector(z);
236  ROL::Ptr<const vector> up = getVector(u);
237  ROL::Ptr<const vector> dp = getVector(d);
238  ROL::Ptr<vector> Bdp = getVector(Bd);
239 
240  for (uint i = 0; i < nu_; i++) {
241  if ( i == 0 ) {
242  (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*(*up)[i]*(*dp)[i]
243  + std::exp((*zp)[i+1])*((*up)[i]-(*up)[i+1])*(*dp)[i+1] );
244  }
245  else if ( i == nu_-1 ) {
246  (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*((*up)[i]-(*up)[i-1])*(*dp)[i]
247  + std::exp((*zp)[i+1])*(*up)[i]*(*dp)[i+1] );
248  }
249  else {
250  (*Bdp)[i] = 1.0/hu_*( std::exp((*zp)[i])*((*up)[i]-(*up)[i-1])*(*dp)[i]
251  + std::exp((*zp)[i+1])*((*up)[i]-(*up)[i+1])*(*dp)[i+1] );
252  }
253  }
254  }
255 
257  const Vector<Real> &d, const Vector<Real> &u ) {
258 
259 
260  ROL::Ptr<const vector> zp = getVector(z);
261  ROL::Ptr<const vector> up = getVector(u);
262  ROL::Ptr<const vector> dp = getVector(d);
263  ROL::Ptr<vector> Bdp = getVector(Bd);
264 
265  for (uint i = 0; i < nz_; i++) {
266  if ( i == 0 ) {
267  (*Bdp)[i] = std::exp((*zp)[i])/hu_*(*up)[i]*(*dp)[i];
268  }
269  else if ( i == nz_-1 ) {
270  (*Bdp)[i] = std::exp((*zp)[i])/hu_*(*up)[i-1]*(*dp)[i-1];
271  }
272  else {
273  (*Bdp)[i] = std::exp((*zp)[i])/hu_*( ((*up)[i]-(*up)[i-1])*((*dp)[i]-(*dp)[i-1]) );
274  }
275  }
276  }
277 
279  const Vector<Real> &d, const Vector<Real> &u ) {
280 
281  ROL::Ptr<const vector> zp = getVector(z);
282  ROL::Ptr<const vector> vp = getVector(v);
283  ROL::Ptr<const vector> up = getVector(u);
284  ROL::Ptr<const vector> dp = getVector(d);
285  ROL::Ptr<vector> Bdp = getVector(Bd);
286 
287  for (uint i = 0; i < nz_; i++) {
288  if ( i == 0 ) {
289  (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*(*up)[i]*(*dp)[i];
290  }
291  else if ( i == nz_-1 ) {
292  (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*(*up)[i-1]*(*dp)[i-1];
293  }
294  else {
295  (*Bdp)[i] = (*vp)[i]*std::exp((*zp)[i])/hu_*( ((*up)[i]-(*up)[i-1])*((*dp)[i]-(*dp)[i-1]) );
296  }
297  }
298  }
299 
300  /* STATE AND ADJOINT EQUATION DEFINTIONS */
302 
303 
304 
305 
306  Real k1 = 1.0;
307  Real k2 = 2.0;
308  // Right Hand Side
309  ROL::Ptr<vector> bp = ROL::makePtr<vector>(nu_, 0.0);
310  for ( uint i = 0; i < nu_; i++ ) {
311  if ( (Real)(i+1)*hu_ < 0.5 ) {
312  (*bp)[i] = 2.0*k1*hu_;
313  }
314  else if ( std::abs((Real)(i+1)*hu_ - 0.5) < ROL_EPSILON<Real>() ) {
315  (*bp)[i] = (k1+k2)*hu_;
316  }
317  else if ( (Real)(i+1)*hu_ > 0.5 ) {
318  (*bp)[i] = 2.0*k2*hu_;
319  }
320  }
321 
322  SV b(bp);
323  // Solve Equation
324  solve_poisson(u,z,b);
325  }
326 
328 
329 
330 
331 
332  ROL::Ptr<const vector> up = getVector(u);
333  ROL::Ptr<vector> rp = ROL::makePtr<vector>(nu_,0.0);
334  SV res(rp);
335 
336  for ( uint i = 0; i < nu_; i++) {
337  (*rp)[i] = -((*up)[i]-evaluate_target((Real)(i+1)*hu_));
338  }
339  StdVector<Real> Mres( ROL::makePtr<std::vector<Real>>(nu_,0.0) );
340  apply_mass(Mres,res);
341  solve_poisson(p,z,Mres);
342  }
343 
345  const Vector<Real> &u, const Vector<Real> &z) {
346 
347 
348  SV b( ROL::makePtr<vector>(nu_,0.0) );
350  solve_poisson(w,z,b);
351  }
352 
354  const Vector<Real> &p, const Vector<Real> &u, const Vector<Real> &z) {
355 
356 
357 
358  SV res( ROL::makePtr<vector>(nu_,0.0) );
359  apply_mass(res,w);
360  SV res1( ROL::makePtr<vector>(nu_,0.0) );
362  res.axpy(-1.0,res1);
363  solve_poisson(q,z,res);
364  }
365 
366  /* OBJECTIVE FUNCTION DEFINITIONS */
367  Real value( const Vector<Real> &z, Real &tol ) {
368 
369 
370 
371 
372  // SOLVE STATE EQUATION
373  ROL::Ptr<vector> up = ROL::makePtr<vector>(nu_,0.0);
374  SV u( up );
375 
377 
378  // COMPUTE MISFIT
379  ROL::Ptr<vector> rp = ROL::makePtr<vector>(nu_,0.0);
380  SV res( rp );
381 
382  for ( uint i = 0; i < nu_; i++) {
383  (*rp)[i] = ((*up)[i]-evaluate_target((Real)(i+1)*hu_));
384  }
385 
386  ROL::Ptr<V> Mres = res.clone();
387  apply_mass(*Mres,res);
388  return 0.5*Mres->dot(res) + reg_value(z);
389  }
390 
391  void gradient( Vector<Real> &g, const Vector<Real> &z, Real &tol ) {
392 
393 
394 
395  // SOLVE STATE EQUATION
396  SV u( ROL::makePtr<vector>(nu_,0.0) );
398 
399  // SOLVE ADJOINT EQUATION
400  SV p( ROL::makePtr<std::vector<Real>>(nu_,0.0) );
401  solve_adjoint_equation(p,u,z);
402 
403  // Apply Transpose of Linearized Control Operator
405 
406  // Regularization gradient
407  SV g_reg( ROL::makePtr<vector>(nz_,0.0) );
408  reg_gradient(g_reg,z);
409 
410  // Build Gradient
411  g.plus(g_reg);
412  }
413 #if USE_HESSVEC
414  void hessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &z, Real &tol ) {
415 
416 
417 
418  // SOLVE STATE EQUATION
419  SV u( ROL::makePtr<vector>(nu_,0.0) );
421 
422  // SOLVE ADJOINT EQUATION
423  SV p( ROL::makePtr<vector>(nu_,0.0) );
424  solve_adjoint_equation(p,u,z);
425 
426  // SOLVE STATE SENSITIVITY EQUATION
427  SV w( ROL::makePtr<vector>(nu_,0.0) );
429 
430  // SOLVE ADJOINT SENSITIVITY EQUATION
431  SV q( ROL::makePtr<vector>(nu_,0.0) );
433 
434  // Apply Transpose of Linearized Control Operator
436 
437  // Apply Transpose of Linearized Control Operator
438  SV tmp( ROL::makePtr<vector>(nz_,0.0) );
440  hv.axpy(-1.0,tmp);
441 
442  // Apply Transpose of 2nd Derivative of Control Operator
443  tmp.zero();
445  hv.plus(tmp);
446 
447  // Regularization hessVec
448  SV hv_reg( ROL::makePtr<vector>(nz_,0.0) );
449  reg_hessVec(hv_reg,v,z);
450 
451  // Build hessVec
452  hv.plus(hv_reg);
453  }
454 #endif
455 
456  void invHessVec( Vector<Real> &hv, const Vector<Real> &v, const Vector<Real> &x, Real &tol ) {
457 
458 
459 
460 
461  // Cast hv and v vectors to std::vector.
462  ROL::Ptr<vector> hvp = getVector(hv);
463 
464  std::vector<Real> vp(*getVector(v));
465 
466  int dim = static_cast<int>(vp.size());
467 
468 
469  // Compute dense Hessian.
470  Teuchos::SerialDenseMatrix<int, Real> H(dim, dim);
471  Objective_PoissonInversion<Real> & obj = *this;
472  H = computeDenseHessian<Real>(obj, x);
473 
474  // Compute eigenvalues, sort real part.
475  std::vector<vector> eigenvals = computeEigenvalues<Real>(H);
476  std::sort((eigenvals[0]).begin(), (eigenvals[0]).end());
477 
478  // Perform 'inertia' correction.
479  Real inertia = (eigenvals[0])[0];
480  Real correction = 0.0;
481  if ( inertia <= 0.0 ) {
482  correction = 2.0*std::abs(inertia);
483  if ( inertia == 0.0 ) {
484  int cnt = 0;
485  while ( eigenvals[0][cnt] == 0.0 ) {
486  cnt++;
487  }
488  correction = 0.5*eigenvals[0][cnt];
489  if ( cnt == dim-1 ) {
490  correction = 1.0;
491  }
492  }
493  for (int i=0; i<dim; i++) {
494  H(i,i) += correction;
495  }
496  }
497 
498  // Compute dense inverse Hessian.
499  Teuchos::SerialDenseMatrix<int, Real> invH = computeInverse<Real>(H);
500 
501  // Apply dense inverse Hessian.
502  Teuchos::SerialDenseVector<int, Real> hv_teuchos(Teuchos::View, &((*hvp)[0]), dim);
503  const Teuchos::SerialDenseVector<int, Real> v_teuchos(Teuchos::View, &(vp[0]), dim);
504  hv_teuchos.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, invH, v_teuchos, 0.0);
505  }
506 
507 };
508 
509 template<class Real>
510 class getPoissonInversion : public TestProblem<Real> {
511 public:
513 
514  Ptr<Objective<Real>> getObjective(void) const {
515  // Problem dimension
516  int n = 128;
517  // Instantiate Objective Function
518  return ROL::makePtr<Objective_PoissonInversion<Real>>(n,1.e-6);
519  }
520 
521  Ptr<Vector<Real>> getInitialGuess(void) const {
522  // Problem dimension
523  int n = 128;
524  // Get Initial Guess
525  ROL::Ptr<std::vector<Real> > x0p = ROL::makePtr<std::vector<Real>>(n,0.0);
526  for ( int i = 0; i < n; i++ ) {
527  (*x0p)[i] = 1.5;
528  }
529  return ROL::makePtr<StdVector<Real>>(x0p);
530  }
531 
532  Ptr<Vector<Real>> getSolution(const int i = 0) const {
533  // Problem dimension
534  int n = 128;
535  // Get Solution
536  ROL::Ptr<std::vector<Real> > xp = ROL::makePtr<std::vector<Real>>(n,0.0);
537  Real h = 1.0/((Real)n+1), pt = 0.0, k1 = 1.0, k2 = 2.0;
538  for( int i = 0; i < n; i++ ) {
539  pt = (Real)(i+1)*h;
540  if ( pt >= 0.0 && pt < 0.5 ) {
541  (*xp)[i] = std::log(k1);
542  }
543  else if ( pt >= 0.5 && pt < 1.0 ) {
544  (*xp)[i] = std::log(k2);
545  }
546  }
547  return ROL::makePtr<StdVector<Real>>(xp);
548  }
549 };
550 
551 } // End ZOO Namespace
552 } // End ROL Namespace
553 
554 #endif
Provides the interface to evaluate objective functions.
typename PV< Real >::size_type size_type
void apply_transposed_linearized_control_operator(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &d, const Vector< Real > &u)
virtual void scale(const Real alpha)=0
Compute where .
void axpy(const Real alpha, const Vector< Real > &x)
Compute where .
void solve_state_sensitivity_equation(Vector< Real > &w, const Vector< Real > &v, const Vector< Real > &u, const Vector< Real > &z)
virtual void plus(const Vector &x)=0
Compute , where .
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
Definition: ROL_Vector.hpp:119
void gradient(Vector< Real > &g, const Vector< Real > &z, Real &tol)
Compute gradient.
virtual void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
Contains definitions for helper functions in ROL.
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:46
void solve_poisson(Vector< Real > &u, const Vector< Real > &z, Vector< Real > &b)
Ptr< Vector< Real > > getInitialGuess(void) const
void solve_adjoint_sensitivity_equation(Vector< Real > &q, const Vector< Real > &w, const Vector< Real > &v, const Vector< Real > &p, const Vector< Real > &u, const Vector< Real > &z)
void apply_transposed_linearized_control_operator_2(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &v, const Vector< Real > &d, const Vector< Real > &u)
void invHessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply inverse Hessian approximation to vector.
void solve_state_equation(Vector< Real > &u, const Vector< Real > &z)
void reg_hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &z)
virtual Ptr< Vector< Real > > clone() const
Clone to make a new (uninitialized) vector.
Contains definitions of test objective functions.
void apply_mass(Vector< Real > &Mf, const Vector< Real > &f)
void solve_adjoint_equation(Vector< Real > &p, const Vector< Real > &u, const Vector< Real > &z)
void apply_linearized_control_operator(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &d, const Vector< Real > &u)
Ptr< Vector< Real > > getSolution(const int i=0) const
Real value(const Vector< Real > &z, Real &tol)
Compute value.
Objective_PoissonInversion(uint nz=32, Real alpha=1.e-4)
virtual void set(const Vector &x)
Set where .
Definition: ROL_Vector.hpp:175
Ptr< Objective< Real > > getObjective(void) const
Real reg_value(const Vector< Real > &z)
void reg_gradient(Vector< Real > &g, const Vector< Real > &z)
constexpr auto dim
ROL::Ptr< const vector > getVector(const V &x)