MittelmannDistCntrlNeumA.cpp 16 KB

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