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"
25
26#include "Teuchos_LAPACK.hpp"
27
28namespace ROL {
29namespace ZOO {
30
33template<class Real>
35
36 typedef std::vector<Real> vector;
37 typedef Vector<Real> V;
39
40 typedef typename vector::size_type uint;
41
42private:
45
46 Real hu_;
47 Real hz_;
48
49 Real alpha_;
50
51 Real eps_;
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
64public:
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
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) );
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) );
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);
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
509template<class Real>
510class getPoissonInversion : public TestProblem<Real> {
511public:
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 li = 0; li < n; li++ ) {
539 pt = (Real)(li+1)*h;
540 if ( pt >= 0.0 && pt < 0.5 ) {
541 (*xp)[li] = std::log(k1);
542 }
543 else if ( pt >= 0.5 && pt < 1.0 ) {
544 (*xp)[li] = 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
Contains definitions for helper functions in ROL.
Contains definitions of test objective functions.
Provides the interface to evaluate objective functions.
virtual void hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &x, Real &tol)
Apply Hessian approximation to vector.
Provides the ROL::Vector interface for scalar values, to be used, for example, with scalar constraint...
void axpy(const Real alpha, const Vector< Real > &x)
Compute where .
virtual Ptr< Vector< Real > > clone() const
Clone to make a new (uninitialized) vector.
Defines the linear algebra or vector space interface.
virtual void set(const Vector &x)
Set where .
virtual void scale(const Real alpha)=0
Compute where .
virtual void plus(const Vector &x)=0
Compute , where .
virtual void axpy(const Real alpha, const Vector &x)
Compute where .
void solve_adjoint_equation(Vector< Real > &p, const Vector< Real > &u, const Vector< Real > &z)
void solve_poisson(Vector< Real > &u, const Vector< Real > &z, Vector< Real > &b)
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)
Real reg_value(const Vector< Real > &z)
void apply_mass(Vector< Real > &Mf, const Vector< Real > &f)
void reg_hessVec(Vector< Real > &hv, const Vector< Real > &v, const Vector< Real > &z)
ROL::Ptr< const vector > getVector(const V &x)
void apply_transposed_linearized_control_operator(Vector< Real > &Bd, const Vector< Real > &z, const Vector< Real > &d, const Vector< Real > &u)
void solve_state_sensitivity_equation(Vector< Real > &w, const Vector< Real > &v, const Vector< Real > &u, const Vector< Real > &z)
void gradient(Vector< Real > &g, const Vector< Real > &z, Real &tol)
Compute gradient.
void solve_state_equation(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)
Objective_PoissonInversion(uint nz=32, Real alpha=1.e-4)
Real value(const Vector< Real > &z, Real &tol)
Compute value.
void reg_gradient(Vector< Real > &g, 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.
Ptr< Vector< Real > > getInitialGuess(void) const
Ptr< Objective< Real > > getObjective(void) const
Ptr< Vector< Real > > getSolution(const int i=0) const
constexpr auto dim