MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
snopt_interface.hpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #ifndef __MAST_snopt_optimization_interface_h__
21 #define __MAST_snopt_optimization_interface_h__
22 
23 // C++ includes
24 #include <map>
25 
26 // MAST includes
27 #include <mast/base/mast_config.h>
29 #include <mast/base/exceptions.hpp>
31 
32 // libMesh includes
33 #include <libmesh/parallel.h>
34 
35 extern "C" {
36 
37 extern void sninit_(int* iPrint,
38  int* iSumm,
39  const char* cw,
40  int* lencw,
41  int* iw,
42  int* leniw,
43  double* rw,
44  int* lenrw);
45 
46 extern void sninitf_(const char* printfile,
47  const char* summary_file,
48  int* iPrint,
49  int* iSumm,
50  const char* cw,
51  int* lencw,
52  int* iw,
53  int* leniw,
54  double* rw,
55  int* lenrw);
56 
57 extern void snspec_(int* iSpecs,
58  int* INFO,
59  const char* cw,
60  int* lencw,
61  int* iw,
62  int* leniw,
63  double* rw,
64  int* lenrw);
65 
66 extern void snspecf_(const char* specsfile,
67  int* INFO,
68  const char* cw,
69  int* lencw,
70  int* iw,
71  int* leniw,
72  double* rw,
73  int* lenrw);
74 
75 extern void npopt_(int* n,
76  int* nclin,
77  int* ncnln,
78  int* ldA,
79  int* ldgg,
80  int* ldH,
81  double* A,
82  double* bl,
83  double* bu,
84  void (*)(int* mode,
85  int* ncnln,
86  int* n,
87  int* ldJ,
88  int* needc,
89  double* x,
90  double* c,
91  double* cJac,
92  int* nstate),
93  void (*)(int* mode,
94  int* n,
95  double* x,
96  double* f,
97  double* g,
98  int* nstate),
99  int* INFO,
100  int* majIts,
101  int* iState,
102  double* fCon,
103  double* gCon,
104  double* cMul,
105  double* fObj,
106  double* gObj,
107  double* Hess,
108  double* x,
109  int* iw,
110  int* leniw,
111  double* re,
112  int* lenrw);
113 
114 extern void npoptn_(const char*, int );
115 }
116 
117 
118 namespace MAST {
119 namespace Optimization {
120 namespace Solvers {
121 
122 typedef void (*funobj) (int* mode,
123  int* n,
124  double* x,
125  double* f,
126  double* g,
127  int* nstate);
128 
129 
130 typedef void (*funcon) (int* mode,
131  int* ncnln,
132  int* n,
133  int* ldJ,
134  int* needc,
135  double* x,
136  double* c,
137  double* cJac,
138  int* nstate);
139 
140 
141 template <typename FunctionEvaluationType>
143 
144 public:
145 
146  SNOPTInterface(libMesh::Parallel::Communicator &comm):
147  _comm (comm),
148  _feval (nullptr),
149  _total_iter (0),
150  _funobj (nullptr),
151  _funcon (nullptr) {
152 
153 #if MAST_ENABLE_SNOPT == 0
154  Error(false, "MAST configured without SNOPT support.");
155 #endif
156 
157  _exit_message[0] = "Finished successfully";
158  _exit_message[10] = " The problem appears to be infeasible 20 The problem appears to be unbounded 30 Resource limit error";
159  _exit_message[40] = " Terminated after numerical difficulties 50 Error in the user-supplied functions";
160  _exit_message[60] = " Undefined user-supplied functions";
161  _exit_message[70] = " User requested termination";
162  _exit_message[80] = " Insufficient storage allocated";
163  _exit_message[90] = " Input arguments out of range";
164  _exit_message[100] = " Finished successfully (associated with SNOPT auxiliary routines) 110 Errors while processing MPS data";
165  _exit_message[120] = " Errors while estimating Jacobian structure";
166  _exit_message[130] = " Errors while reading the Specs file";
167  _exit_message[140] = " System error";
168 
169  _info_message[1] = "optimality conditions satisfied";
170  _info_message[2] = "feasible point found";
171  _info_message[3] = "requested accuracy could not be achieved";
172  _info_message[11] = "infeasible linear constraints";
173  _info_message[12] = "infeasible linear equality constraints";
174  _info_message[13] = "nonlinear infeasibilities minimized";
175  _info_message[14] = "linear infeasibilities minimized";
176  _info_message[15] = "infeasible linear constraints in QP subproblem";
177  _info_message[16] = "infeasible nonelastic constraints";
178  _info_message[21] = "unbounded objective";
179  _info_message[22] = "constraint violation limit reached";
180  _info_message[31] = "iteration limit reached";
181  _info_message[32] = "major iteration limit reached";
182  _info_message[33] = "the superbasics limit is too small";
183  _info_message[41] = "current point cannot be improved";
184  _info_message[42] = "singular basis";
185  _info_message[43] = "cannot satisfy the general constraints";
186  _info_message[44] = "ill-conditioned null-space basis";
187  _info_message[51] = "incorrect objective derivatives";
188  _info_message[52] = "incorrect constraint derivatives";
189  _info_message[56] = "irregular or badly scaled problem functions";
190  _info_message[61] = "undefined function at the first feasible point";
191  _info_message[62] = "undefined function at the initial point";
192  _info_message[63] = "unable to proceed into undefined region";
193  _info_message[71] = "terminated during function evaluation";
194  _info_message[72] = "terminated during constraint evaluation";
195  _info_message[73] = "terminated during objective evaluation";
196  _info_message[74] = "terminated from monitor routine";
197  _info_message[81] = "work arrays must have at least 500 elements";
198  _info_message[82] = "not enough character storage";
199  _info_message[83] = "not enough integer storage";
200  _info_message[84] = "not enough real storage";
201  _info_message[91] = "invalid input argument";
202  _info_message[92] = "basis file dimensions do not match this problem";
203  _info_message[141] = "wrong number of basic variables";
204  _info_message[142] = "error in basis package";
205 
206  }
207 
208  virtual ~SNOPTInterface() { }
209 
210  inline void set_function_evaluation(FunctionEvaluationType& feval) {
211 
212 #if MAST_ENABLE_SNOPT == 1
213  Assert0(!_feval, "Function evaluation object already set");
214 
215  _feval = &feval;
216  _funobj = feval.get_objective_evaluation_function();
217  _funcon = feval.get_constraint_evaluation_function();
218 #endif
219  }
220 
221 
225  inline void init() {
226 
227  Assert0(_feval, "Function evaluation object not set");
228 
229  int
230  N = _feval->n_vars(),
231  _total_iter = 0;
232 
233  _XVAL.resize(N, 0.);
234  _XMIN.resize(N, 0.);
235  _XMAX.resize(N, 0.);
236 
237  _feval->init_dvar(_XVAL, _XMIN, _XMAX);
238  }
239 
240  inline void optimize() {
241 
242 #if MAST_ENABLE_SNOPT == 1
243  // make sure that functions have been provided
244  Assert0(_funobj, "Objective function pointer not initialized");
245  Assert0(_funcon, "Objective function pointer not initialized");
246 
247  int
248  iPrint = 9,
249  iSpec = 4,
250  iSumm = 6,
251  lencw = 500,
252  N = _feval->n_vars(),
253  NCLIN = 0,
254  NCNLN = _feval->n_eq()+_feval->n_ineq(),
255  NCTOTL = N+NCLIN+NCNLN,
256  LDA = std::max(NCLIN, 1),
257  LDJ = std::max(NCNLN, 1),
258  LDR = N,
259  INFORM = 0, // on exit: Reports result of call to NPSOL
260  // < 0 either funobj or funcon has set this to -ve
261  // 0 => converged to point x
262  // 1 => x satisfies optimality conditions, but sequence of iterates has not converged
263  // 2 => Linear constraints and bounds cannot be satisfied. No feasible solution
264  // 3 => Nonlinear constraints and bounds cannot be satisfied. No feasible solution
265  // 4 => Major iter limit was reached
266  // 6 => x does not satisfy first-order optimality to required accuracy
267  // 7 => function derivatives seem to be incorrect
268  // 9 => input parameter invalid
269  ITER = 0, // iter count
270  LENIW = std::max(1200*(NCTOTL+N) ,1000),
271  LENW = std::max(2400*(NCTOTL+N), 1000);
272 
273  real_t
274  F = 0.; // on exit: final objective
275 
276  std::vector<int>
277  IW (LENIW, 0),
278  ISTATE (NCTOTL, 0); // status of constraints l <= r(x) <= u,
279  // -2 => lower bound is violated by more than delta
280  // -1 => upper bound is violated by more than delta
281  // 0 => both bounds are satisfied by more than delta
282  // 1 => lower bound is active (to within delta)
283  // 2 => upper bound is active (to within delta)
284  // 3 => boundars are equal and equality constraint is satisfied
285 
286  std::vector<real_t>
287  A (LDA, 0.), // this is used for liear constraints, not currently handled
288  BL (NCTOTL, 0.),
289  BU (NCTOTL, 0.),
290  C (NCNLN, 0.), // on exit: nonlinear constraints
291  CJAC (LDJ* N, 0.), //
292  // on exit: CJAC(i,j) is the partial derivative of ith nonlinear constraint
293  CLAMBDA (NCTOTL, 0.), // on entry: need not be initialized for cold start
294  // on exit: QP multiplier from the QP subproblem, >=0 if istate(j)=1, <0 if istate(j)=2
295  G (N, 0.), // on exit: objective gradient
296  R (LDR*N, 0.), // on entry: need not be initialized if called with Cold Statrt
297  // on exit: information about Hessian, if Hessian=Yes, R is upper Cholesky factor of approx H
298  X (N, 0.), // on entry: initial point
299  // on exit: final estimate of solution
300  W (LENW, 0.), // workspace
301  xmin (N, 0.),
302  xmax (N, 0.);
303 
304 
305  // now setup the lower and upper limits for the variables and constraints
306  _feval->init_dvar(X, xmin, xmax);
307  for (unsigned int i=0; i<N; i++) {
308  BL[i] = xmin[i];
309  BU[i] = xmax[i];
310  }
311 
312  // all constraints are assumed to be g_i(x) <= 0, so that the upper
313  // bound is 0 and lower bound is -infinity
314  for (unsigned int i=0; i<NCNLN; i++) {
315  BL[i+N] = -1.e20;
316  BU[i+N] = 0.;
317  }
318 
319  std::string cw(lencw*8,' ');
320  // nm = "List";
321  // npoptn_(nm.c_str(), (int)nm.length());
322  // nm = "Verify level 3";
323  // npoptn_(nm.c_str(), (int)nm.length());
324 
325  sninit_(&iPrint,
326  &iSumm,
327  cw.c_str(),
328  &lencw,
329  &IW[0],
330  &LENIW,
331  &W[0],
332  &LENW);
333 
334  snspec_(&iSpec, &INFORM, cw.c_str(), &lencw, &IW[0], &LENIW, &W[0], &LENW);
335 
336  Error(INFORM != 101, "INFORM == 101. Stopping");
337 
338  npopt_(&N,
339  &NCLIN,
340  &NCNLN,
341  &LDA,
342  &LDJ,
343  &LDR,
344  &A[0],
345  &BL[0],
346  &BU[0],
347  _funcon,
348  _funobj,
349  &INFORM,
350  &ITER,
351  &ISTATE[0],
352  &C[0],
353  &CJAC[0],
354  &CLAMBDA[0],
355  &F,
356  &G[0],
357  &R[0],
358  &X[0],
359  &IW[0],
360  &LENIW,
361  &W[0],
362  &LENW);
363 
365 
366 #endif // MAST_ENABLE_SNOPT 1
367  }
368 
369 
370 protected:
371 
372  inline void _print_termination_message(const int INFORM) {
373 
374  int
375  exit = (INFORM%10)*10; // remove the last signifncant digit
376 
377  libmesh_assert(_exit_message.count(exit));
378  libmesh_assert(_info_message.count(INFORM));
379 
380  std::cout
381  << "SNOPT EXIT :" << exit << std::endl
382  << " " << _exit_message[exit] << std::endl
383  << " INFO :" << INFORM << std::endl
384  << " " << _info_message[INFORM] << std::endl << std::endl;
385  }
386 
387 
388  void (*_funobj) (int* mode,
389  int* n,
390  double* x,
391  double* f,
392  double* g,
393  int* nstate);
394 
395  void (*_funcon) (int* mode,
396  int* ncnln,
397  int* n,
398  int* ldJ,
399  int* needc,
400  double* x,
401  double* c,
402  double* cJac,
403  int* nstate);
404 
405  libMesh::Parallel::Communicator &_comm;
406  FunctionEvaluationType *_feval;
408  std::map<int, std::string> _exit_message;
409  std::map<int, std::string> _info_message;
410  std::vector<real_t> _XVAL, _XMIN, _XMAX;
411 };
412 
413 } // namespace Solvers
414 } // namespace Optimization
415 } // namespace MAST
416 
417 
418 #endif // __MAST_snopt_optimization_interface_h__
#define Error(cond, msg)
Definition: exceptions.hpp:166
void(* _funcon)(int *mode, int *ncnln, int *n, int *ldJ, int *needc, double *x, double *c, double *cJac, int *nstate)
void sninit_(int *iPrint, int *iSumm, const char *cw, int *lencw, int *iw, int *leniw, double *rw, int *lenrw)
void npoptn_(const char *, int)
void snspec_(int *iSpecs, int *INFO, const char *cw, int *lencw, int *iw, int *leniw, double *rw, int *lenrw)
SNOPTInterface(libMesh::Parallel::Communicator &comm)
std::map< int, std::string > _exit_message
void set_function_evaluation(FunctionEvaluationType &feval)
libMesh::Parallel::Communicator & _comm
void npopt_(int *n, int *nclin, int *ncnln, int *ldA, int *ldgg, int *ldH, double *A, double *bl, double *bu, void(*)(int *mode, int *ncnln, int *n, int *ldJ, int *needc, double *x, double *c, double *cJac, int *nstate), void(*)(int *mode, int *n, double *x, double *f, double *g, int *nstate), int *INFO, int *majIts, int *iState, double *fCon, double *gCon, double *cMul, double *fObj, double *gObj, double *Hess, double *x, int *iw, int *leniw, double *re, int *lenrw)
void(* funcon)(int *mode, int *ncnln, int *n, int *ldJ, int *needc, double *x, double *c, double *cJac, int *nstate)
void init()
initializes the design variable vector from the function object.
void snspecf_(const char *specsfile, int *INFO, const char *cw, int *lencw, int *iw, int *leniw, double *rw, int *lenrw)
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
void(* funobj)(int *mode, int *n, double *x, double *f, double *g, int *nstate)
std::map< int, std::string > _info_message
double real_t
void sninitf_(const char *printfile, const char *summary_file, int *iPrint, int *iSumm, const char *cw, int *lencw, int *iw, int *leniw, double *rw, int *lenrw)
void(* _funobj)(int *mode, int *n, double *x, double *f, double *g, int *nstate)