ROL
function/constraint/test_04.cpp
Go to the documentation of this file.
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 #include "Teuchos_oblackholestream.hpp"
45 #include "Teuchos_GlobalMPISession.hpp"
46 
48 
50 
51 typedef double Real;
52 
57 double run_test(MPI_Comm comm, const ROL::Ptr<std::ostream> & outStream,int numSteps);
58 
59 int main(int argc, char* argv[])
60 {
61  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
62 
63  // This little trick lets us print to std::cout only if a (dummy) command-line argument is provided.
64  int iprint = argc - 1;
65  ROL::Ptr<std::ostream> outStream;
66  Teuchos::oblackholestream bhs; // outputs nothing
67  if (iprint > 0)
68  outStream = ROL::makePtrFromRef(std::cout);
69  else
70  outStream = ROL::makePtrFromRef(bhs);
71 
72  int numRanks = -1;
73  int myRank = -1;
74 
75  MPI_Comm_size(MPI_COMM_WORLD, &numRanks);
76  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
77 
78  MPI_Comm subComm;
79 
80  // split the comm so if three processors are used you can run a 3, 2 and 1 processor
81  // case all at once
82  if(numRanks!=3) {
83  *outStream << "WARNING: This test is most effective with three processors" << std::endl;
84  }
85  else {
86  MPI_Comm_split(MPI_COMM_WORLD,myRank==0,myRank,&subComm);
87  }
88 
89  int numSteps = 10;
90  int errorFlag = 0;
91 
92  try {
93  double all_final = run_test(MPI_COMM_WORLD, outStream,numSteps);
94 
95  MPI_Barrier(MPI_COMM_WORLD);
96 
97  // run the serial and 2 processor cases as well
98  if(numRanks==3) {
99 
100  // because of the splitting this actually runs two jobs at once
101  double sub_final = run_test(subComm, outStream,numSteps);
102 
103  *outStream << "ALL processors result = " << all_final << std::endl;
104  *outStream << "SUB processors result = " << sub_final << std::endl;
105 
106  if(sub_final!=all_final) {
107  int subRanks = 0;
108  MPI_Comm_size(subComm, &subRanks);
109 
110  std::stringstream ss;
111  ss << "ALL processors result does not match SUB(p=" << subRanks << ") result: " << all_final << " != " << sub_final;
112  throw std::logic_error(ss.str());
113  }
114  }
115  else {
116  *outStream << "ALL processors result = " << all_final << std::endl;
117  }
118  }
119  catch (std::logic_error err) {
120  *outStream << err.what() << "\n";
121  errorFlag = -1000;
122  }; // end try
123 
124  // cleanup split comm
125  if(numRanks==3)
126  MPI_Comm_free(&subComm); // cleanup
127 
128  int errors = std::abs(errorFlag);
129  MPI_Allreduce(&errors,&errorFlag,1,MPI_INT,MPI_MAX,MPI_COMM_WORLD);
130 
131  if (errorFlag != 0)
132  std::cout << "End Result: TEST FAILED\n";
133  else
134  std::cout << "End Result: TEST PASSED\n";
135 
136  return 0;
137 }
138 
139 double run_test(MPI_Comm comm, const ROL::Ptr<std::ostream> & outStream,int numSteps)
140 {
141  typedef ROL::Ptr<ROL::Vector<Real>> PtrVector;
142 
143  int numRanks = -1;
144  int myRank = -1;
145 
146  MPI_Comm_size(comm, &numRanks);
147  MPI_Comm_rank(comm, &myRank);
148 
149  *outStream << "Proc " << myRank << "/" << numRanks << std::endl;
150 
151  double totaltime = 1.75; // we will do 1.75 periods, this way the final result is non-trivial
152  double dt = totaltime/numSteps;
153  double omega = 2.0*M_PI;
154  double tol = 1e-14;
155 
156  ROL::Ptr<const ROL::PinTCommunicators> communicators = ROL::makePtr<ROL::PinTCommunicators>(comm,1);
157 
158  ROL::Ptr< ROL::PinTVector<Real>> state, state_unit;
159  ROL::Ptr< ROL::PinTVector<Real>> control, control_unit;
160 
161  {
162  // allocate local state vector
163  ROL::Ptr<std::vector<Real>> u_data_ptr = ROL::makePtr<std::vector<Real>>(3);
164  std::vector<Real> & u_data = *u_data_ptr;
165  u_data[0] = 0.0;
166  u_data[1] = omega;
167  u_data[2] = 1.0;
168  PtrVector u = ROL::makePtr<ROL::StdVector<Real>>(u_data_ptr);
169 
170  ROL::Ptr<std::vector<Real>> u_data_unit_ptr = ROL::makePtr<std::vector<Real>>(3);
171  std::vector<Real> & u_data_unit = *u_data_unit_ptr;
172  u_data_unit[0] = 1.0;
173  u_data_unit[1] = 1.0;
174  u_data_unit[2] = 1.0;
175  PtrVector u_unit = ROL::makePtr<ROL::StdVector<Real>>(u_data_unit_ptr);
176  // this requirement to use a copy constructor tripped me up for a while
177 
178  // allocate control vector
179  std::vector<Real> z_data(1);
180  z_data[0] = 1.0;
181  PtrVector z = ROL::makePtr<ROL::StdVector<Real>>(ROL::makePtr<std::vector<Real>>(z_data));
182 
183  state = buildPinTVector(communicators,numSteps,{-1,0} /* state stencil */,u);
184  state_unit = buildPinTVector(communicators,numSteps,{-1,0} /* state stencil */,u_unit);
185  control = buildPinTVector(communicators,numSteps,{0} /* control stencil */,z);
186  control_unit = buildPinTVector(communicators,numSteps,{0} /* control stencil */,z);
187 
188  state->getVectorPtr(-1)->set(*u); // set the initial condition
189  state_unit->getVectorPtr(-1)->zero(); // set the initial condition: because this is used as a perturbation, we have to be careful!
190  }
191 
192  ROL::Ptr<ROL::Constraint_TimeSimOpt<Real>> step_constraint = ROL::makePtr<ODE_Constraint<Real>>(dt,omega);
193 
194  ROL::Ptr<ROL::Constraint_PinTSimOpt<Real>> pint_constraint = ROL::makePtr<ROL::Constraint_PinTSimOpt<Real>>(step_constraint);
195 
196  PtrVector u = state_unit;
197  PtrVector z = control_unit->clone();
198  PtrVector c = state->clone();
199  PtrVector jv = c->clone();
200  PtrVector v_u = state_unit->clone();
201  PtrVector v_z = control_unit->clone();
202  PtrVector w_u = state->dual().clone();
203  PtrVector w_z = control->dual().clone();
204  PtrVector w_c = c->dual().clone();
205  PtrVector hv_u = state->dual().clone();
206  PtrVector hv_z = z->dual().clone();
207 
208  ROL::RandomizeVector<RealT>(*u); // this randomization doesn't really matter here as 'u' is complete determine by the solve
209  ROL::RandomizeVector<RealT>(*z);
210  ROL::RandomizeVector<RealT>(*v_u);
211  ROL::RandomizeVector<RealT>(*v_z);
212  ROL::RandomizeVector<RealT>(*w_u);
213  ROL::RandomizeVector<RealT>(*w_z);
214  ROL::RandomizeVector<RealT>(*w_c);
215 
216  // check the solve
218  {
219  if(myRank==0)
220  *outStream << "Checking solve" << std::endl;
221 
222  double solveNorm = pint_constraint->checkSolve(*u,*z,*c,true,*outStream);
223 
224  if(solveNorm>tol) {
225  std::stringstream ss;
226  ss << "Solve failed on problem with " << numRanks << " processors and " << numSteps << ": residual = " << solveNorm
227  << " > " << tol << std::endl;
228  throw std::logic_error(ss.str());
229  }
230  else if(myRank==0) {
231  *outStream << "Solve checked out for p=" << numRanks << " with residual = " << solveNorm << std::endl;
232  }
233  }
234 
235  // check the Jacobian_1
237  {
238  if(myRank==0)
239  *outStream << "Checking apply Jacobian 1" << std::endl;
240 
241  auto errors = pint_constraint->checkApplyJacobian_1(*u,*z,*v_u,*jv,true,*outStream);
242  if(errors[6][3]/errors[6][1] >= 1e-6)
243  throw std::logic_error("Constraint apply jacobian 1 is incorrect");
244  }
245 
246  // check the Jacobian_2
248  {
249  if(myRank==0)
250  *outStream << "Checking apply Jacobian 2" << std::endl;
251 
252  auto errors = pint_constraint->checkApplyJacobian_2(*u,*z,*v_z,*jv,true,*outStream);
253  if(errors[6][3]/errors[6][1] >= 1e-6)
254  throw std::logic_error("Constraint apply jacobian 2 is incorrect");
255  }
256 
257  // check the Adjoint Jacobian_1
259  {
260  if(myRank==0)
261  *outStream << "Checking apply Adjoint Jacobian 1" << std::endl;
262 
263  auto error = pint_constraint->checkAdjointConsistencyJacobian_1(*w_u,*v_u,*u,*z,true,*outStream);
264  if(error >= 1e-8)
265  throw std::logic_error("Constraint apply adjoint jacobian 1 is incorrect");
266  }
267 
268  // check the Adjoint Jacobian_2
270  {
271  if(myRank==0)
272  *outStream << "Checking apply Adjoint Jacobian 2" << std::endl;
273 
274  auto error = pint_constraint->checkAdjointConsistencyJacobian_2(*w_u,*v_z,*u,*z,true,*outStream);
275  if(error >= 1e-8)
276  throw std::logic_error("Constraint apply adjoint jacobian 2 is incorrect");
277  }
278 
279  // check the Adjoint Hessian 11
281  {
282  if(myRank==0)
283  *outStream << "Checking apply Adjoint Hessian_11" << std::endl;
284 
285  auto errors = pint_constraint->checkApplyAdjointHessian_11(*u,*z,*w_c,*v_u,*hv_u,true,*outStream);
286  if(errors[6][3]/errors[6][1] >= 1e-4) // wow, this is really not very good accuracy
287  throw std::logic_error("Constraint apply Adjoint Hessian 11 is incorrect: " + std::to_string( errors[6][3]/errors[6][1]));
288  }
289 
290  // check the Adjoint Hessian_12
292  {
293  if(myRank==0)
294  *outStream << "Checking apply Adjoint Hessian_12" << std::endl;
295 
296  auto errors = pint_constraint->checkApplyAdjointHessian_12(*u,*z,*w_c,*v_u,*hv_z,true,*outStream);
297  if(errors[6][3] >= 1e-5)
298  throw std::logic_error("Constraint apply Adjoint Hessian 12 is incorrect");
299  }
300 
301  // check the Adjoint Hessian_21
303  {
304  if(myRank==0)
305  *outStream << "Checking apply Adjoint Hessian_21" << std::endl;
306 
307  auto errors = pint_constraint->checkApplyAdjointHessian_21(*u,*z,*w_c,*v_z,*hv_u,true,*outStream);
308  if(errors[6][3] >= 1e-5)
309  throw std::logic_error("Constraint apply Adjoint Hessian 12 is incorrect");
310  }
311 
312  // check the Adjoint Hessian_22
314  {
315  if(myRank==0)
316  *outStream << "Checking apply Adjoint Hessian_22" << std::endl;
317 
318  auto errors = pint_constraint->checkApplyAdjointHessian_22(*u,*z,*w_c,*v_z,*hv_z,true,*outStream);
319  if(errors[6][3] >= 1e-5)
320  throw std::logic_error("Constraint apply Adjoint Hessian 12 is incorrect");
321  }
322 
323  // This computes and returns the last value of the 'u' component and shares
324  // it with all processors.
326  double final_result = 0.0;
327  {
328  PtrVector z_unit = control_unit->clone();
329  z->scale(0.0); // z can't be random as the different processor counts won't give the same values
330  z->axpy(3.0,*z_unit);
331 
332  *outStream << "ZNORM = " << z->norm() << std::endl;
333 
334  pint_constraint->solve(*c,*u,*z,tol);
335 
336  // pull out the last value
337  if(myRank==numRanks-1) {
338  PtrVector final_state = state->getVectorPtr(state->numOwnedSteps()-1);
339  // *outStream << "Final state = " << final_state << std::endl;
340  // final_state->print(*outStream);
341 
342  const std::vector<Real> & fs_stdvec = *dynamic_cast<const ROL::StdVector<Real>&>(*final_state).getVector();
343  final_result = fs_stdvec[0];
344  }
345 
346  MPI_Bcast(&final_result,1,MPI_DOUBLE,numRanks-1,comm);
347  }
348 
349  return final_result;
350 }
Ptr< PinTVector< Real > > buildPinTVector(const Ptr< const PinTCommunicators > &communicators, int steps, const std::vector< int > &stencil, const Ptr< Vector< Real >> &localVector)
double run_test(MPI_Comm comm, const ROL::Ptr< std::ostream > &outStream, int numSteps)
ROL::Ptr< const std::vector< Element > > getVector() const
int main(int argc, char *argv[])