1 // @HEADER
2 // ************************************************************************
3 //
4 //               Rapid Optimization Library (ROL) Package
5 //                 Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 //              Drew Kouri   (dpkouri@sandia.gov) and
39 //              Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 /*! \file  example_01.cpp
45     \brief Shows how to solve a semilinear parabolic problem.
46 */
47 
48 #include "Teuchos_Comm.hpp"
49 #include "Teuchos_GlobalMPISession.hpp"
50 #include "Teuchos_FancyOStream.hpp"
51 
52 #include "Tpetra_Core.hpp"
53 #include "Tpetra_Version.hpp"
54 
55 #include <iostream>
56 #include <algorithm>
57 #include <numeric>
58 
59 #include <sys/types.h>
60 #include <unistd.h>
61 
62 #include "ROL_Bounds.hpp"
63 #include "ROL_Stream.hpp"
64 #include "ROL_ParameterList.hpp"
65 #include "ROL_OptimizationSolver.hpp"
66 #include "ROL_ReducedDynamicObjective.hpp"
67 #include "ROL_RandomVector.hpp"
68 #include "ROL_DynamicConstraintCheck.hpp"
69 #include "ROL_DynamicObjectiveCheck.hpp"
70 #include "ROL_PinTConstraint.hpp"
71 #include "ROL_PinTVectorCommunication.hpp"
72 #include "ROL_PinTVectorCommunication_Tpetra.hpp"
73 #include "ROL_PinTVectorCommunication_StdTpetraComposite.hpp"
74 
75 #include "../../TOOLS/dynconstraint.hpp"
76 #include "../../TOOLS/pdeobjective.hpp"
77 #include "../../TOOLS/ltiobjective.hpp"
78 #include "../../TOOLS/meshmanager.hpp"
79 #include "../../TOOLS/pdevector.hpp"
80 #include "dynpde_semilinear.hpp"
81 #include "obj_semilinear.hpp"
82 
83 using RealT = double;
84 
85 class KKTOperator : public ROL::LinearOperator<RealT> {
86 public:
87   ROL::Ptr<ROL::PinTConstraint<RealT>> pint_con;
88   ROL::Ptr<ROL::Vector<RealT>> state;
89   ROL::Ptr<ROL::Vector<RealT>> control;
90   int myRank;
91   ROL::Ptr<std::ostream> outStream;
92 
apply(ROL::Vector<RealT> & Hv,const ROL::Vector<RealT> & v,RealT & tol) const93   void apply( ROL::Vector<RealT> &Hv, const ROL::Vector<RealT> &v, RealT &tol ) const override
94   {
95     pint_con->applyAugmentedKKT(Hv,v,*state,*control,tol);
96   }
97 };
98 
99 class MGRITKKTOperator : public ROL::LinearOperator<RealT> {
100 public:
101   ROL::Ptr<ROL::PinTConstraint<RealT>> pint_con;
102   ROL::Ptr<ROL::Vector<RealT>> state;
103   ROL::Ptr<ROL::Vector<RealT>> control;
104   int myRank;
105   ROL::Ptr<std::ostream> outStream;
106 
apply(ROL::Vector<RealT> & Hv,const ROL::Vector<RealT> & v,RealT & tol) const107   void apply( ROL::Vector<RealT> &Hv, const ROL::Vector<RealT> &v, RealT &tol ) const override
108   {
109     assert(false);
110     pint_con->applyMultigridAugmentedKKT(Hv,v,*state,*control,tol);
111   }
applyInverse(ROL::Vector<RealT> & Hv,const ROL::Vector<RealT> & v,RealT & tol) const112   void applyInverse( ROL::Vector<RealT> &Hv, const ROL::Vector<RealT> &v, RealT &tol ) const override
113   {
114     pint_con->applyMultigridAugmentedKKT(Hv,v,*state,*control,tol);
115   }
116 };
117 
118 class WathenKKTOperator : public ROL::LinearOperator<RealT> {
119 public:
120   ROL::Ptr<ROL::PinTConstraint<RealT>> pint_con;
121   ROL::Ptr<ROL::Vector<RealT>> state;
122   ROL::Ptr<ROL::Vector<RealT>> control;
123   int myRank;
124   ROL::Ptr<std::ostream> outStream;
125 
apply(ROL::Vector<RealT> & Hv,const ROL::Vector<RealT> & v,RealT & tol) const126   void apply( ROL::Vector<RealT> &Hv, const ROL::Vector<RealT> &v, RealT &tol ) const override
127   {
128     assert(false);
129   }
applyInverse(ROL::Vector<RealT> & Hv,const ROL::Vector<RealT> & v,RealT & tol) const130   void applyInverse( ROL::Vector<RealT> &Hv, const ROL::Vector<RealT> &v, RealT &tol ) const override
131   {
132     pint_con->applyWathenInverse(Hv,v,*state,*control,tol,false,0);
133   }
134 };
135 
pauseToAttach(MPI_Comm mpicomm)136 inline void pauseToAttach(MPI_Comm mpicomm)
137 {
138   Teuchos::RCP<Teuchos::Comm<int> > comm =
139     Teuchos::createMpiComm<int>(Teuchos::rcp(new Teuchos::OpaqueWrapper<MPI_Comm>(mpicomm)));
140   Teuchos::FancyOStream out(Teuchos::rcpFromRef(std::cout));
141   out.setShowProcRank(true);
142   out.setOutputToRootOnly(-1);
143 
144   comm->barrier();
145 
146   // try to get them to print out all at once
147   out << "PID = " << getpid() << std::endl;
148 
149   if (comm->getRank() == 0)
150     getchar();
151   comm->barrier();
152 }
153 
154 ROL::Ptr<ROL::Vector<RealT>>
155 solveKKTSystem(const std::string & prefix,
156                bool useWathenPrec,int myRank,
157                double absTol,double relTol,
158                const Teuchos::RCP<Teuchos::StackedTimer> & timer,
159                const ROL::Ptr<std::ostream> & outStream,
160                const ROL::Ptr<ROL::PinTConstraint<RealT>> & pint_con,
161                const ROL::Ptr<ROL::Vector<RealT>> & kkt_b,
162                const ROL::Ptr<ROL::PinTVector<RealT>> & state,
163                const ROL::Ptr<ROL::PinTVector<RealT>> & control);
164 
main(int argc,char * argv[])165 int main(int argc, char *argv[])
166 {
167 
168   using Teuchos::RCP;
169 
170   /*** Initialize communicator. ***/
171   Teuchos::GlobalMPISession mpiSession(&argc, &argv);
172 
173   // pauseToAttach(MPI_COMM_WORLD);
174 
175   ROL::Ptr<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
176 
177   // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided.
178   const int myRank = comm->getRank();
179   ROL::Ptr<std::ostream> outStream = ROL::makeStreamPtr( std::cout, (argc > 1) && (myRank==0) );
180 
181   int errorFlag  = 0;
182 
183   // *** Example body.
184   try {
185 
186     /*** Read in XML input ***/
187     ROL::Ptr<ROL::ParameterList> parlist = ROL::getParametersFromXmlFile("input_ex01.xml");
188     int nt         = parlist->sublist("Time Discretization").get("Number of Time Steps", 100);
189     RealT T        = parlist->sublist("Time Discretization").get("End Time",             1.0);
190     RealT dt       = T/static_cast<RealT>(nt);
191 
192     const Teuchos::ParameterList & geomlist = parlist->sublist("Geometry");
193     RealT dx       = geomlist.get<double>("Width") / geomlist.get<int>("NX");
194     RealT dy       = geomlist.get<double>("Height") / geomlist.get<int>("NY");
195 
196     // Add MGRIT parameter list stuff
197     int sweeps         = parlist->get("MGRIT Sweeps", 1);
198     RealT omega        = parlist->get("MGRIT Relaxation",2.0/3.0);
199     int coarseSweeps   = parlist->get("MGRIT Coarse Sweeps", 1);
200     RealT coarseOmega  = parlist->get("MGRIT Coarse Relaxation",1.0);
201     int numLevels      = parlist->get("MGRIT Levels",3);
202     double relTol      = parlist->get("MGRIT Krylov Relative Tolerance",1e-4);
203     double absTol      = parlist->get("MGRIT Krylov Absolute Tolerance",1e-4);
204     int spaceProc      = parlist->get("MGRIT Spatial Procs",1);
205     double globalScale = parlist->get("MGRIT Global Scale",1.0);
206     bool rebalance     = parlist->get("MGRIT Rebalance",false);
207     int cgIterations   = parlist->get("MGRIT CG Iterations",1);
208     double cntrlRegPar = parlist->get("MGRIT Control Regularization Parameter",1.0);
209 
210     ROL::Ptr<const ROL::PinTCommunicators> communicators           = ROL::makePtr<ROL::PinTCommunicators>(MPI_COMM_WORLD,spaceProc);
211     ROL::Ptr<const Teuchos::Comm<int>> mpiSpaceComm = ROL::makePtr<Teuchos::MpiComm<int>>(communicators->getSpaceCommunicator());
212 
213     // for "serial" in time cases, use the wathen preconditioner
214     bool useWathenPrec = communicators->getTimeSize()==spaceProc;
215 
216     /*************************************************************************/
217     /***************** BUILD GOVERNING PDE ***********************************/
218     /*************************************************************************/
219     /*** Initialize mesh data structure. ***/
220     ROL::Ptr<MeshManager<RealT>> meshMgr
221       = ROL::makePtr<MeshManager_Rectangle<RealT>>(*parlist);
222     // Initialize PDE describe semilinear equation
223     ROL::Ptr<DynamicPDE_Semilinear<RealT>> pde
224       = ROL::makePtr<DynamicPDE_Semilinear<RealT>>(*parlist);
225 
226     /*************************************************************************/
227     /***************** BUILD CONSTRAINT **************************************/
228     /*************************************************************************/
229     ROL::Ptr<DynConstraint<RealT> > dyn_con
230       = ROL::makePtr<DynConstraint<RealT>>(pde,meshMgr,mpiSpaceComm,*parlist,*outStream);
231     const ROL::Ptr<Assembler<RealT>> assembler = dyn_con->getAssembler();
232     dyn_con->setSolveParameters(*parlist);
233     dyn_con->getAssembler()->printMeshData(*outStream);
234 
235     /*************************************************************************/
236     /***************** BUILD VECTORS *****************************************/
237     /*************************************************************************/
238     ROL::Ptr<Tpetra::MultiVector<>> u0_ptr = assembler->createStateVector();
239     ROL::Ptr<Tpetra::MultiVector<>> zk_ptr = assembler->createControlVector();
240     ROL::Ptr<ROL::Vector<RealT>> u0, zk;
241     u0 = ROL::makePtr<PDE_PrimalSimVector<RealT>>(u0_ptr,pde,*assembler,*parlist);
242     zk = ROL::makePtr<PDE_PrimalOptVector<RealT>>(zk_ptr,pde,*assembler,*parlist);
243 
244     // ROL::Ptr<const ROL::PinTVectorCommunication<RealT>> vectorComm = ROL::makePtr<ROL::PinTVectorCommunication_Tpetra<RealT>>();
245     ROL::Ptr<const ROL::PinTVectorCommunication<RealT>> vectorComm = ROL::makePtr<ROL::PinTVectorCommunication_StdTpetraComposite<RealT>>();
246     ROL::Ptr<ROL::PinTVector<RealT>> state   = ROL::buildStatePinTVector<RealT>(   communicators, vectorComm, nt,     u0); // for Euler, Crank-Nicolson, stencil = [-1,0]
247     ROL::Ptr<ROL::PinTVector<RealT>> control = ROL::buildControlPinTVector<RealT>( communicators, vectorComm, nt,     zk); // time discontinous, stencil = [0]
248 
249     // make sure we are globally consistent
250     state->boundaryExchange();
251     control->boundaryExchange();
252 
253     ROL::Ptr<ROL::Vector<RealT>> kkt_vector = ROL::makePtr<ROL::PartitionedVector<RealT>>({state->clone(),control->clone(),state->clone()});
254 
255     /*************************************************************************/
256     /***************** BUILD PINT CONSTRAINT *********************************/
257     /*************************************************************************/
258 
259     /*************************************************************************/
260     /************************* BUILD TIME STAMP ******************************/
261     /*************************************************************************/
262     auto timeStamp = ROL::makePtr<std::vector<ROL::TimeStamp<RealT>>>(control->numOwnedSteps());
263 
264     double myFinalTime = dt*timeStamp->size();
265     double timeOffset  = 0.0;
266     MPI_Exscan(&myFinalTime,&timeOffset,1,MPI_DOUBLE,MPI_SUM,communicators->getTimeCommunicator());
267 
268     for( uint k=0; k<timeStamp->size(); ++k ) {
269       timeStamp->at(k).t.resize(2);
270       timeStamp->at(k).t.at(0) = k*dt+timeOffset;
271       timeStamp->at(k).t.at(1) = (k+1)*dt+timeOffset;
272     }
273 
274     if(myRank==0) {
275       (*outStream) << "Sweeps        = " << sweeps       << std::endl;
276       (*outStream) << "Omega         = " << omega        << std::endl;
277       (*outStream) << "Levels        = " << numLevels    << std::endl;
278       (*outStream) << "Coarse Sweeps = " << coarseSweeps << std::endl;
279       (*outStream) << "Coarse Omega  = " << coarseOmega  << std::endl;
280       (*outStream) << "Global Scale  = " << globalScale  << std::endl;
281       (*outStream) << "Rebalance     = " << rebalance    << std::endl;
282       (*outStream) << "CG Iterations = " << cgIterations;
283       if(cgIterations==0)
284         *(outStream) << " (apply Wathen smoothing)" << std::endl;
285       else
286         *(outStream) << " (apply CG fix to Wathen smoothing)" << std::endl;
287       (*outStream) << "Cntrl Reg Par = " << cntrlRegPar << std::endl;
288     }
289 
290     // build the parallel in time constraint from the user constraint
291     ROL::Ptr<ROL::PinTConstraint<RealT>> pint_con = ROL::makePtr<ROL::PinTConstraint<RealT>>(dyn_con,u0,timeStamp);
292     pint_con->applyMultigrid(numLevels,communicators,vectorComm,rebalance);
293     pint_con->setSweeps(sweeps);
294     pint_con->setRelaxation(omega);
295     pint_con->setCoarseSweeps(coarseSweeps);
296     pint_con->setCoarseRelaxation(coarseOmega);
297     pint_con->setGlobalScale(globalScale);
298     pint_con->setCGIterations(cgIterations);
299     pint_con->setControlRegParam(cntrlRegPar);
300     pint_con->setRecordResidualReductions(true);
301 
302     /*************************************************************************/
303     /***************** Run KKT Solver ***************************************/
304     /*************************************************************************/
305 
306     Teuchos::RCP<Teuchos::StackedTimer> timer = Teuchos::TimeMonitor::getStackedTimer();
307     double tol = 1e-12;
308 
309     state->setScalar(1.0);
310     control->setScalar(1.0);
311 
312     // setup and solve the lagrange multiplier RHS of the SQP algorithm
313     ///////////////////////////////////////////////////////////////////////////
314     {
315       auto kkt_b     = kkt_vector->clone();
316       kkt_b->setScalar(1.0);
317       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(0)->scale(dt*dx*dy); // u
318       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(1)->scale(dt*dx*dy); // z
319       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(2)->scale(0.0);      // lambda
320 
321       if(myRank==0) (*outStream) << std::endl;
322 
323       solveKKTSystem("LAGR MULTIPLIER STEP: ",
324           useWathenPrec,myRank,absTol,relTol,
325           timer,outStream,
326           pint_con,kkt_b,state,control);
327 
328       if(myRank==0) (*outStream) << std::endl;
329     }
330 
331     // compute quasi normal step
332     ///////////////////////////////////////////////////////////////////////////
333 
334     ROL::Ptr<ROL::Vector<RealT>> g_k; // this will be use in tangential step
335     {
336       ROL::Ptr<ROL::Vector<RealT>> residual = state->clone();
337       ROL::Ptr<ROL::Vector<RealT>> cau_pt_1;
338       ROL::Ptr<ROL::Vector<RealT>> cau_pt_2;
339 
340       // residual = c(x_k)
341       pint_con->value(*residual,*state,*control,tol );
342 
343       {
344         ROL::Ptr<ROL::Vector<RealT>> jv_1     = state->clone();
345         ROL::Ptr<ROL::Vector<RealT>> jv_2     = state->clone();
346         ROL::Ptr<ROL::Vector<RealT>> ajv_1    = state->clone();
347         ROL::Ptr<ROL::Vector<RealT>> ajv_2    = control->clone();
348 
349         // ajv = c'(x_k)^* c(x_k)
350         pint_con->applyAdjointJacobian_1(*ajv_1,*residual,*state,*control,tol);
351         pint_con->applyAdjointJacobian_2(*ajv_2,*residual,*state,*control,tol);
352 
353         // jv = c'(x_k) c'(x_k)^* c(x_k)
354         pint_con->applyJacobian_1(*jv_1,*ajv_1,*state,*control,tol);
355         pint_con->applyJacobian_2(*jv_2,*ajv_2,*state,*control,tol);
356 
357         RealT norm_ajv_sqr = std::pow(ajv_1->norm(),2.0) + std::pow(ajv_2->norm(),2.0);
358         RealT norm_jv_sqr = std::pow(jv_1->norm(),2.0) + std::pow(jv_2->norm(),2.0);
359 
360         // now we we will modify the jacobian components
361         jv_1->scale(norm_ajv_sqr/norm_jv_sqr);
362         jv_2->scale(norm_ajv_sqr/norm_jv_sqr);
363         residual->plus(*jv_1);
364         residual->plus(*jv_2);
365 
366         jv_1 = ROL::nullPtr;
367         jv_2 = ROL::nullPtr;
368 
369         // cauchy point
370         cau_pt_1 = ajv_1; cau_pt_1->scale(norm_ajv_sqr/norm_jv_sqr);
371         cau_pt_2 = ajv_2; cau_pt_2->scale(norm_ajv_sqr/norm_jv_sqr);
372       }
373 
374       // build RHS vector
375       auto kkt_b     = kkt_vector->clone();
376       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(0)->set(*cau_pt_1); // u
377       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(1)->set(*cau_pt_2); // z
378       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(2)->set(*residual); // lambda
379 
380       residual = ROL::nullPtr;
381 
382       if(myRank==0) (*outStream) << std::endl;
383 
384       auto delta_nk = solveKKTSystem("QUASI-NORMAL STEP: ",
385                       useWathenPrec,myRank,absTol,relTol,
386                       timer,outStream,
387                       pint_con,kkt_b,state,control);
388 
389       if(myRank==0) (*outStream) << std::endl;
390 
391       kkt_b->setScalar(1.0);
392       kkt_b->plus(*delta_nk);
393 
394       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(0)->scale(dt*dx*dy); // u
395       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(1)->scale(dt*dx*dy); // z
396       ROL::dynamicPtrCast<ROL::PartitionedVector<double>>(kkt_b)->get(2)->setScalar(0.0); // lambda
397 
398       g_k = kkt_b;
399     }
400 
401     // compute tangential step step
402     ///////////////////////////////////////////////////////////////////////////
403     {
404       if(myRank==0) (*outStream) << std::endl;
405 
406       solveKKTSystem("TANG STEP: ",
407           useWathenPrec,myRank,absTol,relTol,
408           timer,outStream,
409           pint_con,g_k,state,control);
410 
411       if(myRank==0) (*outStream) << std::endl;
412     }
413 
414     // setup and solve the quasi normal step
415 
416     #if 0
417     {
418       // This was useful for debugging, maintaing it so that we can recreate it if required.
419       // However, its not consistent right now so I don't want to mislead.
420 
421       ROL::Ptr<ROL::Vector<RealT>> scratch;
422       {
423         /*************************************************************************/
424         /***************** BUILD SERIAL-IN-TIME CONSTRAINT ***********************/
425         /*************************************************************************/
426         auto serial_con = ROL::make_SerialConstraint(dyn_con, *u0, timeStamp);
427 
428         /*************************************************************************/
429         /******************* BUILD SERIAL-IN-TIME VECTORS ************************/
430         /*************************************************************************/
431         auto U  = ROL::PartitionedVector<RealT>::create(*uo, nt);
432         auto Z  = ROL::PartitionedVector<RealT>::create(*zk, nt);
433         auto C  = ROL::PartitionedVector<RealT>::create(*ck, nt);
434 
435         scratch = U->clone(); // this will be used for testing in the PINT vector
436 
437         auto UZ    = ROL::make_Vector_SimOpt(U, Z);
438         auto X     = UZ->clone();
439         auto V_x   = X->clone();
440         auto V_c   = C->clone();
441         auto V_l   = C->dual().clone();
442         auto ajv   = X->dual().clone();
443         auto ajvpx = X->dual().clone();
444         auto jv    = C->clone();
445 
446         /*************************************************************************/
447         /******************* APPLY AUGMENTED SYSTEM TO 1's ***********************/
448         /*************************************************************************/
449         X->zero();
450         ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(V_x)->get_1()->setScalar(1.0);
451         ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(V_x)->get_2()->setScalar(2.0);
452         V_l->setScalar(3.0);
453         ajvpx->set(V_x->dual());
454         serial_con->applyAdjointJacobian(*ajv, *V_l, *X, dummytol);
455         ajvpx->plus(*ajv);
456 
457         auto ajv_u = ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(ajv)->get_1();
458         auto ajv_z = ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(ajv)->get_2();
459 
460         serial_con->applyJacobian(*jv, *V_x, *X, dummytol);
461 
462         (*outStream) << "\nSerial components of augmented system:\n";
463         (*outStream) << "  Norm of Aug*1 1st component = " << ajvpx->norm() << "\n";
464         (*outStream) << "  Norm of Aug*1 2nd component = " << jv->norm() << "\n";
465 
466         auto Hv_u = ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(ajvpx)->get_1();
467         auto Hv_z = ROL::dynamicPtrCast<ROL::Vector_SimOpt<RealT>>(ajvpx)->get_2();
468         auto Hv_l = jv;
469 
470         (*outStream) << "  Norm of Aug*1_u = " << Hv_u->norm() << "\n";
471         (*outStream) << "  Norm of Aug*1_z = " << Hv_z->norm() << "\n";
472         (*outStream) << "  Norm of Aug*1_l = " << Hv_l->norm() << "\n";
473 
474       }
475       {
476         /*************************************************************************/
477         /************************* TEST THE PINT SYSTEM  *************************/
478         /*************************************************************************/
479 
480         /*************************************************************************/
481         /******************* BUILD PARALLEL-IN-TIME VECTORS **********************/
482         /*************************************************************************/
483         auto U = ROL::buildStatePinTVector<RealT>(  communicators, vectorComm, nt, uo); // for Euler, Crank-Nicolson, stencil = [-1,0]
484         auto Z = ROL::buildControlPinTVector<RealT>(communicators, vectorComm, nt, zk); // time discontinous, stencil = [0]
485         auto C = ROL::buildStatePinTVector<RealT>(  communicators, vectorComm, nt, ck); // for Euler, Crank-Nicolson, stencil = [-1,0]
486 
487         auto triple = ROL::makePtr<ROL::PartitionedVector<RealT>>({U->clone(),Z->clone(),C->clone()});
488         auto V      = triple->clone();
489         auto Hv     = triple->dual().clone();
490 
491         /*************************************************************************/
492         /******************* APPLY AUGMENTED SYSTEM TO 1's ***********************/
493         /*************************************************************************/
494 
495         U->zero();
496         Z->zero();
497         ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(V)->get(0)->setScalar(1.0);
498         ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(V)->get(1)->setScalar(2.0);
499         ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(V)->get(2)->setScalar(3.0);
500         Hv->setScalar(0.0);
501 
502         pint_con->applyAugmentedKKT(*Hv,*V,*U,*Z,tol);
503 
504         auto Hv_u = ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(Hv)->get(0);
505         auto Hv_z = ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(Hv)->get(1);
506         auto Hv_l = ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(Hv)->get(2);
507 
508         (*outStream) << "\nParallel compnents of augmented system:\n";
509         (*outStream) << "  Norm of Aug*1_u = " << Hv_u->norm() << "\n";
510         (*outStream) << "  Norm of Aug*1_z = " << Hv_z->norm() << "\n";
511         (*outStream) << "  Norm of Aug*1_l = " << Hv_l->norm() << "\n";
512 
513         auto pint_Hv_u = ROL::dynamicPtrCast<ROL::PinTVector<RealT>>(Hv_u);
514         auto part_scratch = ROL::dynamicPtrCast<ROL::PartitionedVector<RealT>>(scratch);
515         for(int i=0;i<pint_Hv_u->numOwnedSteps();i++) {
516 
517           part_scratch->get(i)->setScalar(-1.0);
518           part_scratch->get(i)->axpy(1.0,*pint_Hv_u->getVectorPtr(2*i));
519           part_scratch->get(i)->axpy(1.0,*pint_Hv_u->getVectorPtr(2*i+1));
520         }
521 
522         (*outStream) << "  Norm of Aug*1_u modified = " << scratch->norm() << "\n";
523       }
524     }
525     #endif
526   }
527   catch (std::logic_error& err) {
528     *outStream << err.what() << "\n";
529     errorFlag = -1000;
530   }; // end try
531 
532   if(myRank==0) {
533     if (errorFlag != 0)
534       std::cout << "End Result: TEST FAILED " << myRank << "\n";
535     else
536       std::cout << "End Result: TEST PASSED " << myRank << "\n";
537   }
538 
539   return 0;
540 }
541 
542 ROL::Ptr<ROL::Vector<RealT>>
solveKKTSystem(const std::string & prefix,bool useWathenPrec,int myRank,double absTol,double relTol,const Teuchos::RCP<Teuchos::StackedTimer> & timer,const ROL::Ptr<std::ostream> & outStream,const ROL::Ptr<ROL::PinTConstraint<RealT>> & pint_con,const ROL::Ptr<ROL::Vector<RealT>> & kkt_b,const ROL::Ptr<ROL::PinTVector<RealT>> & state,const ROL::Ptr<ROL::PinTVector<RealT>> & control)543 solveKKTSystem(const std::string & prefix,
544                bool useWathenPrec,int myRank,
545                double absTol,double relTol,
546                const Teuchos::RCP<Teuchos::StackedTimer> & timer,
547                const ROL::Ptr<std::ostream> & outStream,
548                const ROL::Ptr<ROL::PinTConstraint<RealT>> & pint_con,
549                const ROL::Ptr<ROL::Vector<RealT>> & kkt_b,
550                const ROL::Ptr<ROL::PinTVector<RealT>> & state,
551                const ROL::Ptr<ROL::PinTVector<RealT>> & control)
552 {
553   using Teuchos::RCP;
554 
555   RealT res0 = kkt_b->norm();
556   res0 = kkt_b->norm();
557 
558   auto kkt_x_out = kkt_b->clone();
559   kkt_x_out->zero();
560 
561   KKTOperator kktOperator;
562   kktOperator.pint_con = pint_con;
563   kktOperator.state = state;
564   kktOperator.control = control;
565   kktOperator.outStream = outStream;
566   kktOperator.myRank = myRank;
567 
568   RCP<ROL::LinearOperator<RealT>> precOperator;
569 
570   // build the preconditioner
571   if(useWathenPrec) {
572     RCP<WathenKKTOperator> wathenOperator(new WathenKKTOperator);
573     wathenOperator->pint_con = pint_con;
574     wathenOperator->state = state;
575     wathenOperator->control = control;
576     wathenOperator->outStream = outStream;
577     wathenOperator->myRank = myRank;
578 
579     precOperator = wathenOperator;
580   }
581   else {
582     RCP<MGRITKKTOperator> mgOperator(new MGRITKKTOperator);
583     mgOperator->pint_con = pint_con;
584     mgOperator->state = state;
585     mgOperator->control = control;
586     mgOperator->outStream = outStream;
587     mgOperator->myRank = myRank;
588 
589     precOperator = mgOperator;
590   }
591 
592   Teuchos::ParameterList parlist;
593   ROL::ParameterList &krylovList = parlist.sublist("General").sublist("Krylov");
594   krylovList.set("Absolute Tolerance",absTol);
595   krylovList.set("Relative Tolerance",relTol);
596 
597   if(myRank==0)
598     (*outStream) << "Relative tolerance = " << relTol << std::endl;
599 
600   ROL::GMRES<RealT> krylov(parlist); // TODO: Do Belos
601   // ROL::MINRES<RealT> krylov(1e0, 1e-6, 200); // TODO: Do Belos
602 
603   int flag = 0;
604   int iter = 0;
605 
606 
607   if(myRank==0) {
608     (*outStream) << "Solving KKT system: ";
609     if(useWathenPrec)
610       (*outStream) << "using Wathen preconditioner" << std::endl;
611     else
612       (*outStream) << "using MGRIT preconditioner" << std::endl;
613   }
614 
615   MPI_Barrier(MPI_COMM_WORLD);
616   double t0 = MPI_Wtime();
617 
618   timer->start("krylov");
619   RealT finalTol = krylov.run(*kkt_x_out,kktOperator,*kkt_b,*precOperator,iter,flag);
620   timer->stop("krylov");
621 
622   MPI_Barrier(MPI_COMM_WORLD);
623   double tf = MPI_Wtime();
624 
625   // Don't trust residual computation, so repeat.
626   auto myb = kkt_b->clone();
627   myb->set(*kkt_b);
628   auto norm_myb = myb->norm();
629   auto tmp = kkt_b->clone();
630   RealT dummytol = 1e-8;
631   kktOperator.apply(*tmp, *kkt_x_out, dummytol);
632   tmp->axpy(-1, *myb);
633   auto norm_myAxmb = tmp->norm();
634   auto norm_mysoln = kkt_x_out->norm();
635 
636   if(myRank==0) {
637      (*outStream) << prefix << "Krylov Iteration = " << iter << " " << (finalTol / res0) << " " << tf-t0 << std::endl;
638      (*outStream) << "||x||=" << norm_mysoln << "  ||b||=" << norm_myb << "  ||Ax-b||=" << norm_myAxmb << std::endl;
639 
640      const std::map<int,std::vector<double>> & preSmooth = pint_con->getPreSmoothResidualReductions();
641      const std::map<int,std::vector<double>> & postSmooth = pint_con->getPostSmoothResidualReduction();
642      const std::vector<double> & coarseSmooth = pint_con->getCoarseResidualReduction();
643 
644      if(not useWathenPrec) {
645        // loop over presmoother residual reductions
646        *outStream << "Presmooth Reductions: " << std::endl;
647        for(auto iter_l : preSmooth) {
648          double average = std::accumulate( iter_l.second.begin(), iter_l.second.end(), 0.0)/coarseSmooth.size();
649          double min = *std::min_element(iter_l.second.begin(),iter_l.second.end());
650          double max = *std::max_element(iter_l.second.begin(),iter_l.second.end());
651          *outStream << "  level ";
652          *outStream << "min,avg,max = " << min << ", " << average << ", " << max << std::endl;
653        }
654 
655        // loop over postsmoother residual reductions
656        *outStream << "Postsmooth Reductions: " << std::endl;
657        for(auto iter_l : postSmooth) {
658          double average = std::accumulate( iter_l.second.begin(), iter_l.second.end(), 0.0)/coarseSmooth.size();
659          double min = *std::min_element(iter_l.second.begin(),iter_l.second.end());
660          double max = *std::max_element(iter_l.second.begin(),iter_l.second.end());
661          *outStream << "  level ";
662          *outStream << "min,avg,max = " << min << ", " << average << ", " << max << std::endl;
663        }
664 
665        // loop over coarse residual reductions
666        {
667          *outStream << "Coarse Reductions: ";
668          double average = std::accumulate( coarseSmooth.begin(), coarseSmooth.end(), 0.0)/coarseSmooth.size();
669          double min = *std::min_element(coarseSmooth.begin(),coarseSmooth.end());
670          double max = *std::max_element(coarseSmooth.begin(),coarseSmooth.end());
671          *outStream << "min,avg,max = " << min << ", " << average << ", " << max << std::endl;
672          *outStream << std::endl;
673        }
674      }
675   }
676 
677   pint_con->clearResidualReduction();
678 
679   return kkt_x_out;
680 }
681