Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mma_cpu.f90
1
33
34submodule(mma) mma_cpu
35 use lapack_interfaces, only: dgesv
36 use mpi_f08, only: mpi_in_place, mpi_max, mpi_min
37 use comm, only: neko_comm, pe_rank, mpi_real_precision
38 use math, only: neko_eps
39 use profiler, only: profiler_start_region, profiler_end_region
40 use, intrinsic :: ieee_arithmetic, only: ieee_is_nan
41
42 implicit none
43
44contains
45
46 module subroutine mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
47 ! ----------------------------------------------------- !
48 ! Update the design variable x by solving the convex !
49 ! approximation of the problem. !
50 ! !
51 ! This subroutine is called in each iteration of the !
52 ! optimization loop !
53 ! ----------------------------------------------------- !
54 class(mma_t), intent(inout) :: this
55 integer, intent(in) :: iter
56 real(kind=rp), dimension(this%n), intent(inout) :: x
57 real(kind=rp), dimension(this%n), intent(in) :: df0dx
58 real(kind=rp), dimension(this%m), intent(in) :: fval
59 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
60
61 if (.not. this%is_initialized) then
62 call neko_error("The MMA object is not initialized.")
63 end if
64
65 call profiler_start_region("MMA update")
66
67 ! generate a convex approximation of the problem
68 call profiler_start_region("MMA gensub")
69 call mma_gensub_cpu(this, iter, x, df0dx, fval, dfdx)
70 call profiler_end_region("MMA gensub")
71
72 !solve the approximation problem using interior point method
73 call profiler_start_region("MMA subsolve")
74 if (this%subsolver .eq. "dip") then
75 call mma_subsolve_dip_cpu(this, x)
76 else if (this%subsolver .eq. "pdip") then
77 call mma_subsolve_pdip_cpu(this, x)
78 else
79 call neko_error("Unrecognized subsolver for MMA in mma_cpu.")
80 end if
81 call profiler_end_region("MMA subsolve")
82
83 call profiler_end_region("MMA update")
84
85 this%is_updated = .true.
86 end subroutine mma_update_cpu
87
89 module subroutine mma_kkt_cpu(this, x, df0dx, fval, dfdx)
90 ! ----------------------------------------------------- !
91 ! Compute the KKT condition right hand side for a given !
92 ! designx x and set the max and norm values of the !
93 ! residue of KKT system to this%residumax and !
94 ! this%residunorm. !
95 ! !
96 ! The left hand sides of the KKT conditions are computed!
97 ! for the following nonlinear programming problem: !
98 ! Minimize f_0(x) + a_0*z + !
99 ! sum(c_i*y_i + 0.5*d_i*(y_i)^2)!
100 ! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
101 ! xmin_j <= x_j <= xmax_j, j = 1,...,n !
102 ! z >= 0, y_i >= 0, i = 1,...,m !
103 ! !
104 ! !
105 ! Note that before calling this function, the function !
106 ! values (f0val, fval, dfdx, ...) should be updated !
107 ! using the new x values. !
108 ! ----------------------------------------------------- !
109 class(mma_t), intent(inout) :: this
110 real(kind=rp), dimension(this%n), intent(in) :: x
111 real(kind=rp), dimension(this%n), intent(in) :: df0dx
112 real(kind=rp), dimension(this%m), intent(in) :: fval
113 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
114
115 call profiler_start_region("MMA KKT computation")
116
117 if (this%subsolver .eq. "dip") then
118 call mma_dip_kkt_cpu(this, x, df0dx, fval, dfdx)
119 else if (this%subsolver .eq. "pdip") then
120 call mma_pdip_kkt_cpu(this, x, df0dx, fval, dfdx)
121 else
122 call neko_error("Unrecognized subsolver for MMA in mma_cpu.")
123 end if
124
125 call profiler_end_region("MMA KKT computation")
126 end subroutine mma_kkt_cpu
127
129 ! point method (pdip) subsolve of MMA algorithm.
130 module subroutine mma_pdip_kkt_cpu(this, x, df0dx, fval, dfdx)
131 ! ----------------------------------------------------- !
132 ! Compute the KKT condition right hand side for a given !
133 ! designx x and set the max and norm values of the !
134 ! residue of KKT system to this%residumax and !
135 ! this%residunorm. !
136 ! !
137 ! The left hand sides of the KKT conditions are computed!
138 ! for the following nonlinear programming problem: !
139 ! Minimize f_0(x) + a_0*z + !
140 ! sum( c_i*y_i + 0.5*d_i*(y_i)^2 )!
141 ! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
142 ! xmin_j <= x_j <= xmax_j, j = 1,...,n !
143 ! z >= 0, y_i >= 0, i = 1,...,m !
144 ! !
145 ! !
146 ! Note that before calling this function, the function !
147 ! values (f0val, fval, dfdx, ...) should be updated !
148 ! using the new x values. !
149 ! ----------------------------------------------------- !
150 class(mma_t), intent(inout) :: this
151 real(kind=rp), dimension(this%n), intent(in) :: x
152 real(kind=rp), dimension(this%n), intent(in) :: df0dx
153 real(kind=rp), dimension(this%m), intent(in) :: fval
154 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
155
156 real(kind=rp) :: rez, rezeta
157 real(kind=rp), dimension(this%m) :: rey, relambda, remu, res
158 real(kind=rp), dimension(this%n) :: rex, rexsi, reeta
159 real(kind=rp), dimension(3*this%n+4*this%m+2) :: residual
160
161 real(kind=rp), dimension(4*this%m+2) :: residual_small
162 integer :: ierr
163 real(kind=rp) :: re_sq_norm
164
165 rex = df0dx + matmul(transpose(dfdx), this%lambda%x) &
166 - this%xsi%x + this%eta%x
167 rey = this%c%x + this%d%x*this%y%x - this%lambda%x - this%mu%x
168 rez = this%a0 - this%zeta - dot_product(this%lambda%x, this%a%x)
169
170 relambda = fval - this%a%x * this%z - this%y%x + this%s%x
171 rexsi = this%xsi%x * (x - this%xmin%x)
172 reeta = this%eta%x * (this%xmax%x - x)
173 remu = this%mu%x * this%y%x
174 rezeta = this%zeta * this%z
175 res = this%lambda%x * this%s%x
176
177 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
178 residual_small = [rey, rez, relambda, remu, rezeta, res]
179
180 this%residumax = maxval(abs(residual))
181 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
182
183 call mpi_allreduce(mpi_in_place, this%residumax, 1, &
184 mpi_real_precision, mpi_max, neko_comm, ierr)
185
186 call mpi_allreduce(mpi_in_place, re_sq_norm, 1, &
187 mpi_real_precision, mpi_sum, neko_comm, ierr)
188
189 this%residunorm = sqrt(norm2(residual_small)**2 + re_sq_norm)
190
191 ! MAXVAL and MPI_MAX can drop a NaN, which would then read as convergence.
192 ! The 2-norm keeps it on every rank: its distributed part is reduced with
193 ! MPI_SUM, and the rest is replicated.
194 if (ieee_is_nan(this%residunorm)) this%residumax = this%residunorm
195 end subroutine mma_pdip_kkt_cpu
196
198 ! point method (dip) subsolve of MMA algorithm.
199 module subroutine mma_dip_kkt_cpu(this, x, df0dx, fval, dfdx)
200 ! ----------------------------------------------------- !
201 ! Compute the KKT residual of the original problem for !
202 ! the design x and set its max and 2-norm to !
203 ! this%residumax and this%residunorm. !
204 ! !
205 ! This follows MMA::KKTresidual in the Cpp code by !
206 ! Niels (topopt_in_petsc). The multipliers lambda and !
207 ! the artificial variables y and z are those of the !
208 ! last subproblem. The residual consists of: !
209 ! - stationarity w.r.t. x_j: !
210 ! df0dx_j + sum_i lambda_i*dfdx_ij - xsi_j + eta_j!
211 ! where the bound multipliers xsi_j, eta_j are !
212 ! estimated for x_j within 1e-5 of xmin_j, xmax_j, !
213 ! - complementarity of the bounds: !
214 ! xsi_j*(x_j - xmin_j) and eta_j*(xmax_j - x_j), !
215 ! - complementarity of the constraints: !
216 ! sum_i lambda_i*(a_i*z + y_i - f_i(x)). !
217 ! The true bounds xmin, xmax are used, not the move !
218 ! limited ones. !
219 ! !
220 ! Note that before calling this function, the function !
221 ! values (f0val, fval, dfdx, ...) should be updated !
222 ! using the new x values. !
223 ! ----------------------------------------------------- !
224 class(mma_t), intent(inout) :: this
225 real(kind=rp), dimension(this%n), intent(in) :: x
226 real(kind=rp), dimension(this%n), intent(in) :: df0dx
227 real(kind=rp), dimension(this%m), intent(in) :: fval
228 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
229
230 real(kind=rp) :: rex, resi, xsi, eta, relambda
231 real(kind=rp) :: residual_max, residual_sq_norm
232 integer :: i, j, ierr
233
234 residual_max = 0.0_rp
235 residual_sq_norm = 0.0_rp
236
237 associate(xmin => this%xmin%x, xmax => this%xmax%x, &
238 lambda => this%lambda%x)
239
240 do j = 1, this%n
241 ! Gradient of the Lagrangian w.r.t. x_j
242 rex = df0dx(j)
243 do i = 1, this%m
244 rex = rex + lambda(i) * dfdx(i, j)
245 end do
246
247 ! Estimate the bound multipliers where x_j is at a bound
248 xsi = 0.0_rp
249 if (x(j) .lt. xmin(j) + 1.0e-5_rp .and. rex .gt. 0.0_rp) xsi = rex
250 eta = 0.0_rp
251 if (x(j) .gt. xmax(j) - 1.0e-5_rp .and. rex .lt. 0.0_rp) eta = -rex
252 rex = rex + (-xsi + eta)
253
254 residual_sq_norm = residual_sq_norm + rex**2
255 residual_max = max(abs(rex), residual_max)
256 resi = xsi * (x(j) - xmin(j))
257 residual_sq_norm = residual_sq_norm + resi**2
258 residual_max = max(abs(resi), residual_max)
259 resi = eta * (xmax(j) - x(j))
260 residual_sq_norm = residual_sq_norm + resi**2
261 residual_max = max(abs(resi), residual_max)
262 end do
263
264 end associate
265
266 call mpi_allreduce(mpi_in_place, residual_sq_norm, 1, &
267 mpi_real_precision, mpi_sum, neko_comm, ierr)
268 call mpi_allreduce(mpi_in_place, residual_max, 1, &
269 mpi_real_precision, mpi_max, neko_comm, ierr)
270
271 ! Complementarity of the constraints, a global quantity
272 relambda = 0.0_rp
273 do i = 1, this%m
274 relambda = relambda + this%lambda%x(i) * &
275 (this%a%x(i) * this%z + this%y%x(i) - fval(i))
276 end do
277
278 this%residumax = max(abs(relambda), residual_max)
279 this%residunorm = sqrt(residual_sq_norm + relambda**2)
280
281 ! MAX and MPI_MAX can drop a NaN, which would then read as convergence.
282 ! The 2-norm keeps it on every rank: its distributed part is reduced with
283 ! MPI_SUM, and the rest is replicated.
284 if (ieee_is_nan(this%residunorm)) this%residumax = this%residunorm
285
286 end subroutine mma_dip_kkt_cpu
287
288 !============================================================================!
289 ! private internal subroutines
290
292 subroutine mma_gensub_cpu(this, iter, x, df0dx, fval, dfdx)
293 ! ----------------------------------------------------- !
294 ! Generate the approximation sub problem by computing !
295 ! the lower and upper asymtotes and the other necessary !
296 ! parameters (alpha, beta, p0j, q0j, pij, qij, ...). !
297 ! ----------------------------------------------------- !
298 class(mma_t), intent(inout) :: this
299 real(kind=rp), dimension(this%n), intent(in) :: x
300 real(kind=rp), dimension(this%n), intent(in) :: df0dx
301 real(kind=rp), dimension(this%m), intent(in) :: fval
302 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
303 integer, intent(in) :: iter
304 integer :: i, j, ierr
305 real(kind=rp), dimension(this%n) :: xmin_eff, xmax_eff
306 real(kind=rp), dimension(this%n) :: x_diff
307 real(kind=rp) :: asy_factor
308
309 xmin_eff = this%xmin%x
310 xmax_eff = this%xmax%x
311 if (this%move_limit .gt. 0.0_rp) then
312 xmin_eff = max(xmin_eff, x - this%move_limit)
313 xmax_eff = min(xmax_eff, x + this%move_limit)
314 end if
315
316 x_diff = max(xmax_eff - xmin_eff, 1.0e-5_rp)
317
318 ! ------------------------------------------------------------------------ !
319 ! Setup the current asymptotes
320 associate(low => this%low%x, upp => this%upp%x, &
321 x_1 => this%xold1%x, x_2 => this%xold2%x)
322
323 if (iter .lt. 3) then
324 ! Initialize the lower and upper asymptotes
325 low = x - this%asyinit * x_diff
326 upp = x + this%asyinit * x_diff
327 else
328 do j = 1, this%n
329 if ((x(j) - x_1(j)) * (x_1(j) - x_2(j)) .lt. 0.0_rp) then
330 asy_factor = this%asydecr
331 else if ((x(j) - x_1(j)) * (x_1(j) - x_2(j)) .gt. 0.0_rp) then
332 asy_factor = this%asyincr
333 else
334 asy_factor = 1.0_rp
335 end if
336
337 low(j) = x(j) - asy_factor * (x_1(j) - low(j))
338 upp(j) = x(j) + asy_factor * (upp(j) - x_1(j))
339 end do
340
341
342 ! Setting a minimum and maximum for the low and upp
343 ! asymptotes (eq3.9)
344 low = max(low, x - 10.0_rp * x_diff)
345 low = min(low, x - 0.01_rp * x_diff)
346
347 upp = min(upp, x + 10.0_rp * x_diff)
348 upp = max(upp, x + 0.01_rp * x_diff)
349 end if
350
351 end associate
352
353
354 ! ------------------------------------------------------------------------ !
355 ! Set the the bounds and coefficients for the approximation
356 ! the move bounds (alpha and beta) are slightly more restrictive
357 ! than low and upp. This is done based on eq(3.6)--eq(3.10).
358 ! also check
359 ! https://comsolyar.com/wp-content/uploads/2020/03/gcmma.pdf
360 ! eq (2.8) and (2.9)
361
362 associate(alpha => this%alpha%x, beta => this%beta%x, &
363 xmin => xmin_eff, xmax => xmax_eff, &
364 low => this%low%x, upp => this%upp%x, x => x)
365
366 alpha = max(xmin, low + 0.1_rp*(x - low))
367 beta = min(xmax, upp - 0.1_rp*(upp - x))
368 end associate
369
370 ! ------------------------------------------------------------------------ !
371 ! Calculate p0j, q0j, pij, qij
372 ! where j = 1,2,...,n and i = 1,2,...,m (eq(2.3)-eq(2.5))
373
374 associate(p0j => this%p0j%x, q0j => this%q0j%x, &
375 pij => this%pij%x, qij => this%qij%x, &
376 low => this%low%x, upp => this%upp%x)
377
378 if (this%subsolver .eq. "dip") then
379 ! Following MMA::GenSub in the Cpp code by Niels (topopt_in_petsc,
380 ! constraintModification = false): only the objective is
381 ! regularised, by 0.5e-6/(upp - low).
382 p0j = (upp - x)**2 * (max(df0dx, 0.0_rp) + 0.001_rp*abs(df0dx) &
383 + 0.5_rp*1.0e-6_rp/(upp - low))
384 q0j = (x - low)**2 * (max(-df0dx, 0.0_rp) + 0.001_rp*abs(df0dx) &
385 + 0.5_rp*1.0e-6_rp/(upp - low))
386 do j = 1, this%n
387 do i = 1, this%m
388 pij(i, j) = (upp(j) - x(j))**2 * max(dfdx(i, j), 0.0_rp)
389 qij(i, j) = (x(j) - low(j))**2 * max(-dfdx(i, j), 0.0_rp)
390 end do
391 end do
392 else
393 ! Following mmasub by Svanberg: the objective and all constraints
394 ! are regularised by 1e-5/max(x_diff, 1e-5).
395 p0j = ( &
396 1.001_rp * max(df0dx, 0.0_rp) &
397 + 0.001_rp * max(-df0dx, 0.0_rp) &
398 + 0.00001_rp / max(x_diff, 0.00001_rp) &
399 ) * (upp - x)**2
400
401 q0j = ( &
402 0.001_rp * max(df0dx, 0.0_rp) &
403 + 1.001_rp * max(-df0dx, 0.0_rp) &
404 + 0.00001_rp / max(x_diff, 0.00001_rp)&
405 ) * (x - low)**2
406
407 do j = 1, this%n
408 do i = 1, this%m
409 pij(i, j) = ( &
410 1.001_rp * max(dfdx(i, j), 0.0_rp) &
411 + 0.001_rp * max(-dfdx(i, j), 0.0_rp) &
412 + 0.00001_rp / max(x_diff(j), 0.00001_rp) &
413 ) * (upp(j) - x(j))**2
414
415 qij(i, j) = ( &
416 0.001_rp * max(dfdx(i, j), 0.0_rp) &
417 + 1.001_rp * max(-dfdx(i, j), 0.0_rp) &
418 + 0.00001_rp / max(x_diff(j), 0.00001_rp) &
419 ) * (x(j) - low(j))**2
420 end do
421 end do
422 end if
423
424 end associate
425
426 ! ------------------------------------------------------------------------ !
427 ! Computing bi as defined in page 5
428
429 associate(bi => this%bi%x, &
430 pij => this%pij%x, qij => this%qij%x, &
431 low => this%low%x, upp => this%upp%x)
432
433 bi = 0.0_rp
434 do i = 1, this%m
435 do j = 1, this%n
436 bi(i) = bi(i) &
437 + pij(i, j) / (upp(j) - x(j)) &
438 + qij(i, j) / (x(j) - low(j))
439 end do
440 end do
441
442 call mpi_allreduce(mpi_in_place, bi, this%m, &
443 mpi_real_precision, mpi_sum, neko_comm, ierr)
444 bi = bi - fval
445
446 end associate
447 end subroutine mma_gensub_cpu
448
451 subroutine mma_subsolve_pdip_cpu(this, designx)
452 ! ------------------------------------------------------- !
453 ! Primal-dual interior point method using Newton's step !
454 ! to solve MMA sub problem. !
455 ! A Backtracking Line Search approach is used to compute !
456 ! the step size; starting with the full Newton's step !
457 ! (delta = 1) and dividing by 2 until we have a step size !
458 ! that leads to a feasible point while ensuring a !
459 ! decrease in the residue. !
460 ! ------------------------------------------------------- !
461
462 class(mma_t), intent(inout) :: this
463 real(kind=rp), dimension(this%n), intent(inout) :: designx
464 ! Note that there is a local dummy "x" in this subroutine, thus, we call
465 ! the current design "designx" instead of just "x"
466 integer :: i, j, k, iter, itto, ierr
467 real(kind=rp) :: epsi, residual_max, residual_norm, &
468 z, zeta, rez, rezeta, &
469 delz, dz, dzeta, &
470 steg, zold, zetaold, new_residual
471 real(kind=rp), dimension(this%m) :: y, lambda, s, mu, &
472 rey, relambda, remu, res, &
473 dely, dellambda, &
474 dy, dlambda, ds, dmu, &
475 yold, lambdaold, sold, muold
476 real(kind=rp), dimension(this%n) :: x, xsi, eta, &
477 rex, rexsi, reeta, &
478 delx, diagx, dx, dxsi, deta, &
479 xold, xsiold, etaold
480 real(kind=rp), dimension(4*this%m + 2) :: residual_small
481 real(kind=rp), dimension(3*this%n + 4*this%m + 2) :: residual
482 real(kind=rp), dimension(2*this%n + 4*this%m + 2) :: xx, dxx
483
484 real(kind=rp), dimension(this%m, this%n) :: gg
485 real(kind=rp), dimension(this%m+1) :: bb
486 real(kind=rp), dimension(this%m+1, this%m+1) :: aa
487 real(kind=rp), dimension(this%m * this%m) :: aa_buffer
488
489 ! using DGESV in lapack to solve
490 ! the linear system which needs the following parameters
491 integer :: info
492 integer, dimension(this%m+1) :: ipiv
493
494 ! Parameters for global communication
495 real(kind=rp) :: re_sq_norm
496 real(kind=rp) :: minimal_epsilon
497
498 ! ------------------------------------------------------------------------ !
499 ! initial value for the parameters in the subsolve based on
500 ! page 15 of "https://people.kth.se/~krille/mmagcmma.pdf"
501
502 epsi = 1.0_rp !100
503 x = 0.5_rp * (this%alpha%x + this%beta%x)
504 y = 1.0_rp
505 z = 1.0_rp
506 zeta = 1.0_rp
507 lambda = 1.0_rp
508 s = 1.0_rp
509 xsi = max(1.0_rp, 1.0_rp / (x - this%alpha%x))
510 eta = max(1.0_rp, 1.0_rp / (this%beta%x - x))
511 mu = max(1.0_rp, 0.5_rp * this%c%x)
512
513 ! ------------------------------------------------------------------------ !
514 ! Computing the minimal epsilon and choose the most conservative one
515
516 minimal_epsilon = max(0.9_rp * this%epsimin, 1.0e-12_rp)
517 call mpi_allreduce(mpi_in_place, minimal_epsilon, 1, &
518 mpi_real_precision, mpi_min, neko_comm, ierr)
519
520 ! ------------------------------------------------------------------------ !
521 ! The main loop of the primal-dual interior point method.
522
523 do while (epsi .gt. minimal_epsilon)
524
525 ! --------------------------------------------------------------------- !
526 ! Calculating residuals based on
527 ! "https://people.kth.se/~krille/mmagcmma.pdf" for the variables
528 ! x, y, z, lambda residuals based on eq(5.9a)-(5.9d), respectively.
529
530 associate(p0j => this%p0j%x, q0j => this%q0j%x, &
531 pij => this%pij%x, qij => this%qij%x, &
532 low => this%low%x, upp => this%upp%x, &
533 alpha => this%alpha%x, beta => this%beta%x, &
534 c => this%c%x, d => this%d%x, &
535 a0 => this%a0, a => this%a%x)
536
537 rex = (p0j + matmul(transpose(pij), lambda)) / (upp - x)**2 &
538 - (q0j + matmul(transpose(qij), lambda)) / (x - low)**2 &
539 - xsi + eta
540
541 rey = c + d * y - lambda - mu
542 rez = a0 - zeta - dot_product(lambda, a)
543
544 relambda = 0.0_rp
545 do i = 1, this%m
546 do j = 1, this%n
547 ! Accumulate sums for relambda (the term gi(x))
548 relambda(i) = relambda(i) &
549 + pij(i, j) / (upp(j) - x(j)) &
550 + qij(i, j) / (x(j) - low(j))
551 end do
552 end do
553
554 end associate
555
556 ! --------------------------------------------------------------------- !
557 ! Computing the norm of the residuals
558
559 ! Complete the computations of lambda residuals
560 call mpi_allreduce(mpi_in_place, relambda, this%m, &
561 mpi_real_precision, mpi_sum, neko_comm, ierr)
562 relambda = relambda - this%a%x*z - y + s - this%bi%x
563
564 rexsi = xsi * (x - this%alpha%x) - epsi
565 reeta = eta * (this%beta%x - x) - epsi
566 remu = mu * y - epsi
567 rezeta = zeta * z - epsi
568 res = lambda * s - epsi
569
570 ! Setup vectors of residuals and their norms
571 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
572 residual_small = [rey, rez, relambda, remu, rezeta, res]
573
574 residual_max = maxval(abs(residual))
575 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
576
577 call mpi_allreduce(mpi_in_place, residual_max, 1, &
578 mpi_real_precision, mpi_max, neko_comm, ierr)
579
580 call mpi_allreduce(mpi_in_place, re_sq_norm, &
581 1, mpi_real_precision, mpi_sum, neko_comm, ierr)
582
583 residual_norm = sqrt(norm2(residual_small)**2 + re_sq_norm)
584
585 ! --------------------------------------------------------------------- !
586 ! Internal loop
587
588 do iter = 1, this%max_iter
589
590 !Check the condition
591 if (residual_max .lt. epsi) exit
592
593 delx = 0.0_rp
594 do j = 1, this%n
595 do i = 1, this%m
596 delx(j) = delx(j) &
597 + this%pij%x(i,j) * lambda(i) / (this%upp%x(j) - x(j))**2 &
598 - this%qij%x(i,j) * lambda(i) / (x(j) - this%low%x(j))**2
599 end do
600 end do
601
602 delx = delx &
603 + this%p0j%x / (this%upp%x - x)**2 &
604 - this%q0j%x / (x - this%low%x)**2 &
605 - epsi / (x - this%alpha%x) &
606 + epsi / (this%beta%x - x)
607
608 dely = this%c%x + this%d%x * y - lambda - epsi / y
609 delz = this%a0 - dot_product(lambda, this%a%x) - epsi / z
610
611 ! Accumulate sums for dellambda (the term gi(x))
612 dellambda = 0.0_rp
613 do i = 1, this%m
614 do j = 1, this%n
615 dellambda(i) = dellambda(i) &
616 + this%pij%x(i, j) / (this%upp%x(j) - x(j)) &
617 + this%qij%x(i, j) / (x(j) - this%low%x(j))
618 end do
619 end do
620
621 call mpi_allreduce(mpi_in_place, dellambda, this%m, &
622 mpi_real_precision, mpi_sum, neko_comm, ierr)
623
624 dellambda = dellambda - this%a%x*z - y - this%bi%x + epsi / lambda
625
626 do i = 1, this%m
627 gg(i,:) = this%pij%x(i,:) / (this%upp%x - x)**2 &
628 - this%qij%x(i,:) / (x - this%low%x)**2
629 end do
630
631 diagx = &
632 (this%p0j%x + matmul(transpose(this%pij%x), lambda)) &
633 / (this%upp%x - x)**3 &
634 + (this%q0j%x + matmul(transpose(this%qij%x), lambda)) &
635 / (x - this%low%x)**3
636
637 diagx = 2.0_rp * diagx &
638 + xsi / (x - this%alpha%x) &
639 + eta / (this%beta%x - x)
640
641
642 !Here we only consider the case m<n in the matlab code
643 !assembling the right hand side matrix based on eq(5.20)
644 ! bb = [dellambda + dely/(this%d%x + &
645 ! (mu/y)) - matmul(GG,delx/diagx), delz ]
646
647 !--------------------------------------------------------------------!
648 ! for MPI computation of bb
649
650 bb = 0.0_rp
651 do i = 1, this%m
652 do j = 1, this%n
653 bb(i) = bb(i) + gg(i, j) * (delx(j) / diagx(j))
654 end do
655 end do
656
657 call mpi_allreduce(mpi_in_place, bb, this%m, &
658 mpi_real_precision, mpi_sum, neko_comm, ierr)
659
660 bb(1:this%m) = dellambda + dely / (this%d%x + mu / y) - bb(1:this%m)
661 bb(this%m + 1) = delz
662
663 !--------------------------------------------------------------------!
664 ! assembling the coefficients matrix AA based on eq(5.20)
665 ! AA(1:this%m,1:this%m) = &
666 ! matmul(matmul(GG,mma_diag(1/diagx)), transpose(GG))
667 ! !update diag(AA)
668 ! AA(1:this%m,1:this%m) = AA(1:this%m,1:this%m) + &
669 ! mma_diag(s/lambda + 1.0/(this%d%x + (mu/y)))
670
671 aa = 0.0_rp
672 ! Direct computation of the matrix multiplication
673 ! (for better performance)
674 do i = 1, this%m
675 do j = 1, this%m
676 ! Compute the (i, j) element of AA
677 do k = 1, this%n !this n is global
678 aa(i, j) = aa(i, j) &
679 + gg(i, k) * (1.0_rp / diagx(k)) * gg(j, k)
680 end do
681 end do
682 end do
683
684 aa_buffer = reshape(aa(1:this%m, 1:this%m), [this%m * this%m])
685
686 call mpi_allreduce(mpi_in_place, aa_buffer, &
687 this%m*this%m, mpi_real_precision, mpi_sum, neko_comm, ierr)
688
689 aa(1:this%m, 1:this%m) = reshape(aa_buffer, [this%m, this%m])
690
691 do i = 1, this%m
692 ! update the diag AA
693 aa(i, i) = aa(i, i) &
694 + s(i) / lambda(i) &
695 + 1.0_rp / (this%d%x(i) + mu(i) / y(i))
696 end do
697
698 aa(1:this%m, this%m+1) = this%a%x
699 aa(this%m+1, 1:this%m) = this%a%x
700 aa(this%m+1, this%m+1) = - zeta/z
701
702 call dgesv(this%m + 1, 1, aa, this%m + 1, ipiv, bb, this%m + 1, info)
703
704 if (info .ne. 0) then
705 call neko_error("DGESV failed to solve the linear system in " // &
706 "mma_subsolve_pdip.")
707 end if
708
709
710 dlambda = bb(1:this%m)
711 dz = bb(this%m + 1)
712
713 ! based on eq(5.19)
714 dx = - delx / diagx - matmul(transpose(gg), dlambda) / diagx
715 dy = (-dely + dlambda) / (this%d%x + mu / y)
716
717 dxsi = -xsi + (epsi - dx * xsi) / (x - this%alpha%x)
718 deta = -eta + (epsi + dx * eta) / (this%beta%x - x)
719 dmu = -mu + (epsi - mu * dy) / y
720 dzeta = -zeta + (epsi - zeta * dz) / z
721 ds = -s + (epsi - dlambda * s) / lambda
722
723 dxx = [dy, dz, dlambda, dxsi, deta, dmu, dzeta, ds]
724 xx = [y, z, lambda, xsi, eta, mu, zeta, s]
725
726 steg = 1.0_rp / maxval([ &
727 1.0_rp, &
728 -1.01_rp * dxx / xx, &
729 -1.01_rp * dx / (x - this%alpha%x), &
730 1.01_rp * dx / (this%beta%x - x) &
731 ])
732
733 ! Save the old values
734 xold = x
735 yold = y
736 zold = z
737 lambdaold = lambda
738 xsiold = xsi
739 etaold = eta
740 muold = mu
741 zetaold = zeta
742 sold = s
743
744 new_residual = 2.0_rp * residual_norm
745
746 ! Share the new_residual and steg values
747 call mpi_allreduce(mpi_in_place, steg, 1, &
748 mpi_real_precision, mpi_min, neko_comm, ierr)
749 call mpi_allreduce(mpi_in_place, new_residual, 1, &
750 mpi_real_precision, mpi_min, neko_comm, ierr)
751
752 ! The innermost loop to determine the suitable step length
753 ! using the Backtracking Line Search approach
754 itto = 0
755 do while ((new_residual .gt. residual_norm) .and. (itto .lt. 50))
756 itto = itto + 1
757
758 ! update the variables
759 x = xold + steg*dx
760 y = yold + steg*dy
761 z = zold + steg*dz
762
763 lambda = lambdaold + steg*dlambda
764 xsi = xsiold + steg*dxsi
765 eta = etaold + steg*deta
766 mu = muold + steg*dmu
767 zeta = zetaold + steg*dzeta
768 s = sold + steg*ds
769
770 ! Recompute the new_residual to see if this stepsize improves
771 ! the residue
772 rex = (this%p0j%x + matmul(transpose(this%pij%x), lambda)) &
773 / (this%upp%x - x)**2 &
774 - (this%q0j%x + matmul(transpose(this%qij%x), lambda)) &
775 / (x - this%low%x)**2 &
776 - xsi + eta
777
778 rey = this%c%x + this%d%x*y - lambda - mu
779 rez = this%a0 - zeta - dot_product(lambda, this%a%x)
780
781 ! Accumulate sums for relambda (the term gi(x))
782 relambda = 0.0_rp
783 do i = 1, this%m
784 do j = 1, this%n
785 relambda(i) = relambda(i) &
786 + this%pij%x(i, j) / (this%upp%x(j) - x(j)) &
787 + this%qij%x(i, j) / (x(j) - this%low%x(j))
788 end do
789 end do
790
791 call mpi_allreduce(mpi_in_place, relambda, this%m, &
792 mpi_real_precision, mpi_sum, neko_comm, ierr)
793
794 relambda = relambda - this%a%x*z - y + s - this%bi%x
795
796 rexsi = xsi * (x - this%alpha%x) - epsi
797 reeta = eta * (this%beta%x - x) - epsi
798 remu = mu * y - epsi
799 rezeta = zeta * z - epsi
800 res = lambda * s - epsi
801
802 ! Compute squared norms for the residuals
803 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
804 call mpi_allreduce(mpi_in_place, re_sq_norm, &
805 1, mpi_real_precision, mpi_sum, neko_comm, ierr)
806
807 residual_small = [rey, rez, relambda, remu, rezeta, res]
808 new_residual = sqrt(norm2(residual_small)**2 + re_sq_norm)
809 call mpi_allreduce(mpi_in_place, new_residual, 1, &
810 mpi_real_precision, mpi_min, neko_comm, ierr)
811
812 steg = steg / 2.0_rp
813 end do
814 steg = 2.0_rp * steg ! Correction for the final division by 2
815
816 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
817
818 ! Update the maximum and norm of the residuals
819 residual_norm = new_residual
820 residual_max = maxval(abs(residual))
821 call mpi_allreduce(mpi_in_place, residual_max, 1, &
822 mpi_real_precision, mpi_max, neko_comm, ierr)
823 end do
824
825 epsi = 0.1_rp * epsi
826 end do
827
828 ! Save the new designx
829 this%xold2%x = this%xold1%x
830 this%xold1%x = designx
831 designx = x
832
833 !update the parameters of the MMA object nesessary to compute KKT residual
834 this%y%x = y
835 this%z = z
836 this%lambda%x = lambda
837 this%zeta = zeta
838 this%xsi%x = xsi
839 this%eta%x = eta
840 this%mu%x = mu
841 this%s%x = s
842
843 end subroutine mma_subsolve_pdip_cpu
844
847 subroutine mma_subsolve_dip_cpu(this, designx)
848 ! ------------------------------------------------------------------------ !
849 ! -------------------------------Dual Solver------------------------------ !
850 ! ------------------------------------------------------------------------ !
851 ! This implementation is based on: !
852 ! https://doi.org/10.1007/s00158-012-0869-2 !
853 ! Definition of the Lagrangian function: !
854 ! (Note that the equation is slightly different with d(i)=1 and a quadratic!
855 ! term for z. This is done to ensure that we have quadratic terms for both !
856 ! y and z. The weight 0.05 of z^2 follows the Cpp code by Niels.) !
857 ! !
858 ! L(x, y, z, λ) = !
859 ! sum_{j=1}^{n} [ (p_{0j} + sum_{i=1}^{m} λ_i * p_{ij}) / (u_j - x_j)!
860 ! + (q_{0j} + sum_{i=1}^{m} λ_i * q_{ij}) / (x_j - l_j) ]!
861 ! - sum_{i=1}^{m} λ_i * b_i !
862 ! + sum_{i=1}^{m} [ (c_i - λ_i) * y_i + 0.5 * y_i^2 ] !
863 ! + (a_0 - sum_{i=1}^{m} λ_i * a_i) * z + 0.05 * z^2 !
864 ! !
865 ! Breakdown of terms: !
866 ! - Terms related to x: L_x (the first three lines of L(x, y, z, λ)) !
867 ! - Terms related to y: L_y (the fourth line of L(x, y, z, λ)) !
868 ! - Terms related to z: L_z (the last line of L(x, y, z, λ)) !
869 ! !
870 ! Optimization problem if λ is given: !
871 ! !
872 ! Minimize L(x, y, z, λ) !
873 ! subject to: α_j ≤ x_j ≤ β_j, z ≥ 0, and y_i ≥ 0 for all i, j. !
874 ! !
875 ! Since the problem is separable: !
876 ! Ψ(λ) = !
877 ! sum_{j=1}^{n} min_xj {L_x(x_j, λ) | α_j ≤ x_j ≤ β_j} !
878 ! + min_z {L_z(z, λ) | z ≥ 0} !
879 ! + sum_{i=1}^{m} min_yi {L_y(y_i, λ) | y_i ≥ 0} !
880 ! !
881 ! Maximize Ψ(λ) subject to λ_i ≥ 0 for i = 1, ..., m. !
882 ! !
883 ! ------------------------------------------------------------------------ !
884
885 class(mma_t), intent(inout) :: this
886 real(kind=rp), dimension(this%n), intent(inout) :: designx
887 ! Note that there is a local dummy "x" in this subroutine, thus, we call
888 ! the current design "designx" instead of just "x"
889 integer :: i, j, k, iter, ierr
890 real(kind=rp) :: epsi, residual_max, z, steg
891 real(kind=rp), dimension(this%m) :: y, lambda, mu, &
892 relambda, remu, dlambda, dmu, gradlambda
893 real(kind=rp), dimension(this%n) :: x, pjlambda, qjlambda
894
895 ! To compute the Hessian based on eq(13)
896 ! https://doi.org/10.1007/s00158-012-0869-2
897
898 ! inverse of a diag matrix:
899 real(kind=rp), dimension(this%n) :: ljjxinv ! [∇_x^2 Ljj]−1
900 real(kind=rp), dimension(this%m,this%n) :: hijx ! ∇_x hij
901 real(kind=rp), dimension(this%m,this%m) :: hess
902 real(kind=rp) :: hesstrace
903
904
905 ! using DGESV in lapack to solve
906 ! the linear system which needs the following parameters
907 integer :: info
908 integer, dimension(this%m+1) :: ipiv
909
910 ! Parameters for global communication
911 real(kind=rp) :: minimal_epsilon
912
913 ! ------------------------------------------------------------------------ !
914 ! initial value for the parameters in the subsolve based on
915 ! page 15 of "https://people.kth.se/~krille/mmagcmma.pdf"
916
917 epsi = 1.0_rp !100
918 ! The design is kept if no iteration is performed, as in the Cpp code
919 x = designx
920 y = 1.0_rp
921 z = 0.0_rp
922 lambda = max(1.0_rp, 0.5_rp * this%c%x)
923 mu = 1.0_rp !this parameter is eta in Niel's paper
924 ! note that mu in the paper translates to epsi in the code following the
925 ! same style as the Cpp code by Neils
926
927 ! ------------------------------------------------------------------------ !
928 ! Computing the minimal epsilon and choose the most conservative one
929
930 minimal_epsilon = this%epsimin
931 call mpi_allreduce(mpi_in_place, minimal_epsilon, 1, &
932 mpi_real_precision, mpi_min, neko_comm, ierr)
933
934 ! As in the Cpp code by Niels, the residual starts at 1 and is carried
935 ! over from one epsilon level to the next.
936 residual_max = 1.0_rp
937
938 ! ------------------------------------------------------------------------ !
939 ! The main loop of the dual interior point method.
940
941 do while (epsi .gt. minimal_epsilon)
942
943 ! --------------------------------------------------------------------- !
944 ! Compute x(λ), y(λ), z(λ) for the current λ. The residual is carried
945 ! over from the previous epsilon level (initially 1), as in
946 ! MMA::SolveDIP in the Cpp code by Niels.
947
948 associate(p0j => this%p0j%x, q0j => this%q0j%x, &
949 pij => this%pij%x, qij => this%qij%x, &
950 low => this%low%x, upp => this%upp%x, &
951 alpha => this%alpha%x, beta => this%beta%x, &
952 c => this%c%x, d => this%d%x, &
953 a0 => this%a0, a => this%a%x, &
954 bi => this%bi%x)
955 ! minimize(L_x, L_y, L_z) and compute x(λ), y(λ), z(λ) for
956 ! the current value of λ
957
958 ! Comput the value of y that minimizes L_y for the current λ
959 ! minimize (sum_{i=1}^{m} [ (c_i - λ_i) * y_i + 0.5 * y_i^2 ])
960 ! dL_y/dy =0 => y= (λ_i - c_i), ensure y>=0
961 y = max(0.0_rp, lambda - c)
962
963 ! Comput the value of z that minimizes L_z for the current λ
964 ! minimize ((a_0 - sum_{i=1}^{m} λ_i * a_i) * z + 0.05 * z^2)
965 ! ensure z>=0
966 z = max(0.0_rp, 10.0_rp * (dot_product(lambda, a) - a0))
967
968 ! Comput the value of x that minimizes L_x for the current λ
969 ! minimize( sum_{j=1}^{n} [ (p_{0j} + sum_{i=1}^{m} λ_i *
970 ! p_{ij}) / (u_j - x_j) + (q_{0j} + sum_{i=1}^{m} λ_i * q_{ij}) /
971 ! (x_j - l_j) ] - sum_{i=1}^{m} λ_i * b_i)
972 pjlambda = (p0j + matmul(transpose(pij), lambda))
973 qjlambda = (q0j + matmul(transpose(qij), lambda))
974 x = (sqrt(pjlambda) * low + sqrt(qjlambda) * upp) / &
975 (sqrt(pjlambda) + sqrt(qjlambda))
976
977 ! Ensure that x is feasible (alpha<=x<=beta)
978 x = merge(alpha, x, x .lt. alpha)
979 x = merge(beta, x, x .gt. beta)
980
981 ! ------------------------------------------------------------------- !
982 ! Internal loop, the residual of the previous epsilon level is used
983 ! for the first check, following the Cpp code by Niels.
984 do iter = 1, this%max_iter
985
986 !Check the condition
987 if (.not. (residual_max .gt. 0.9_rp * epsi)) exit
988
989 ! Compute dL(x, y, z, λ)/dλ for the updated x(λ), y(λ), z(λ)
990
991 gradlambda = matmul(pij, 1.0_rp / (upp - x)) + &
992 matmul(qij, 1.0_rp/(x - low))
993
994 ! Global comminucation for gradlambda values
995 call mpi_allreduce(mpi_in_place, gradlambda, this%m, &
996 mpi_real_precision, mpi_sum, neko_comm, ierr)
997 gradlambda = gradlambda - bi - y - a * z
998
999 ! Update gradlambda as the right hand side for Newton's method(eq10)
1000 gradlambda = - gradlambda - epsi / lambda
1001
1002 ! Computing the Hessian as in equation (13) in
1003 !! https://doi.org/10.1007/s00158-012-0869-2
1004
1005 !--------------contributions of x terms to Hess--------------------!
1006 ljjxinv= - 1.0_rp / ( (2.0_rp * pjlambda/(upp - x)**3) + &
1007 (2.0_rp * qjlambda/(x - low)**3))
1008
1009
1010 ! Remove the sensitivity for the active primal constraints
1011 ljjxinv = merge(0.0_rp, ljjxinv, x - alpha < neko_eps)
1012 ljjxinv = merge(0.0_rp, ljjxinv, beta - x < neko_eps)
1013
1014 do i = 1, this%m
1015 hijx(i,:) = pij(i,:) / (upp - x)**2 &
1016 - qij(i,:) / (x - low)**2
1017 end do
1018
1019 hess = 0.0_rp
1020 ! Direct computation of the matrix multiplication
1021 ! (for better performance)
1022 do i = 1, this%m
1023 do j = 1, this%m
1024 ! Compute the (i, j) element of AA
1025 ! this n is local, the sum over the ranks follows below
1026 do k = 1, this%n
1027 hess(i, j) = hess(i, j) &
1028 + hijx(i, k) * (ljjxinv(k)) * hijx(j, k)
1029 end do
1030 end do
1031 end do
1032
1033 call mpi_allreduce(mpi_in_place, hess, &
1034 this%m * this%m, mpi_real_precision, mpi_sum, neko_comm, ierr)
1035
1036 !---------------contributions of z terms to Hess-------------------!
1037 ! Only for inactive constraint, we consider contributions to Hess
1038 ! based on the cpp code by Niels. The factor 10 is the inverse of
1039 ! the weight 2 * 0.05 of z^2 in L_z.
1040 if (dot_product(lambda, a) .gt. 0.0_rp) then
1041 do i = 1, this%m
1042 do j = 1, this%m
1043 hess(i, j) = hess(i, j) - 10.0_rp * a(i) * a(j)
1044 end do
1045 end do
1046 end if
1047
1048 !---------------contributions of y terms to Hess-------------------!
1049 ! Only for inactive constraint, we consider contributions to Hess.
1050 do i = 1, this%m
1051 if (y(i) .gt. 0.0_rp) then
1052 hess(i, i) = hess(i, i) - 1.0_rp
1053 end if
1054 ! Based on eq(10), note the term (-\Omega \Lambda)
1055 hess(i, i) = hess(i, i) - mu(i) / lambda(i)
1056 end do
1057
1058 ! Improve the robustness by stablizing the Hess using
1059 ! Levenberg-Marquardt algorithm (heuristically)
1060 hesstrace = 0.0_rp
1061 do i=1, this%m
1062 hesstrace = hesstrace + hess(i, i)
1063 end do
1064 do i=1, this%m
1065 hess(i,i) = hess(i, i) - &
1066 max(-1.0e-4_rp*hesstrace/this%m, 1.0e-7_rp)
1067 end do
1068
1069 call dgesv(this%m , 1, hess, this%m , ipiv, &
1070 gradlambda, this%m, info)
1071
1072 if (info .ne. 0) then
1073 call neko_error("DGESV failed to solve the linear system in " // &
1074 "mma_subsolve_dip.")
1075 end if
1076 dlambda = gradlambda
1077
1078 ! based on eq(11) for delta eta
1079 dmu = -mu + epsi / lambda - dlambda * mu / lambda
1080
1081 ! Compute the stepsize and update lambda and mu (eta in the paper)
1082
1083 steg = 1.005_rp
1084 do i = 1, this%m
1085 steg = merge(-1.01_rp * dlambda(i) / lambda(i), steg, &
1086 steg < -1.01_rp * dlambda(i) / lambda(i))
1087 steg = merge(-1.01_rp * dmu(i) / mu(i), &
1088 steg, steg < -1.01_rp * dmu(i) / mu(i))
1089 end do
1090
1091 steg = 1.0_rp / steg
1092
1093 lambda = lambda + steg*dlambda
1094 mu = mu + steg*dmu
1095
1096 ! minimize(L_x, L_y, L_z) and compute x(λ), y(λ), z(λ) for
1097 ! the updated values of λ
1098
1099 ! Comput the value of y that minimizes L_y for the current λ
1100 ! minimize (sum_{i=1}^{m} [ (c_i - λ_i) * y_i + 0.5 * y_i^2 ])
1101 ! dL_y/dy =0 => y= (λ_i - c_i), ensure y>=0
1102 y = max(0.0_rp, lambda - c)
1103
1104
1105 ! Comput the value of z that minimizes L_z for the current λ
1106 ! minimize ((a_0 - sum_{i=1}^{m} λ_i * a_i) * z + 0.05 * z^2)
1107 ! ensure z>=0
1108 z = max(0.0_rp, 10.0_rp * (dot_product(lambda, a) - a0))
1109
1110 ! Comput the value of x that minimizes L_x for the current λ
1111 ! minimize( sum_{j=1}^{n} [ (p_{0j} + sum_{i=1}^{m} λ_i *
1112 ! p_{ij}) / (u_j - x_j) + (q_{0j} + sum_{i=1}^{m} λ_i * q_{ij}) /
1113 ! (x_j - l_j) ] - sum_{i=1}^{m} λ_i * b_i)
1114 pjlambda = (p0j + matmul(transpose(pij), lambda))
1115 qjlambda = (q0j + matmul(transpose(qij), lambda))
1116 x = (sqrt(pjlambda) * low + sqrt(qjlambda) * upp) / &
1117 (sqrt(pjlambda) + sqrt(qjlambda))
1118
1119 ! Ensure that x is feasible (alpha<=x<=beta)
1120 x = merge(alpha, x, x .lt. alpha)
1121 x = merge(beta, x, x .gt. beta)
1122
1123 ! Compute the residual for the lambda and mu using eq(9) and eq(15)
1124 relambda = matmul(pij, 1.0_rp / (upp - x)) + &
1125 matmul(qij, 1.0_rp / (x - low))
1126 ! Global comminucation for relambda values
1127 call mpi_allreduce(mpi_in_place, relambda, this%m, &
1128 mpi_real_precision, mpi_sum, neko_comm, ierr)
1129 relambda = relambda - bi - y - a * z + mu
1130
1131 ! Compute residual for mu (eta in the paper)
1132 remu = mu * lambda - epsi
1133
1134 residual_max = maxval(abs([relambda, remu]))
1135 call mpi_allreduce(mpi_in_place, residual_max, 1, &
1136 mpi_real_precision, mpi_max, neko_comm, ierr)
1137 end do
1138 end associate
1139
1140 epsi = 0.1_rp * epsi
1141 end do
1142
1143 ! Save the new designx
1144 this%xold2%x = this%xold1%x
1145 this%xold1%x = designx
1146 designx = x
1147
1148 !update the parameters of the MMA object nesessary to compute KKT residual
1149
1150 this%y%x = y
1151 this%z = z
1152 this%lambda%x = lambda
1153 this%mu%x = mu
1154 end subroutine mma_subsolve_dip_cpu
1155
1156end submodule mma_cpu
MMA module.
Definition mma.f90:69