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_02.cpp
45     \brief Shows how to solve the Poisson-Boltzmann problem.
46 */
47 
48 #include "Teuchos_Comm.hpp"
49 #include "Teuchos_GlobalMPISession.hpp"
50 #include "Teuchos_XMLParameterListHelpers.hpp"
51 
52 #include "Tpetra_Core.hpp"
53 #include "Tpetra_Version.hpp"
54 
55 #include <iostream>
56 #include <algorithm>
57 
58 #include "ROL_Stream.hpp"
59 #include "ROL_OptimizationSolver.hpp"
60 #include "ROL_UnaryFunctions.hpp"
61 #include "ROL_Bounds.hpp"
62 #include "ROL_Reduced_Objective_SimOpt.hpp"
63 #include "ROL_MonteCarloGenerator.hpp"
64 #include "ROL_TpetraTeuchosBatchManager.hpp"
65 #include "ROL_CompositeConstraint_SimOpt.hpp"
66 
67 #include "../TOOLS/linearpdeconstraint.hpp"
68 #include "../TOOLS/pdeconstraint.hpp"
69 #include "../TOOLS/pdeobjective.hpp"
70 #include "../TOOLS/pdevector.hpp"
71 #include "../TOOLS/batchmanager.hpp"
72 #include "pde_poisson_boltzmann_ex02.hpp"
73 #include "mesh_poisson_boltzmann_ex02.hpp"
74 #include "obj_poisson_boltzmann_ex02.hpp"
75 
76 typedef double RealT;
77 
78 template<class Real>
random(const Teuchos::Comm<int> & comm,const Real a=-1,const Real b=1)79 Real random(const Teuchos::Comm<int> &comm,
80             const Real a = -1, const Real b = 1) {
81   Real val(0), u(0);
82   if ( Teuchos::rank<int>(comm)==0 ) {
83     u   = static_cast<Real>(rand())/static_cast<Real>(RAND_MAX);
84     val = (b-a)*u + a;
85   }
86   Teuchos::broadcast<int,Real>(comm,0,1,&val);
87   return val;
88 }
89 
main(int argc,char * argv[])90 int main(int argc, char *argv[]) {
91   // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided.
92   int iprint     = argc - 1;
93   ROL::Ptr<std::ostream> outStream;
94   ROL::nullstream bhs; // outputs nothing
95 
96   /*** Initialize communicator. ***/
97   Teuchos::GlobalMPISession mpiSession (&argc, &argv, &bhs);
98   ROL::Ptr<const Teuchos::Comm<int> > comm
99     = Tpetra::getDefaultComm();
100   ROL::Ptr<const Teuchos::Comm<int> > serial_comm
101     = ROL::makePtr<Teuchos::SerialComm<int>>();
102   const int myRank = comm->getRank();
103   if ((iprint > 0) && (myRank == 0)) {
104     outStream = ROL::makePtrFromRef(std::cout);
105   }
106   else {
107     outStream = ROL::makePtrFromRef(bhs);
108   }
109   int errorFlag  = 0;
110 
111   // *** Example body.
112   try {
113 
114     /*** Read in XML input ***/
115     std::string filename = "input_ex02.xml";
116     Teuchos::RCP<Teuchos::ParameterList> parlist = Teuchos::rcp( new Teuchos::ParameterList() );
117     Teuchos::updateParametersFromXmlFile( filename, parlist.ptr() );
118 
119     /*** Initialize main data structure. ***/
120     ROL::Ptr<MeshManager<RealT> > meshMgr
121       = ROL::makePtr<MeshManager_Example02<RealT>>(*parlist);
122     // Initialize PDE describe Poisson's equation
123     ROL::Ptr<PDE_Poisson_Boltzmann_ex02<RealT> > pde
124       = ROL::makePtr<PDE_Poisson_Boltzmann_ex02<RealT>>(*parlist);
125     ROL::Ptr<ROL::Constraint_SimOpt<RealT> > con
126       = ROL::makePtr<PDE_Constraint<RealT>>(pde,meshMgr,serial_comm,*parlist,*outStream);
127     ROL::Ptr<PDE_Constraint<RealT> > pdeCon
128       = ROL::dynamicPtrCast<PDE_Constraint<RealT> >(con);
129     ROL::Ptr<PDE_Doping<RealT> > pdeDoping
130       = ROL::makePtr<PDE_Doping<RealT>>(*parlist);
131     ROL::Ptr<ROL::Constraint_SimOpt<RealT> > conDoping
132       = ROL::makePtr<Linear_PDE_Constraint<RealT>>(pdeDoping,meshMgr,serial_comm,*parlist,*outStream,true);
133     const ROL::Ptr<Assembler<RealT> > assembler = pdeCon->getAssembler();
134     assembler->printMeshData(*outStream);
135     con->setSolveParameters(*parlist);
136 
137     /*************************************************************************/
138     /***************** BUILD VECTORS *****************************************/
139     /*************************************************************************/
140     ROL::Ptr<Tpetra::MultiVector<> >  u_ptr = assembler->createStateVector();
141     ROL::Ptr<Tpetra::MultiVector<> >  p_ptr = assembler->createStateVector();
142     ROL::Ptr<Tpetra::MultiVector<> >  r_ptr = assembler->createResidualVector();
143     ROL::Ptr<Tpetra::MultiVector<> >  z_ptr = assembler->createControlVector();
144     ROL::Ptr<ROL::Vector<RealT> > up, pp, rp, zp;
145     u_ptr->randomize();  //u_ptr->putScalar(static_cast<RealT>(1));
146     p_ptr->randomize();  //p_ptr->putScalar(static_cast<RealT>(1));
147     r_ptr->randomize();  //r_ptr->putScalar(static_cast<RealT>(1));
148     z_ptr->randomize();  //z_ptr->putScalar(static_cast<RealT>(1));
149     up = ROL::makePtr<PDE_PrimalSimVector<RealT>>(u_ptr,pde,assembler,*parlist);
150     pp = ROL::makePtr<PDE_PrimalSimVector<RealT>>(p_ptr,pde,assembler,*parlist);
151     rp = ROL::makePtr<PDE_DualSimVector<RealT>>(r_ptr,pde,assembler,*parlist);
152     zp = ROL::makePtr<PDE_PrimalOptVector<RealT>>(z_ptr,pde,assembler,*parlist);
153 
154     /*************************************************************************/
155     /***************** BUILD SAMPLER *****************************************/
156     /*************************************************************************/
157     int stochDim = 3;
158     std::vector<ROL::Ptr<ROL::Distribution<RealT> > > distVec(stochDim);
159     // Build lambda2 distribution
160     Teuchos::ParameterList LvolList;
161     LvolList.sublist("Distribution").set("Name","Uniform");
162     LvolList.sublist("Distribution").sublist("Uniform").set("Lower Bound", -2.0);
163     LvolList.sublist("Distribution").sublist("Uniform").set("Upper Bound", -1.0);
164     distVec[0] = ROL::DistributionFactory<RealT>(LvolList);
165     // Build delta2 distribution
166     Teuchos::ParameterList DvolList;
167     DvolList.sublist("Distribution").set("Name","Uniform");
168     DvolList.sublist("Distribution").sublist("Uniform").set("Lower Bound", -1.0);
169     DvolList.sublist("Distribution").sublist("Uniform").set("Upper Bound",  0.0);
170     distVec[1] = ROL::DistributionFactory<RealT>(DvolList);
171     // Build doping diffusion distribution
172     Teuchos::ParameterList dopeList;
173     dopeList.sublist("Distribution").set("Name","Uniform");
174     dopeList.sublist("Distribution").sublist("Uniform").set("Lower Bound", 2e-6);
175     dopeList.sublist("Distribution").sublist("Uniform").set("Upper Bound", 2e-4);
176     distVec[2] = ROL::DistributionFactory<RealT>(dopeList);
177     // Build sampler
178     int nsamp = parlist->sublist("Problem").get("Number of Samples",100);
179     ROL::Ptr<ROL::BatchManager<RealT> > bman
180       = ROL::makePtr<ROL::TpetraTeuchosBatchManager<RealT>>(comm);
181     ROL::Ptr<ROL::SampleGenerator<RealT> > sampler
182       = ROL::makePtr<ROL::MonteCarloGenerator<RealT>>(nsamp,distVec,bman);
183     // Print samples
184     std::vector<RealT> sample(stochDim), Lmean(stochDim), Gmean(stochDim);
185     std::stringstream name_samp;
186     name_samp << "samples_" << bman->batchID() << ".txt";
187     std::ofstream file_samp;
188     file_samp.open(name_samp.str());
189     for (int i = 0; i < sampler->numMySamples(); ++i) {
190       sample = sampler->getMyPoint(i);
191       file_samp << std::scientific << std::setprecision(15);
192       for (int j = 0; j < stochDim; ++j) {
193         file_samp << std::setw(25) << std::left << sample[j];
194         Lmean[j] += sampler->getMyWeight(i)*sample[j];
195       }
196       file_samp << std::endl;
197     }
198     file_samp.close();
199     bman->sumAll(&Lmean[0],&Gmean[0],stochDim);
200 
201     /*************************************************************************/
202     /***************** BUILD REFERENCE DOPING AND POTENTIAL ******************/
203     /*************************************************************************/
204     ROL::Ptr<Tpetra::MultiVector<> > ru_ptr = assembler->createStateVector();
205     ROL::Ptr<ROL::Vector<RealT> > rup
206       = ROL::makePtr<PDE_PrimalSimVector<RealT>>(ru_ptr,pde,assembler,*parlist);
207     ROL::Ptr<Tpetra::MultiVector<> > rz_ptr = assembler->createControlVector();
208     ROL::Ptr<ROL::Vector<RealT> > rzp
209       = ROL::makePtr<PDE_PrimalOptVector<RealT>>(rz_ptr,pde,assembler,*parlist);
210     ROL::Ptr<Doping<RealT> > dope
211       = ROL::makePtr<Doping<RealT>>(pde->getFE(),
212                                        assembler->getDofManager()->getCellDofs(),
213                                        assembler->getCellIds(),*parlist);
214     // Initialize "filtered" of "unfiltered" constraint.
215     ROL::Ptr<ROL::Constraint_SimOpt<RealT> > pdeWithDoping
216       = ROL::makePtr<ROL::CompositeConstraint_SimOpt<RealT>>(con, conDoping,
217         *rp, *rp, *up, *zp, *zp, true, true);
218     pdeWithDoping->setSolveParameters(*parlist);
219     dope->build(rz_ptr);
220     RealT tol(1.e-8);
221     pdeWithDoping->setParameter(Gmean);
222     pdeWithDoping->solve(*rp,*rup,*rzp,tol);
223     pdeCon->outputTpetraVector(ru_ptr,"reference_state.txt");
224     pdeCon->outputTpetraVector(rz_ptr,"reference_control.txt");
225 
226     /*************************************************************************/
227     /***************** BUILD COST FUNCTIONAL *********************************/
228     /*************************************************************************/
229     std::vector<ROL::Ptr<QoI<RealT> > > qoi_vec(3,ROL::nullPtr);
230     // Current flow over drain
231     qoi_vec[0] = ROL::makePtr<QoI_State_Cost_1_Poisson_Boltzmann<RealT>>(pde->getFE(),
232                                     pde->getBdryFE(),pde->getBdryCellLocIds(),*parlist);
233     ROL::Ptr<IntegralObjective<RealT> > stateObj
234       = ROL::makePtr<IntegralObjective<RealT>>(qoi_vec[0],assembler);
235     // Deviation from reference doping
236     qoi_vec[1] = ROL::makePtr<QoI_Control_Cost_1_Poisson_Boltzmann<RealT>>(pde->getFE(),dope);
237     ROL::Ptr<IntegralObjective<RealT> > ctrlObj1
238       = ROL::makePtr<IntegralObjective<RealT>>(qoi_vec[1],assembler);
239     // H1-Seminorm of doping
240     qoi_vec[2] = ROL::makePtr<QoI_Control_Cost_2_Poisson_Boltzmann<RealT>>(pde->getFE());
241     ROL::Ptr<IntegralObjective<RealT> > ctrlObj2
242       = ROL::makePtr<IntegralObjective<RealT>>(qoi_vec[2],assembler);
243     // Build standard vector objective function
244     RealT currentWeight = parlist->sublist("Problem").get("Desired Current Scale",1.5);
245     RealT J = stateObj->value(*rup,*rzp,tol); // Reference current flow over drain
246     J *= currentWeight; // Increase current flow by 50%
247     RealT w1 = parlist->sublist("Problem").get("State Cost Parameter",1e-3);
248     RealT w2 = parlist->sublist("Problem").get("Control Misfit Parameter",1e-2);
249     RealT w3 = parlist->sublist("Problem").get("Control Cost Parameter",1e-8);
250     ROL::Ptr<ROL::StdObjective<RealT> > std_obj
251       = ROL::makePtr<StdObjective_Poisson_Boltzmann<RealT>>(J,w1,w2,w3);
252     // Build full-space objective
253     ROL::Ptr<PDE_Objective<RealT> > obj
254       = ROL::makePtr<PDE_Objective<RealT>>(qoi_vec,std_obj,assembler);
255     // Build reduced-space objective
256     bool storage = parlist->sublist("Problem").get("Use state storage",true);
257     ROL::Ptr<ROL::SimController<RealT> > stateStore
258       = ROL::makePtr<ROL::SimController<RealT>>();
259     ROL::Ptr<ROL::Reduced_Objective_SimOpt<RealT> > objReduced
260       = ROL::makePtr<ROL::Reduced_Objective_SimOpt<RealT>>(
261                        obj,pdeWithDoping,stateStore,up,zp,pp,storage);
262 
263     /*************************************************************************/
264     /***************** BUILD BOUND CONSTRAINT ********************************/
265     /*************************************************************************/
266     ROL::Ptr<Tpetra::MultiVector<> > lo_ptr = assembler->createControlVector();
267     ROL::Ptr<Tpetra::MultiVector<> > hi_ptr = assembler->createControlVector();
268     ROL::Ptr<DopingBounds<RealT> > dopeBnd
269       = ROL::makePtr<DopingBounds<RealT>>(pde->getFE(),
270                                              assembler->getDofManager()->getCellDofs(),
271                                              assembler->getCellIds(),*parlist);
272     dopeBnd->build(lo_ptr,hi_ptr);
273     ROL::Ptr<ROL::Vector<RealT> > lop, hip;
274     lop = ROL::makePtr<PDE_PrimalOptVector<RealT>>(lo_ptr,pde,assembler);
275     hip = ROL::makePtr<PDE_PrimalOptVector<RealT>>(hi_ptr,pde,assembler);
276     ROL::Ptr<ROL::BoundConstraint<RealT> > bnd
277       = ROL::makePtr<ROL::Bounds<RealT>>(lop,hip);
278     bool deactivate = parlist->sublist("Problem").get("Deactivate Bound Constraints",false);
279     if (deactivate) {
280       bnd->deactivate();
281     }
282 
283     /*************************************************************************/
284     /***************** BUILD STOCHASTIC PROBLEM ******************************/
285     /*************************************************************************/
286     ROL::OptimizationProblem<RealT> opt(objReduced,zp,bnd);
287     parlist->sublist("SOL").set("Initial Statistic", static_cast<RealT>(1));
288     opt.setStochasticObjective(*parlist,sampler);
289 
290     /*************************************************************************/
291     /***************** RUN VECTOR AND DERIVATIVE CHECKS **********************/
292     /*************************************************************************/
293     bool checkDeriv = parlist->sublist("Problem").get("Check Derivatives",false);
294     if ( checkDeriv ) {
295       ROL::Ptr<Tpetra::MultiVector<> > du_ptr = assembler->createStateVector();
296       ROL::Ptr<Tpetra::MultiVector<> > dz_ptr = assembler->createControlVector();
297       du_ptr->randomize(); //du_ptr->putScalar(static_cast<RealT>(0));
298       dz_ptr->randomize(); //dz_ptr->putScalar(static_cast<RealT>(1));
299       ROL::Ptr<ROL::Vector<RealT> > dup, dzp;
300       dup = ROL::makePtr<PDE_PrimalSimVector<RealT>>(du_ptr,pde,assembler,*parlist);
301       dzp = ROL::makePtr<PDE_PrimalOptVector<RealT>>(dz_ptr,pde,assembler,*parlist);
302       // Create ROL SimOpt vectors
303       ROL::Vector_SimOpt<RealT> x(up,zp);
304       ROL::Vector_SimOpt<RealT> d(dup,dzp);
305 
306       objReduced->setParameter(Gmean);
307       *outStream << "\n\nCheck Gradient of Full Objective Function\n";
308       obj->checkGradient(x,d,true,*outStream);
309       *outStream << "\n\nCheck Hessian of Full Objective Function\n";
310       obj->checkHessVec(x,d,true,*outStream);
311       *outStream << "\n\nCheck Full Jacobian of PDE Constraint\n";
312       pdeWithDoping->checkApplyJacobian(x,d,*rp,true,*outStream);
313       *outStream << "\n\nCheck Jacobian_1 of PDE Constraint\n";
314       pdeWithDoping->checkApplyJacobian_1(*up,*zp,*dup,*rp,true,*outStream);
315       *outStream << "\n\nCheck Jacobian_2 of PDE Constraint\n";
316       pdeWithDoping->checkApplyJacobian_2(*up,*zp,*dzp,*rp,true,*outStream);
317       *outStream << "\n\nCheck Full Hessian of PDE Constraint\n";
318       pdeWithDoping->checkApplyAdjointHessian(x,*pp,d,x,true,*outStream);
319       *outStream << "\n";
320       pdeWithDoping->checkAdjointConsistencyJacobian(*dup,d,x,true,*outStream);
321       *outStream << "\n";
322       pdeWithDoping->checkInverseJacobian_1(*rp,*dup,*up,*zp,true,*outStream);
323       *outStream << "\n";
324       *outStream << "\n\nCheck Gradient of Reduced Objective Function\n";
325       objReduced->checkGradient(*zp,*dzp,true,*outStream);
326       *outStream << "\n\nCheck Hessian of Reduced Objective Function\n";
327       objReduced->checkHessVec(*zp,*dzp,true,*outStream);
328 
329       opt.check(*outStream);
330     }
331 
332     /*************************************************************************/
333     /***************** SOLVE OPTIMIZATION PROBLEM ****************************/
334     /*************************************************************************/
335     parlist->sublist("Step").set("Type","Trust Region");
336     ROL::OptimizationSolver<RealT> solver(opt,*parlist);
337     zp->set(*rzp);
338     std::clock_t timer = std::clock();
339     solver.solve(*outStream);
340     *outStream << "Optimization time: "
341                << static_cast<RealT>(std::clock()-timer)/static_cast<RealT>(CLOCKS_PER_SEC)
342                << " seconds." << std::endl << std::endl;
343 
344     /*************************************************************************/
345     /***************** OUTPUT RESULTS ****************************************/
346     /*************************************************************************/
347     std::clock_t timer_print = std::clock();
348     // Output control to file
349     pdeCon->outputTpetraVector(z_ptr,"control.txt");
350     // Output expected state and samples to file
351     ROL::Ptr<Tpetra::MultiVector<> > Lu_ptr = assembler->createStateVector();
352     ROL::Ptr<Tpetra::MultiVector<> > Lv_ptr = assembler->createStateVector();
353     ROL::Ptr<Tpetra::MultiVector<> > Gu_ptr = assembler->createStateVector();
354     ROL::Ptr<Tpetra::MultiVector<> > Gv_ptr = assembler->createStateVector();
355     ROL::Ptr<ROL::Vector<RealT> > Lup, Gup, Lvp, Gvp;
356     Lup = ROL::makePtr<PDE_PrimalSimVector<RealT>>(Lu_ptr,pde,assembler,*parlist);
357     Lvp = ROL::makePtr<PDE_PrimalSimVector<RealT>>(Lv_ptr,pde,assembler,*parlist);
358     Gup = ROL::makePtr<PDE_PrimalSimVector<RealT>>(Gu_ptr,pde,assembler,*parlist);
359     Gvp = ROL::makePtr<PDE_PrimalSimVector<RealT>>(Gv_ptr,pde,assembler,*parlist);
360     ROL::Elementwise::Power<RealT> sqr(2.0);
361     for (int i = 0; i < sampler->numMySamples(); ++i) {
362       sample = sampler->getMyPoint(i);
363       con->setParameter(sample);
364       con->solve(*rp,*Gup,*zp,tol);
365       Gvp->set(*Gup); Gvp->applyUnary(sqr);
366       Lup->axpy(sampler->getMyWeight(i),*Gup);
367       Lvp->axpy(sampler->getMyWeight(i),*Gvp);
368     }
369     bman->sumAll(*Lup,*Gup);
370     pdeCon->outputTpetraVector(Gu_ptr,"mean_state.txt");
371     bman->sumAll(*Lvp,*Gvp);
372     Gup->applyUnary(sqr);
373     Gvp->axpy(-1.0,*Gup);
374     pdeCon->outputTpetraVector(Gv_ptr,"variance_state.txt");
375     // Build objective function distribution
376     RealT val(0), val1(0), val2(0);
377     int nsamp_dist = parlist->sublist("Problem").get("Number of Output Samples",100);
378     ROL::Ptr<ROL::SampleGenerator<RealT> > sampler_dist
379       = ROL::makePtr<ROL::MonteCarloGenerator<RealT>>(nsamp_dist,distVec,bman);
380     std::stringstream name;
381     name << "obj_samples_" << bman->batchID() << ".txt";
382     std::ofstream file;
383     file.open(name.str());
384     for (int i = 0; i < sampler_dist->numMySamples(); ++i) {
385       sample = sampler_dist->getMyPoint(i);
386       objReduced->setParameter(sample);
387       val  = objReduced->value(*zp,tol);
388       val1 = ctrlObj1->value(*up,*zp,tol);
389       val2 = ctrlObj2->value(*up,*zp,tol);
390       file << std::scientific << std::setprecision(15);
391       for (int j = 0; j < stochDim; ++j) {
392         file << std::setw(25) << std::left << sample[j];
393       }
394       file << std::setw(25) << std::left << val;
395       file << std::setw(25) << std::left << (val-w2*val1-w3*val2)/w1;
396       file << std::setw(25) << std::left << val1;
397       file << std::setw(25) << std::left << val2;
398       file << std::endl;
399     }
400     file.close();
401     *outStream << "Output time: "
402                << static_cast<RealT>(std::clock()-timer_print)/static_cast<RealT>(CLOCKS_PER_SEC)
403                << " seconds." << std::endl << std::endl;
404   }
405   catch (std::logic_error& err) {
406     *outStream << err.what() << "\n";
407     errorFlag = -1000;
408   }; // end try
409 
410   if (errorFlag != 0)
411     std::cout << "End Result: TEST FAILED\n";
412   else
413     std::cout << "End Result: TEST PASSED\n";
414 
415   return 0;
416 }
417