MittelmannBndryCntrlNeum.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. // Copyright (C) 2005, 2006 International Business Machines and others.
  2. // All Rights Reserved.
  3. // This code is published under the Eclipse Public License.
  4. //
  5. // $Id: MittelmannBndryCntrlNeum.cpp 2005 2011-06-06 12:55:16Z stefan $
  6. //
  7. // Authors: Andreas Waechter IBM 2005-10-18
  8. // based on MyNLP.cpp
  9. #include "MittelmannBndryCntrlNeum.hpp"
  10. #ifdef HAVE_CASSERT
  11. # include <cassert>
  12. #else
  13. # ifdef HAVE_ASSERT_H
  14. # include <assert.h>
  15. # else
  16. # error "don't have header file for assert"
  17. # endif
  18. #endif
  19. using namespace Ipopt;
  20. /* Constructor. */
  21. MittelmannBndryCntrlNeumBase::MittelmannBndryCntrlNeumBase()
  22. :
  23. y_d_(NULL)
  24. {}
  25. MittelmannBndryCntrlNeumBase::~MittelmannBndryCntrlNeumBase()
  26. {
  27. delete [] y_d_;
  28. }
  29. void
  30. MittelmannBndryCntrlNeumBase::SetBaseParameters(Index N, Number alpha,
  31. Number lb_y, Number ub_y,
  32. Number lb_u, Number ub_u,
  33. Number u_init)
  34. {
  35. N_ = N;
  36. h_ = 1./(N+1);
  37. hh_ = h_*h_;
  38. alpha_ = alpha;
  39. lb_y_ = lb_y;
  40. ub_y_ = ub_y;
  41. lb_u_ = lb_u;
  42. ub_u_ = ub_u;
  43. u_init_ = u_init;
  44. // Initialize the target profile variables
  45. delete [] y_d_;
  46. y_d_ = new Number[(N_+2)*(N_+2)];
  47. for (Index j=0; j<= N_+1; j++) {
  48. for (Index i=0; i<= N_+1; i++) {
  49. y_d_[y_index(i,j)] = y_d_cont(x1_grid(i),x2_grid(j));
  50. }
  51. }
  52. }
  53. bool MittelmannBndryCntrlNeumBase::get_nlp_info(
  54. Index& n, Index& m, Index& nnz_jac_g,
  55. Index& nnz_h_lag, IndexStyleEnum& index_style)
  56. {
  57. // We for each of the N_+2 times N_+2 mesh points we have the value
  58. // of the functions y, and for each 4*N_ boundary mesh points we
  59. // have values for u
  60. n = (N_+2)*(N_+2) + 4*N_;
  61. // For each of the N_ times N_ interior mesh points we have the
  62. // discretized PDE, and we have one constriant for each boundary
  63. // point (except for the corners)
  64. m = N_*N_ + 4*N_;
  65. // y(i,j), y(i-1,j), y(i+1,j), y(i,j-1), y(i,j+1) for each of the
  66. // N_*N_ discretized PDEs, and for the Neumann boundary conditions
  67. // we have entries for two y's and one u
  68. nnz_jac_g = 5*N_*N_ + 3*4*N_;
  69. // diagonal entry for each dydy, dudu, dydu in the interior
  70. nnz_h_lag = N_*N_;
  71. if (!b_cont_dydy_alwayszero()) {
  72. nnz_h_lag += 4*N_;
  73. }
  74. if (alpha_!=0.) {
  75. nnz_h_lag += 4*N_;
  76. }
  77. // We use the C indexing style for row/col entries (corresponding to
  78. // the C notation, starting at 0)
  79. index_style = C_STYLE;
  80. return true;
  81. }
  82. bool
  83. MittelmannBndryCntrlNeumBase::get_bounds_info(Index n, Number* x_l, Number* x_u,
  84. Index m, Number* g_l, Number* g_u)
  85. {
  86. // Set overall bounds on the y variables
  87. for (Index i=0; i<=N_+1; i++) {
  88. for (Index j=0; j<=N_+1; j++) {
  89. Index iy = y_index(i,j);
  90. x_l[iy] = lb_y_;
  91. x_u[iy] = ub_y_;
  92. }
  93. }
  94. // Set overall bounds on the u variables
  95. for (Index j=1; j<=N_; j++) {
  96. Index iu = u0j_index(j);
  97. x_l[iu] = lb_u_;
  98. x_u[iu] = ub_u_;
  99. }
  100. for (Index j=1; j<=N_; j++) {
  101. Index iu = u1j_index(j);
  102. x_l[iu] = lb_u_;
  103. x_u[iu] = ub_u_;
  104. }
  105. for (Index i=1; i<=N_; i++) {
  106. Index iu = ui0_index(i);
  107. x_l[iu] = lb_u_;
  108. x_u[iu] = ub_u_;
  109. }
  110. for (Index i=1; i<=N_; i++) {
  111. Index iu = ui1_index(i);
  112. x_l[iu] = lb_u_;
  113. x_u[iu] = ub_u_;
  114. }
  115. // There is no information for the y's at the corner points, so just
  116. // take those variables out
  117. x_l[y_index(0,0)] = x_u[y_index(0,0)] = 0.;
  118. x_l[y_index(0,N_+1)] = x_u[y_index(0,N_+1)] = 0.;
  119. x_l[y_index(N_+1,0)] = x_u[y_index(N_+1,0)] = 0.;
  120. x_l[y_index(N_+1,N_+1)] = x_u[y_index(N_+1,N_+1)] = 0.;
  121. // all discretized PDE constraints have right hand side zero
  122. for (Index i=0; i<m; i++) {
  123. g_l[i] = 0.;
  124. g_u[i] = 0.;
  125. }
  126. return true;
  127. }
  128. bool
  129. MittelmannBndryCntrlNeumBase::get_starting_point(Index n, bool init_x, Number* x,
  130. bool init_z, Number* z_L, Number* z_U,
  131. Index m, bool init_lambda,
  132. Number* lambda)
  133. {
  134. // Here, we assume we only have starting values for x, if you code
  135. // your own NLP, you can provide starting values for the others if
  136. // you wish.
  137. assert(init_x == true);
  138. assert(init_z == false);
  139. assert(init_lambda == false);
  140. // set all y's to the perfect match with y_d
  141. for (Index i=0; i<= N_+1; i++) {
  142. for (Index j=0; j<= N_+1; j++) {
  143. x[y_index(i,j)] = y_d_[y_index(i,j)];
  144. //x[y_index(i,j)] += h_*x1_grid(i) + 2*h_*x2_grid(j);
  145. }
  146. }
  147. // Set the initial (constant) value for the u's
  148. for (Index j=1; j<= N_; j++) {
  149. x[u0j_index(j)] = u_init_;
  150. x[u1j_index(j)] = u_init_;
  151. }
  152. for (Index i=1; i<= N_; i++) {
  153. x[ui0_index(i)] = u_init_;
  154. x[ui1_index(i)] = u_init_;
  155. }
  156. return true;
  157. }
  158. bool
  159. MittelmannBndryCntrlNeumBase::get_scaling_parameters(Number& obj_scaling,
  160. bool& use_x_scaling,
  161. Index n, Number* x_scaling,
  162. bool& use_g_scaling,
  163. Index m, Number* g_scaling)
  164. {
  165. obj_scaling = 1./hh_;
  166. use_x_scaling = false;
  167. use_g_scaling = false;
  168. return true;
  169. }
  170. bool
  171. MittelmannBndryCntrlNeumBase::eval_f(Index n, const Number* x,
  172. bool new_x, Number& obj_value)
  173. {
  174. // return the value of the objective function
  175. obj_value = 0.;
  176. // First the integration of y-td over the interior
  177. for (Index i=1; i<=N_; i++) {
  178. for (Index j=1; j<= N_; j++) {
  179. Index iy = y_index(i,j);
  180. Number tmp = x[iy] - y_d_[iy];
  181. obj_value += tmp*tmp;
  182. }
  183. }
  184. obj_value *= hh_/2.;
  185. // Now the integration of u over the boundary
  186. if (alpha_!=0.) {
  187. Number usum = 0.;
  188. for (Index j=1; j<=N_; j++) {
  189. Index iu = u0j_index(j);
  190. usum += x[iu]*x[iu];
  191. }
  192. for (Index j=1; j<=N_; j++) {
  193. Index iu = u1j_index(j);
  194. usum += x[iu]*x[iu];
  195. }
  196. for (Index i=1; i<=N_; i++) {
  197. Index iu = ui0_index(i);
  198. usum += x[iu]*x[iu];
  199. }
  200. for (Index i=1; i<=N_; i++) {
  201. Index iu = ui1_index(i);
  202. usum += x[iu]*x[iu];
  203. }
  204. obj_value += alpha_*h_/2.*usum;
  205. }
  206. return true;
  207. }
  208. bool
  209. MittelmannBndryCntrlNeumBase::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
  210. {
  211. // return the gradient of the objective function grad_{x} f(x)
  212. // now let's take care of the nonzero values coming from the
  213. // integrant over the interior
  214. for (Index i=1; i<=N_; i++) {
  215. for (Index j=1; j<= N_; j++) {
  216. Index iy = y_index(i,j);
  217. grad_f[iy] = hh_*(x[iy] - y_d_[iy]);
  218. }
  219. }
  220. // The values for variables on the boundary
  221. if (alpha_!=0.) {
  222. for (Index j=1; j<= N_; j++) {
  223. Index iu = u0j_index(j);
  224. grad_f[iu] = alpha_*h_*x[iu];
  225. }
  226. for (Index j=1; j<= N_; j++) {
  227. Index iu = u1j_index(j);
  228. grad_f[iu] = alpha_*h_*x[iu];
  229. }
  230. for (Index i=1; i<= N_; i++) {
  231. Index iu = ui0_index(i);
  232. grad_f[iu] = alpha_*h_*x[iu];
  233. }
  234. for (Index i=1; i<= N_; i++) {
  235. Index iu = ui1_index(i);
  236. grad_f[iu] = alpha_*h_*x[iu];
  237. }
  238. }
  239. else {
  240. for (Index j=1; j<= N_; j++) {
  241. Index iu = u0j_index(j);
  242. grad_f[iu] = 0.;
  243. }
  244. for (Index j=1; j<= N_; j++) {
  245. Index iu = u1j_index(j);
  246. grad_f[iu] = 0.;
  247. }
  248. for (Index i=1; i<= N_; i++) {
  249. Index iu = ui0_index(i);
  250. grad_f[iu] = 0.;
  251. }
  252. for (Index i=1; i<= N_; i++) {
  253. Index iu = ui1_index(i);
  254. grad_f[iu] = 0.;
  255. }
  256. }
  257. // The values are zero for y variables on the boundary
  258. for (Index i=0; i<= N_+1; i++) {
  259. grad_f[y_index(i,0)] = 0.;
  260. }
  261. for (Index i=0; i<= N_+1; i++) {
  262. grad_f[y_index(i,N_+1)] = 0.;
  263. }
  264. for (Index j=1; j<= N_; j++) {
  265. grad_f[y_index(0,j)] = 0.;
  266. }
  267. for (Index j=1; j<= N_; j++) {
  268. grad_f[y_index(N_+1,j)] = 0.;
  269. }
  270. return true;
  271. }
  272. bool MittelmannBndryCntrlNeumBase::eval_g(Index n, const Number* x, bool new_x,
  273. Index m, Number* g)
  274. {
  275. // return the value of the constraints: g(x)
  276. // compute the discretized PDE for each interior grid point
  277. Index ig=0;
  278. for (Index i=1; i<=N_; i++) {
  279. for (Index j=1; j<=N_; j++) {
  280. Number val;
  281. // Start with the discretized Laplacian operator
  282. val = 4.* x[y_index(i,j)]
  283. - x[y_index(i-1,j)] - x[y_index(i+1,j)]
  284. - x[y_index(i,j-1)] - x[y_index(i,j+1)];
  285. // Add the forcing term (including the step size here)
  286. val += hh_*d_cont(x1_grid(i), x2_grid(j), x[y_index(i,j)]);
  287. g[ig] = val;
  288. ig++;
  289. }
  290. }
  291. // set up the Neumann boundary conditions
  292. for (Index j=1; j<= N_; j++) {
  293. g[ig] = x[y_index(0,j)] - x[y_index(1,j)]
  294. - h_*b_cont(x1_grid(0), x2_grid(j), x[y_index(0,j)], x[u0j_index(j)]);
  295. ig++;
  296. }
  297. for (Index j=1; j<= N_; j++) {
  298. g[ig] = x[y_index(N_+1,j)] - x[y_index(N_,j)]
  299. - h_*b_cont(x1_grid(N_+1), x2_grid(j), x[y_index(N_+1,j)], x[u1j_index(j)]);
  300. ig++;
  301. }
  302. for (Index i=1; i<= N_; i++) {
  303. g[ig] = x[y_index(i,0)] - x[y_index(i,1)]
  304. - h_*b_cont(x1_grid(i), x2_grid(0), x[y_index(i,0)], x[ui0_index(i)]);
  305. ig++;
  306. }
  307. for (Index i=1; i<= N_; i++) {
  308. g[ig] = x[y_index(i,N_+1)] - x[y_index(i,N_)]
  309. - h_*b_cont(x1_grid(i), x2_grid(N_+1), x[y_index(i,N_+1)], x[ui1_index(i)]);
  310. ig++;
  311. }
  312. DBG_ASSERT(ig==m);
  313. return true;
  314. }
  315. bool MittelmannBndryCntrlNeumBase::eval_jac_g(Index n, const Number* x, bool new_x,
  316. Index m, Index nele_jac, Index* iRow, Index *jCol,
  317. Number* values)
  318. {
  319. if (values == NULL) {
  320. // return the structure of the jacobian of the constraints
  321. // distretized PDEs
  322. Index ijac = 0;
  323. Index ig = 0;
  324. for (Index i=1; i<= N_; i++) {
  325. for (Index j=1; j<= N_; j++) {
  326. // y(i,j)
  327. iRow[ijac] = ig;
  328. jCol[ijac] = y_index(i,j);
  329. ijac++;
  330. // y(i-1,j)
  331. iRow[ijac] = ig;
  332. jCol[ijac] = y_index(i-1,j);
  333. ijac++;
  334. // y(i+1,j)
  335. iRow[ijac] = ig;
  336. jCol[ijac] = y_index(i+1,j);
  337. ijac++;
  338. // y(i,j-1)
  339. iRow[ijac] = ig;
  340. jCol[ijac] = y_index(i,j-1);
  341. ijac++;
  342. // y(i,j+1)
  343. iRow[ijac] = ig;
  344. jCol[ijac] = y_index(i,j+1);
  345. ijac++;
  346. ig++;
  347. }
  348. }
  349. // set up the Neumann boundary conditions
  350. for (Index j=1; j<=N_; j++) {
  351. iRow[ijac] = ig;
  352. jCol[ijac] = y_index(0,j);
  353. ijac++;
  354. iRow[ijac] = ig;
  355. jCol[ijac] = y_index(1,j);
  356. ijac++;
  357. iRow[ijac] = ig;
  358. jCol[ijac] = u0j_index(j);
  359. ijac++;
  360. ig++;
  361. }
  362. for (Index j=1; j<=N_; j++) {
  363. iRow[ijac] = ig;
  364. jCol[ijac] = y_index(N_,j);
  365. ijac++;
  366. iRow[ijac] = ig;
  367. jCol[ijac] = y_index(N_+1,j);
  368. ijac++;
  369. iRow[ijac] = ig;
  370. jCol[ijac] = u1j_index(j);
  371. ijac++;
  372. ig++;
  373. }
  374. for (Index i=1; i<=N_; i++) {
  375. iRow[ijac] = ig;
  376. jCol[ijac] = y_index(i,0);
  377. ijac++;
  378. iRow[ijac] = ig;
  379. jCol[ijac] = y_index(i,1);
  380. ijac++;
  381. iRow[ijac] = ig;
  382. jCol[ijac] = ui0_index(i);
  383. ijac++;
  384. ig++;
  385. }
  386. for (Index i=1; i<=N_; i++) {
  387. iRow[ijac] = ig;
  388. jCol[ijac] = y_index(i,N_);
  389. ijac++;
  390. iRow[ijac] = ig;
  391. jCol[ijac] = y_index(i,N_+1);
  392. ijac++;
  393. iRow[ijac] = ig;
  394. jCol[ijac] = ui1_index(i);
  395. ijac++;
  396. ig++;
  397. }
  398. DBG_ASSERT(ijac==nele_jac);
  399. }
  400. else {
  401. // return the values of the jacobian of the constraints
  402. Index ijac = 0;
  403. for (Index i=1; i<= N_; i++) {
  404. for (Index j=1; j<= N_; j++) {
  405. // y(i,j)
  406. values[ijac] = 4. + hh_*d_cont_dy(x1_grid(i), x2_grid(j),
  407. x[y_index(i,j)]);
  408. ijac++;
  409. // y(i-1,j)
  410. values[ijac] = -1.;
  411. ijac++;
  412. // y(i+1,j)
  413. values[ijac] = -1.;
  414. ijac++;
  415. // y(1,j-1)
  416. values[ijac] = -1.;
  417. ijac++;
  418. // y(1,j+1)
  419. values[ijac] = -1.;
  420. ijac++;
  421. }
  422. }
  423. for (Index j=1; j<=N_; j++) {
  424. values[ijac] = 1. -
  425. h_*b_cont_dy(x1_grid(0), x2_grid(j), x[y_index(0,j)], x[u0j_index(j)]);
  426. ijac++;
  427. values[ijac] = -1.;
  428. ijac++;
  429. values[ijac] = -h_*b_cont_du(x1_grid(0), x2_grid(j), x[y_index(0,j)], x[u0j_index(j)]);
  430. ijac++;
  431. }
  432. for (Index j=1; j<=N_; j++) {
  433. values[ijac] = -1.;
  434. ijac++;
  435. values[ijac] = 1. -
  436. h_*b_cont_dy(x1_grid(N_+1), x2_grid(j), x[y_index(N_+1,j)], x[u1j_index(j)]);
  437. ijac++;
  438. values[ijac] = -h_*b_cont_du(x1_grid(N_+1), x2_grid(j), x[y_index(N_+1,j)], x[u1j_index(j)]);
  439. ijac++;
  440. }
  441. for (Index i=1; i<=N_; i++) {
  442. values[ijac] = 1. -
  443. h_*b_cont_dy(x1_grid(i), x2_grid(0), x[y_index(i,0)], x[ui0_index(i)]);
  444. ijac++;
  445. values[ijac] = -1.;
  446. ijac++;
  447. values[ijac] = -h_*b_cont_du(x1_grid(i), x2_grid(0), x[y_index(i,0)], x[ui0_index(i)]);
  448. ijac++;
  449. }
  450. for (Index i=1; i<=N_; i++) {
  451. values[ijac] = -1.;
  452. ijac++;
  453. values[ijac] = 1. -
  454. h_*b_cont_dy(x1_grid(i), x2_grid(N_+1), x[y_index(i,N_+1)], x[ui1_index(i)]);
  455. ijac++;
  456. values[ijac] = -h_*b_cont_du(x1_grid(i), x2_grid(N_+1), x[y_index(i,N_+1)], x[ui1_index(i)]);
  457. ijac++;
  458. }
  459. DBG_ASSERT(ijac==nele_jac);
  460. }
  461. return true;
  462. }
  463. bool
  464. MittelmannBndryCntrlNeumBase::eval_h(Index n, const Number* x, bool new_x,
  465. Number obj_factor, Index m,
  466. const Number* lambda,
  467. bool new_lambda, Index nele_hess, Index* iRow,
  468. Index* jCol, Number* values)
  469. {
  470. if (values == NULL) {
  471. // return the structure. This is a symmetric matrix, fill the lower left
  472. // triangle only.
  473. Index ihes=0;
  474. // First the diagonal entries for dydy in the interior
  475. for (Index i=1; i<= N_; i++) {
  476. for (Index j=1; j<= N_; j++) {
  477. iRow[ihes] = y_index(i,j);
  478. jCol[ihes] = y_index(i,j);
  479. ihes++;
  480. }
  481. }
  482. // Now, if necessary, the dydy entries on the boundary
  483. if (!b_cont_dydy_alwayszero()) {
  484. // Now the diagonal entries for dudu
  485. for (Index j=1; j<= N_; j++) {
  486. iRow[ihes] = y_index(0,j);
  487. jCol[ihes] = y_index(0,j);
  488. ihes++;
  489. }
  490. for (Index j=1; j<= N_; j++) {
  491. iRow[ihes] = y_index(N_+1,j);
  492. jCol[ihes] = y_index(N_+1,j);
  493. ihes++;
  494. }
  495. for (Index i=1; i<= N_; i++) {
  496. iRow[ihes] = y_index(i,0);
  497. jCol[ihes] = y_index(i,0);
  498. ihes++;
  499. }
  500. for (Index i=1; i<= N_; i++) {
  501. iRow[ihes] = y_index(i,N_+1);
  502. jCol[ihes] = y_index(i,N_+1);
  503. ihes++;
  504. }
  505. }
  506. if (alpha_!=0.) {
  507. // Now the diagonal entries for dudu
  508. for (Index j=1; j<=N_; j++) {
  509. Index iu = u0j_index(j);
  510. iRow[ihes] = iu;
  511. jCol[ihes] = iu;
  512. ihes++;
  513. }
  514. for (Index j=1; j<=N_; j++) {
  515. Index iu = u1j_index(j);
  516. iRow[ihes] = iu;
  517. jCol[ihes] = iu;
  518. ihes++;
  519. }
  520. for (Index i=1; i<= N_; i++) {
  521. Index iu = ui0_index(i);
  522. iRow[ihes] = iu;
  523. jCol[ihes] = iu;
  524. ihes++;
  525. }
  526. for (Index i=1; i<= N_; i++) {
  527. Index iu = ui1_index(i);
  528. iRow[ihes] = iu;
  529. jCol[ihes] = iu;
  530. ihes++;
  531. }
  532. }
  533. DBG_ASSERT(ihes==nele_hess);
  534. }
  535. else {
  536. // return the values
  537. Index ihes=0;
  538. Index ihes_store;
  539. // First the diagonal entries for dydy
  540. ihes_store = ihes;
  541. for (Index i=1; i<= N_; i++) {
  542. for (Index j=1; j<= N_; j++) {
  543. // Contribution from the objective function
  544. values[ihes] = obj_factor*hh_;
  545. ihes++;
  546. }
  547. }
  548. // If we have something from the discretized PDEs, add this now
  549. if (!d_cont_dydy_alwayszero()) {
  550. Index ig = 0;
  551. ihes = ihes_store;
  552. for (Index i=1; i<=N_; i++) {
  553. for (Index j=1; j<=N_; j++) {
  554. values[ihes] += lambda[ig]*hh_*d_cont_dydy(x1_grid(i), x2_grid(j), x[y_index(i,j)]);
  555. ihes++;
  556. ig++;
  557. }
  558. }
  559. }
  560. // Now include the elements for dydy on the boudary if there are any
  561. if (!b_cont_dydy_alwayszero()) {
  562. Index ig = N_*N_;
  563. // Now the diagonal entries for dudu
  564. for (Index j=1; j<= N_; j++) {
  565. values[ihes] = -lambda[ig]*h_*b_cont_dydy(x1_grid(0), x2_grid(j), x[y_index(0,j)], x[u0j_index(j)]);
  566. ig++;
  567. ihes++;
  568. }
  569. for (Index j=1; j<= N_; j++) {
  570. values[ihes] = -lambda[ig]*h_*b_cont_dydy(x1_grid(N_+1), x2_grid(j), x[y_index(N_+1,j)], x[u1j_index(j)]);
  571. ig++;
  572. ihes++;
  573. }
  574. for (Index i=1; i<= N_; i++) {
  575. values[ihes] = -lambda[ig]*h_*b_cont_dydy(x1_grid(i), x2_grid(0), x[y_index(i,0)], x[ui0_index(i)]);
  576. ig++;
  577. ihes++;
  578. }
  579. for (Index i=1; i<= N_; i++) {
  580. values[ihes] = -lambda[ig]*h_*b_cont_dydy(x1_grid(i), x2_grid(N_+1), x[y_index(i,N_+1)], x[ui1_index(i)]);
  581. ig++;
  582. ihes++;
  583. }
  584. }
  585. // Finally, we take care of the dudu entries
  586. if (alpha_!=0.) {
  587. // Now the diagonal entries for u at the boundary
  588. for (Index i=1; i<=N_; i++) {
  589. values[ihes] = obj_factor*h_*alpha_;
  590. ihes++;
  591. }
  592. for (Index i=1; i<=N_; i++) {
  593. values[ihes] = obj_factor*h_*alpha_;
  594. ihes++;
  595. }
  596. for (Index j=1; j<=N_; j++) {
  597. values[ihes] = obj_factor*h_*alpha_;
  598. ihes++;
  599. }
  600. for (Index i=1; i<=N_; i++) {
  601. values[ihes] = obj_factor*h_*alpha_;
  602. ihes++;
  603. }
  604. }
  605. }
  606. return true;
  607. }
  608. void
  609. MittelmannBndryCntrlNeumBase::finalize_solution(SolverReturn status,
  610. Index n, const Number* x, const Number* z_L, const Number* z_U,
  611. Index m, const Number* g, const Number* lambda, Number obj_value,
  612. const IpoptData* ip_data,
  613. IpoptCalculatedQuantities* ip_cq)
  614. {
  615. /*
  616. FILE* fp = fopen("solution.txt", "w+");
  617. for (Index i=0; i<=N_+1; i++) {
  618. for (Index j=0; j<=N_+1; j++) {
  619. fprintf(fp, "y[%6d,%6d] = %15.8e\n", i, j, x[y_index(i,j)]);
  620. }
  621. }
  622. for (Index j=1; j<=N_; j++) {
  623. fprintf(fp, "u[%6d,%6d] = %15.8e\n", 0, j, x[u0j_index(j)]);
  624. }
  625. for (Index j=1; j<=N_; j++) {
  626. fprintf(fp, "u[%6d,%6d] = %15.8e\n", N_+1, j, x[u1j_index(j)]);
  627. }
  628. for (Index i=1; i<=N_; i++) {
  629. fprintf(fp, "u[%6d,%6d] = %15.8e\n", i, 0, x[ui0_index(i)]);
  630. }
  631. for (Index i=1; i<=N_; i++) {
  632. fprintf(fp, "u[%6d,%6d] = %15.8e\n", i, N_+1, x[ui1_index(i)]);
  633. }
  634. fclose(fp);
  635. */
  636. }