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