Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mma_cpu.f90
Go to the documentation of this file.
1! Copyright (c) 2025, The Neko-TOP Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32
33submodule(mma) mma_cpu
34 use lapack_interfaces, only: dgesv
35 use mpi_f08, only: mpi_in_place
36 implicit none
37
38contains
39
40 module subroutine mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
41 ! ----------------------------------------------------- !
42 ! Update the design variable x by solving the convex !
43 ! approximation of the problem. !
44 ! !
45 ! This subroutine is called in each iteration of the !
46 ! optimization loop !
47 ! ----------------------------------------------------- !
48 class(mma_t), intent(inout) :: this
49 integer, intent(in) :: iter
50 real(kind=rp), dimension(this%n), intent(inout) :: x
51 type(vector_t) :: df0dx, fval
52 type(matrix_t) :: dfdx
53
54 if (.not. this%is_initialized) then
55 write(stderr, *) "The MMA object is not initialized."
56 error stop
57 end if
58
59 ! generate a convex approximation of the problem
60 call mma_gensub_cpu(this, iter, x, df0dx, fval, dfdx)
61
62 !solve the approximation problem using interior point method
63 call mma_subsolve_dpip_cpu(this, x)
64
65 this%is_updated = .true.
66 end subroutine mma_update_cpu
67
69 module subroutine mma_kkt_cpu(this, x, df0dx, fval, dfdx)
70 ! ----------------------------------------------------- !
71 ! Compute the KKT condition right hand side for a given !
72 ! designx x and set the max and norm values of the !
73 ! residue of KKT system to this%residumax and !
74 ! this%residunorm. !
75 ! !
76 ! The left hand sides of the KKT conditions are computed!
77 ! for the following nonlinear programming problem: !
78 ! Minimize f_0(x) + a_0*z + !
79 ! sum( c_i*y_i + 0.5*d_i*(y_i)^2 )!
80 ! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
81 ! xmax_j <= x_j <= xmin_j, j = 1,...,n !
82 ! z >= 0, y_i >= 0, i = 1,...,m !
83 ! !
84 ! !
85 ! Note that before calling this function, the function !
86 ! values (f0val, fval, dfdx, ...) should be updated !
87 ! using the new x values. !
88 ! ----------------------------------------------------- !
89 class(mma_t), intent(inout) :: this
90 real(kind=rp), dimension(this%n), intent(in) :: x
91 type(vector_t), intent(in) :: df0dx, fval
92 type(matrix_t), intent(in) :: dfdx
93
94 real(kind=rp) :: rez, rezeta
95 real(kind=rp), dimension(this%m) :: rey, relambda, remu, res
96 real(kind=rp), dimension(this%n) :: rex, rexsi, reeta
97 real(kind=rp), dimension(3*this%n+4*this%m+2) :: residual
98
99 real(kind=rp), dimension(4*this%m+2) :: residual_small
100 integer :: ierr
101 real(kind=rp) :: re_sq_norm
102
103
104 associate(fval => fval%x, dfdx => dfdx%x, df0dx => df0dx%x)
105
106 rex = df0dx + matmul(transpose(dfdx), this%lambda%x) &
107 - this%xsi%x + this%eta%x
108 rey = this%c%x + this%d%x*this%y%x - this%lambda%x - this%mu%x
109 rez = this%a0 - this%zeta - dot_product(this%lambda%x, this%a%x)
110
111 relambda = fval - this%a%x * this%z - this%y%x + this%s%x
112 rexsi = this%xsi%x * (x - this%xmin%x)
113 reeta = this%eta%x * (this%xmax%x - x)
114 remu = this%mu%x * this%y%x
115 rezeta = this%zeta * this%z
116 res = this%lambda%x * this%s%x
117
118 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
119 residual_small = [rey, rez, relambda, remu, rezeta, res]
120
121 this%residumax = maxval(abs(residual))
122 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
123
124 call mpi_allreduce(mpi_in_place, this%residumax, 1, &
125 mpi_real_precision, mpi_max, neko_comm, ierr)
126
127 call mpi_allreduce(mpi_in_place, re_sq_norm, 1, &
128 mpi_real_precision, mpi_sum, neko_comm, ierr)
129
130 this%residunorm = sqrt(norm2(residual_small)**2 + re_sq_norm)
131 end associate
132 end subroutine mma_kkt_cpu
133
134 !============================================================================!
135 ! private internal subroutines
136
138 subroutine mma_gensub_cpu(this, iter, xdesign, df0dx, fval, dfdx)
139 ! ----------------------------------------------------- !
140 ! Generate the approximation sub problem by computing !
141 ! the lower and upper asymtotes and the other necessary !
142 ! parameters (alpha, beta, p0j, q0j, pij, qij, ...). !
143 ! ----------------------------------------------------- !
144 class(mma_t), intent(inout) :: this
145 real(kind=rp), dimension(this%n), intent(in) :: xdesign
146 type(vector_t) :: df0dx, fval
147 type(matrix_t) :: dfdx
148 integer, intent(in) :: iter
149 integer :: i, j, ierr
150 real(kind=rp), dimension(this%n) :: x_diff
151 real(kind=rp) :: asy_factor
152
153 x_diff = this%xmax%x - this%xmin%x
154
155 ! ------------------------------------------------------------------------ !
156 ! Setup the current asymptotes
157 associate(low => this%low%x, upp => this%upp%x, &
158 x_1 => this%xold1%x, x_2 => this%xold2%x, x => xdesign)
159
160 if (iter .lt. 3) then
161 ! Initialize the lower and upper asymptotes
162 low = x - this%asyinit * x_diff
163 upp = x + this%asyinit * x_diff
164 else
165 do j = 1, this%n
166 if ((x(j) - x_1(j)) * (x_1(j) - x_2(j)) .lt. 0.0_rp) then
167 asy_factor = this%asydecr
168 else if ((x(j) - x_1(j)) * (x_1(j) - x_2(j)) .gt. 0.0_rp) then
169 asy_factor = this%asyincr
170 else
171 asy_factor = 1.0_rp
172 end if
173
174 low(j) = x(j) - asy_factor * (x_1(j) - low(j))
175 upp(j) = x(j) + asy_factor * (upp(j) - x_1(j))
176 end do
177
178
179 ! Setting a minimum and maximum for the low and upp
180 ! asymptotes (eq3.9)
181 low = max(low, x - 10.0_rp * x_diff)
182 low = min(low, x - 0.01_rp * x_diff)
183
184 upp = min(upp, x + 10.0_rp * x_diff)
185 upp = max(upp, x + 0.01_rp * x_diff)
186 end if
187
188 end associate
189
190
191 ! ------------------------------------------------------------------------ !
192 ! Set the the bounds and coefficients for the approximation
193 ! the move bounds (alpha and beta) are slightly more restrictive
194 ! than low and upp. This is done based on eq(3.6)--eq(3.10).
195 ! also check
196 ! https://comsolyar.com/wp-content/uploads/2020/03/gcmma.pdf
197 ! eq (2.8) and (2.9)
198
199 associate(alpha => this%alpha%x, beta => this%beta%x, &
200 xmin => this%xmin%x, xmax => this%xmax%x, &
201 low => this%low%x, upp => this%upp%x, x => xdesign)
202
203 alpha = max(xmin, low + 0.1_rp*(x - low), x - 0.5_rp*x_diff)
204 beta = min(xmax, upp - 0.1_rp*(upp - x), x + 0.5_rp*x_diff)
205
206 end associate
207
208 ! ------------------------------------------------------------------------ !
209 ! Calculate p0j, q0j, pij, qij
210 ! where j = 1,2,...,n and i = 1,2,...,m (eq(2.3)-eq(2.5))
211
212 associate(p0j => this%p0j%x, q0j => this%q0j%x, &
213 pij => this%pij%x, qij => this%qij%x, &
214 low => this%low%x, upp => this%upp%x, x => xdesign, &
215 dfdx => dfdx%x, df0dx => df0dx%x)
216
217 p0j = ( &
218 1.001_rp * max(df0dx, 0.0_rp) &
219 + 0.001_rp * max(-df0dx, 0.0_rp) &
220 + 0.00001_rp / max(x_diff, 0.00001_rp) &
221 ) * (upp - x)**2
222
223 q0j = ( &
224 0.001_rp * max(df0dx, 0.0_rp) &
225 + 1.001_rp * max(-df0dx, 0.0_rp) &
226 + 0.00001_rp / max(x_diff, 0.00001_rp)&
227 ) * (x - low)**2
228
229 do j = 1, this%n
230 do i = 1, this%m
231 pij(i, j) = ( &
232 1.001_rp * max(dfdx(i, j), 0.0_rp) &
233 + 0.001_rp * max(-dfdx(i, j), 0.0_rp) &
234 + 0.00001_rp / max(x_diff(j), 0.00001_rp) &
235 ) * (upp(j) - x(j))**2
236
237 qij(i, j) = ( &
238 0.001_rp * max(dfdx(i, j), 0.0_rp) &
239 + 1.001_rp * max(-dfdx(i, j), 0.0_rp) &
240 + 0.00001_rp / max(x_diff(j), 0.00001_rp) &
241 ) * (x(j) - low(j))**2
242 end do
243 end do
244
245 end associate
246
247 ! ------------------------------------------------------------------------ !
248 ! Computing bi as defined in page 5
249
250 associate(bi => this%bi%x, &
251 pij => this%pij%x, qij => this%qij%x, &
252 low => this%low%x, upp => this%upp%x, x => xdesign)
253
254 bi = 0.0_rp
255 do i = 1, this%m
256 do j = 1, this%n
257 bi(i) = bi(i) &
258 + pij(i, j) / (upp(j) - x(j)) &
259 + qij(i, j) / (x(j) - low(j))
260 end do
261 end do
262
263 call mpi_allreduce(mpi_in_place, bi, this%m, &
264 mpi_real_precision, mpi_sum, neko_comm, ierr)
265 bi = bi - fval%x
266
267 end associate
268
269 end subroutine mma_gensub_cpu
270
272 subroutine mma_subsolve_dpip_cpu(this, designx)
273 ! ------------------------------------------------------- !
274 ! Dual-primal interior point method using Newton's step !
275 ! to solve MMA sub problem. !
276 ! A Backtracking Line Search approach is used to compute !
277 ! the step size; starting with the full Newton's step !
278 ! (delta = 1) and dividing by 2 until we have a step size !
279 ! that leads to a feasible point while ensuring a !
280 ! decrease in the residue. !
281 ! ------------------------------------------------------- !
282
283 class(mma_t), intent(inout) :: this
284 real(kind=rp), dimension(this%n), intent(inout) :: designx
285 ! Note that there is a local dummy "x" in this subroutine, thus, we call
286 ! the current design "designx" instead of just "x"
287 integer :: i, j, k, iter, itto, ierr
288 real(kind=rp) :: epsi, residual_max, residual_norm, &
289 z, zeta, rez, rezeta, &
290 delz, dz, dzeta, &
291 steg, zold, zetaold, new_residual
292 real(kind=rp), dimension(this%m) :: y, lambda, s, mu, &
293 rey, relambda, remu, res, &
294 dely, dellambda, &
295 dy, dlambda, ds, dmu, &
296 yold, lambdaold, sold, muold
297 real(kind=rp), dimension(this%n) :: x, xsi, eta, &
298 rex, rexsi, reeta, &
299 delx, diagx, dx, dxsi, deta, &
300 xold, xsiold, etaold
301 real(kind=rp), dimension(4*this%m + 2) :: residual_small
302 real(kind=rp), dimension(3*this%n + 4*this%m + 2) :: residual
303 real(kind=rp), dimension(2*this%n + 4*this%m + 2) :: xx, dxx
304
305 real(kind=rp), dimension(this%m, this%n) :: gg
306 real(kind=rp), dimension(this%m+1) :: bb
307 real(kind=rp), dimension(this%m+1, this%m+1) :: aa
308
309 ! using DGESV in lapack to solve
310 ! the linear system which needs the following parameters
311 integer :: info
312 integer, dimension(this%m+1) :: ipiv
313
314 ! Parameters for global communication
315 real(kind=rp) :: re_sq_norm
316 real(kind=rp) :: minimal_epsilon
317
318 integer :: nglobal
319
320 ! ------------------------------------------------------------------------ !
321 ! initial value for the parameters in the subsolve based on
322 ! page 15 of "https://people.kth.se/~krille/mmagcmma.pdf"
323
324 epsi = 1.0_rp !100
325 x = 0.5_rp * (this%alpha%x + this%beta%x)
326 y = 1.0_rp
327 z = 1.0_rp
328 zeta = 1.0_rp
329 lambda = 1.0_rp
330 s = 1.0_rp
331 xsi = max(1.0_rp, 1.0_rp / (x - this%alpha%x))
332 eta = max(1.0_rp, 1.0_rp / (this%beta%x - x))
333 mu = max(1.0_rp, 0.5_rp * this%c%x)
334
335 call mpi_allreduce(this%n, nglobal, 1, &
336 mpi_integer, mpi_sum, neko_comm, ierr)
337
338 ! ------------------------------------------------------------------------ !
339 ! Computing the minimal epsilon and choose the most conservative one
340
341 minimal_epsilon = max(0.9_rp * this%epsimin, 1.0e-12_rp)
342 call mpi_allreduce(mpi_in_place, minimal_epsilon, 1, &
343 mpi_real_precision, mpi_min, neko_comm, ierr)
344
345 ! ------------------------------------------------------------------------ !
346 ! The main loop of the dual-primal interior point method.
347
348 do while (epsi .gt. minimal_epsilon)
349
350 ! --------------------------------------------------------------------- !
351 ! Calculating residuals based on
352 ! "https://people.kth.se/~krille/mmagcmma.pdf" for the variables
353 ! x, y, z, lambda residuals based on eq(5.9a)-(5.9d), respectively.
354
355 associate(p0j => this%p0j%x, q0j => this%q0j%x, &
356 pij => this%pij%x, qij => this%qij%x, &
357 low => this%low%x, upp => this%upp%x, &
358 alpha => this%alpha%x, beta => this%beta%x, &
359 c => this%c%x, d => this%d%x, &
360 a0 => this%a0, a => this%a%x, &
361 bi => this%bi%x)
362
363 rex = (p0j + matmul(transpose(pij), lambda)) / (upp - x)**2 &
364 - (q0j + matmul(transpose(qij), lambda)) / (x - low)**2 &
365 - xsi + eta
366
367 rey = c + d * y - lambda - mu
368 rez = a0 - zeta - dot_product(lambda, a)
369
370 relambda = 0.0_rp
371 do i = 1, this%m
372 do j = 1, this%n
373 ! Accumulate sums for relambda (the term gi(x))
374 relambda(i) = relambda(i) &
375 + pij(i, j) / (upp(j) - x(j)) &
376 + qij(i, j) / (x(j) - low(j))
377 end do
378 end do
379
380 end associate
381
382 ! --------------------------------------------------------------------- !
383 ! Computing the norm of the residuals
384
385 ! Complete the computations of lambda residuals
386 call mpi_allreduce(mpi_in_place, relambda, this%m, &
387 mpi_real_precision, mpi_sum, neko_comm, ierr)
388 relambda = relambda - this%a%x*z - y + s - this%bi%x
389
390 rexsi = xsi * (x - this%alpha%x) - epsi
391 reeta = eta * (this%beta%x - x) - epsi
392 remu = mu * y - epsi
393 rezeta = zeta * z - epsi
394 res = lambda * s - epsi
395
396 ! Setup vectors of residuals and their norms
397 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
398 residual_small = [rey, rez, relambda, remu, rezeta, res]
399
400 residual_max = maxval(abs(residual))
401 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
402
403 call mpi_allreduce(mpi_in_place, residual_max, 1, &
404 mpi_real_precision, mpi_max, neko_comm, ierr)
405
406 call mpi_allreduce(mpi_in_place, re_sq_norm, &
407 1, mpi_real_precision, mpi_sum, neko_comm, ierr)
408
409 residual_norm = sqrt(norm2(residual_small)**2 + re_sq_norm)
410
411 ! --------------------------------------------------------------------- !
412 ! Internal loop
413
414 do iter = 1, this%max_iter
415
416 !Check the condition
417 if (residual_max .lt. epsi) exit
418
419 delx = 0.0_rp
420 do j = 1, this%n
421 do i = 1, this%m
422 delx(j) = delx(j) &
423 + this%pij%x(i,j) * lambda(i) / (this%upp%x(j) - x(j))**2 &
424 - this%qij%x(i,j) * lambda(i) / (x(j) - this%low%x(j))**2
425 end do
426 end do
427
428 delx = delx &
429 + this%p0j%x / (this%upp%x - x)**2 &
430 - this%q0j%x / (x - this%low%x)**2 &
431 - epsi / (x - this%alpha%x) &
432 + epsi / (this%beta%x - x)
433
434 dely = this%c%x + this%d%x * y - lambda - epsi / y
435 delz = this%a0 - dot_product(lambda, this%a%x) - epsi / z
436
437 ! Accumulate sums for dellambda (the term gi(x))
438 dellambda = 0.0_rp
439 do i = 1, this%m
440 do j = 1, this%n
441 dellambda(i) = dellambda(i) &
442 + this%pij%x(i, j) / (this%upp%x(j) - x(j)) &
443 + this%qij%x(i, j) / (x(j) - this%low%x(j))
444 end do
445 end do
446
447 call mpi_allreduce(mpi_in_place, dellambda, this%m, &
448 mpi_real_precision, mpi_sum, neko_comm, ierr)
449
450 dellambda = dellambda - this%a%x*z - y - this%bi%x + epsi / lambda
451
452 do i = 1, this%m
453 gg(i,:) = this%pij%x(i,:) / (this%upp%x - x)**2 &
454 - this%qij%x(i,:) / (x - this%low%x)**2
455 end do
456
457 diagx = &
458 (this%p0j%x + matmul(transpose(this%pij%x), lambda)) &
459 / (this%upp%x - x)**3 &
460 + (this%q0j%x + matmul(transpose(this%qij%x), lambda)) &
461 / (x - this%low%x)**3
462
463 diagx = 2.0_rp * diagx &
464 + xsi / (x - this%alpha%x) &
465 + eta / (this%beta%x - x)
466
467
468 !Here we only consider the case m<n in the matlab code
469 !assembling the right hand side matrix based on eq(5.20)
470 ! bb = [dellambda + dely/(this%d%x + &
471 ! (mu/y)) - matmul(GG,delx/diagx), delz ]
472
473 !--------------------------------------------------------------------!
474 ! for MPI computation of bb
475
476 bb = 0.0_rp
477 do i = 1, this%m
478 do j = 1, this%n
479 bb(i) = bb(i) + gg(i, j) * (delx(j) / diagx(j))
480 end do
481 end do
482
483 call mpi_allreduce(mpi_in_place, bb(1:this%m), this%m, &
484 mpi_real_precision, mpi_sum, neko_comm, ierr)
485
486 bb(1:this%m) = dellambda + dely / (this%d%x + mu / y) - bb(1:this%m)
487 bb(this%m + 1) = delz
488
489 !--------------------------------------------------------------------!
490 ! assembling the coefficients matrix AA based on eq(5.20)
491 ! AA(1:this%m,1:this%m) = &
492 ! matmul(matmul(GG,mma_diag(1/diagx)), transpose(GG))
493 ! !update diag(AA)
494 ! AA(1:this%m,1:this%m) = AA(1:this%m,1:this%m) + &
495 ! mma_diag(s/lambda + 1.0/(this%d%x + (mu/y)))
496
497 aa = 0.0_rp
498 ! Direct computation of the matrix multiplication
499 ! (for better performance)
500 do i = 1, this%m
501 do j = 1, this%m
502 ! Compute the (i, j) element of AA
503 do k = 1, this%n !this n is global
504 aa(i, j) = aa(i, j) &
505 + gg(i, k) * (1.0_rp / diagx(k)) * gg(j, k)
506 end do
507 end do
508 end do
509
510 call mpi_allreduce(mpi_in_place, aa(1:this%m, 1:this%m), &
511 this%m*this%m, mpi_real_precision, mpi_sum, neko_comm, ierr)
512
513 do i = 1, this%m
514 ! update the diag AA
515 aa(i, i) = aa(i, i) &
516 + s(i) / lambda(i) &
517 + 1.0_rp / (this%d%x(i) + mu(i) / y(i))
518 end do
519
520 aa(1:this%m, this%m+1) = this%a%x
521 aa(this%m+1, 1:this%m) = this%a%x
522 aa(this%m+1, this%m+1) = - zeta/z
523
524 call dgesv(this%m + 1, 1, aa, this%m + 1, ipiv, bb, this%m + 1, info)
525
526 if (info .ne. 0) then
527 write(stderr, *) "DGESV failed to solve the linear system in MMA."
528 write(stderr, *) "Please check mma_subsolve_dpip in mma.f90"
529 error stop
530 end if
531
532 dlambda = bb(1:this%m)
533 dz = bb(this%m + 1)
534
535 ! based on eq(5.19)
536 dx = - delx / diagx - matmul(transpose(gg), dlambda) / diagx
537 dy = (-dely + dlambda) / (this%d%x + mu / y)
538
539 dxsi = -xsi + (epsi - dx * xsi) / (x - this%alpha%x)
540 deta = -eta + (epsi + dx * eta) / (this%beta%x - x)
541 dmu = -mu + (epsi - mu * dy) / y
542 dzeta = -zeta + (epsi - zeta * dz) / z
543 ds = -s + (epsi - dlambda * s) / lambda
544
545 dxx = [dy, dz, dlambda, dxsi, deta, dmu, dzeta, ds]
546 xx = [y, z, lambda, xsi, eta, mu, zeta, s]
547
548 steg = 1.0_rp / maxval([ &
549 1.0_rp, &
550 -1.01_rp * dxx / xx, &
551 -1.01_rp * dx / (x - this%alpha%x), &
552 1.01_rp * dx / (this%beta%x - x) &
553 ])
554
555 ! Save the old values
556 xold = x
557 yold = y
558 zold = z
559 lambdaold = lambda
560 xsiold = xsi
561 etaold = eta
562 muold = mu
563 zetaold = zeta
564 sold = s
565
566 ! The innermost loop to determine the suitable step length
567 ! using the Backtracking Line Search approach
568 new_residual = 2.0_rp * residual_norm
569
570 ! Share the new_residual and steg values
571 call mpi_allreduce(mpi_in_place, steg, 1, &
572 mpi_real_precision, mpi_min, neko_comm, ierr)
573 call mpi_allreduce(mpi_in_place, new_residual, 1, &
574 mpi_real_precision, mpi_min, neko_comm, ierr)
575
576 itto = 0
577 do while ((new_residual .gt. residual_norm) .and. (itto .lt. 50))
578 itto = itto + 1
579
580 ! update the variables
581 x = xold + steg*dx
582 y = yold + steg*dy
583 z = zold + steg*dz
584 lambda = lambdaold + steg*dlambda
585 xsi = xsiold + steg*dxsi
586 eta = etaold + steg*deta
587 mu = muold + steg*dmu
588 zeta = zetaold + steg*dzeta
589 s = sold + steg*ds
590
591 ! Recompute the new_residual to see if this stepsize improves
592 ! the residue
593 rex = (this%p0j%x + matmul(transpose(this%pij%x), lambda)) &
594 / (this%upp%x - x)**2 &
595 - (this%q0j%x + matmul(transpose(this%qij%x), lambda)) &
596 / (x - this%low%x)**2 &
597 - xsi + eta
598
599 rey = this%c%x + this%d%x*y - lambda - mu
600 rez = this%a0 - zeta - dot_product(lambda, this%a%x)
601
602 ! Accumulate sums for relambda (the term gi(x))
603 relambda = 0.0_rp
604 do i = 1, this%m
605 do j = 1, this%n
606 relambda(i) = relambda(i) &
607 + this%pij%x(i, j) / (this%upp%x(j) - x(j)) &
608 + this%qij%x(i, j) / (x(j) - this%low%x(j))
609 end do
610 end do
611
612 call mpi_allreduce(mpi_in_place, relambda, this%m, &
613 mpi_real_precision, mpi_sum, neko_comm, ierr)
614
615 relambda = relambda - this%a%x*z - y + s - this%bi%x
616
617 rexsi = xsi * (x - this%alpha%x) - epsi
618 reeta = eta * (this%beta%x - x) - epsi
619 remu = mu * y - epsi
620 rezeta = zeta * z - epsi
621 res = lambda * s - epsi
622
623 residual_small = [rey, rez, relambda, remu, rezeta, res]
624
625 re_sq_norm = norm2(rex)**2 + norm2(rexsi)**2 + norm2(reeta)**2
626 call mpi_allreduce(mpi_in_place, re_sq_norm, &
627 1, mpi_real_precision, mpi_sum, neko_comm, ierr)
628
629 new_residual = sqrt(norm2(residual_small)**2 + re_sq_norm)
630
631 steg = steg / 2.0_rp
632 end do
633 steg = 2.0_rp * steg ! Correction for the final division by 2
634
635 residual = [rex, rey, rez, relambda, rexsi, reeta, remu, rezeta, res]
636
637 ! Update the maximum and norm of the residuals
638 residual_norm = new_residual
639 residual_max = maxval(abs(residual))
640 call mpi_allreduce(mpi_in_place, residual_max, 1, &
641 mpi_real_precision, mpi_max, neko_comm, ierr)
642 end do
643
644 epsi = 0.1_rp * epsi
645 end do
646
647 ! Save the new designx
648 this%xold2%x = this%xold1%x
649 this%xold1%x = designx
650 designx = x
651
652 !update the parameters of the MMA object nesessary to compute KKT residual
653 this%y%x = y
654 this%z = z
655 this%lambda%x = lambda
656 this%zeta = zeta
657 this%xsi%x = xsi
658 this%eta%x = eta
659 this%mu%x = mu
660 this%s%x = s
661
662 end subroutine mma_subsolve_dpip_cpu
663
664
665end submodule mma_cpu
Definition mma.f90:34