Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
mma.f90
Go to the documentation of this file.
1
34
35!===========================================================================!
36! Method of Moving Asymptotes !
37! This implementation is based on the following documents: !
38! 1-https://people.kth.se/~krille/mmagcmma.pdf !
39! 2-https://people.kth.se/~krille/originalmma.pdf !
40! 2-https://comsolyar.com/wp-content/uploads/2020/03/gcmma.pdf !
41! ------------------------------------------------------------------------- !
42! !
43! This module solves the following original optimization problem: !
44! !
45! Minimize f_0(x) + a_0*z + sum( c_i*y_i + 0.5*d_i*(y_i)^2 ) !
46! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
47! xmin_j <= x_j <= xmax_j, j = 1,...,n !
48! z >= 0, y_i >= 0, i = 1,...,m !
49! !
50! by first creating the following convex approximation of the original !
51! problem: !
52! !
53! Minimize sum_{j = 1,...,n} (p0j / (upp_j-x_j) + q0j / (x_j-low_j)) + !
54! a0*z + sum_i = 1,...,m(c_i*y_i + 0.5*d_i*y_i^2) !
55! subject to sum_{j = 1,...,n} (pij / (upp_j-x_j) + qij / (x_j-low_j)) + !
56! a_i*z + y_i <= b_i, i = 1,...,m !
57! xmin_j <= alpha_j <= x_j <= beta_j <= xmax_j j = 1,...,n !
58! y_i>=0 i = 1,...,m !
59! z>=0 !
60! !
61! note that based on eq(3.5) there should be r0 in the approximated problem !
62! however since it is just a constant added to a minimization problem, it !
63! is ignored. !
64! A primal-dual algorithm is then employed to solve the approximated !
65! problem using interior point method. !
66!===========================================================================!
67
69module mma
70 ! Inclusions from Neko
71 use num_types, only: rp, dp, sp
72 use json_module, only: json_file
73 use json_utils, only: json_get_or_default
74 use vector, only: vector_t
75 use matrix, only: matrix_t
76 use comm, only: pe_rank, neko_comm, pe_size, mpi_real_precision
77 use utils, only: neko_error, filename_suffix
78 use neko_config, only: neko_bcknd_device, neko_bcknd_cuda, neko_bcknd_hip, &
79 neko_bcknd_opencl
80 use device, only: device_memcpy, host_to_device, device_to_host
81 use, intrinsic :: iso_c_binding, only: c_ptr
82 use logger, only: neko_log
83 use mpi_f08, only: mpi_sum, mpi_allreduce, mpi_integer
84 use scratch_registry, only: scratch_registry_t
85
86 implicit none
87 private
88
90 type, public :: mma_t
91 private
92 integer :: n, m, n_global, max_iter
93 real(kind=rp) :: a0, asyinit, asyincr, asydecr, epsimin, &
94 residumax, residunorm
95 real(kind=rp) :: move_limit = 0.2_rp
96 type(vector_t) :: xold1, xold2, low, upp, alpha, beta, a, c, d, xmax, xmin
97 logical :: is_initialized = .false.
98 logical :: is_updated = .false.
99 type(scratch_registry_t) :: scratch
100 character(len=:), allocatable :: subsolver, bcknd
101
102 ! Internal dummy variables for MMA
103 type(vector_t) :: p0j, q0j
104 type(matrix_t) :: pij, qij
105 type(vector_t) :: bi
106
107 !---nesessary for KKT check after updating df0dx, fval, dfdx --------
108 real(kind=rp) :: z, zeta
109 type(vector_t) :: y, lambda, s, mu
110 type(vector_t) :: xsi, eta
111 contains
113 generic, public :: init => init_from_json, init_from_components
114 procedure, public, pass(this) :: init_from_json => mma_init_from_json
115 procedure, public, pass(this) :: init_from_components => &
116 mma_init_from_components
117 procedure, public, pass(this) :: free => mma_free
118 procedure, public, pass(this) :: get_n => mma_get_n
119 procedure, public, pass(this) :: get_m => mma_get_m
120 procedure, public, pass(this) :: get_residumax => mma_get_residumax
121 procedure, public, pass(this) :: get_residunorm => mma_get_residunorm
122 procedure, public, pass(this) :: get_max_iter => mma_get_max_iter
123 procedure, public, pass(this) :: get_backend_and_subsolver => &
124 mma_get_backend_and_subsolver
125
126 generic, public :: update => update_vector, update_cpu, update_device
127 procedure, pass(this) :: update_vector => mma_update_vector
128 procedure, pass(this) :: update_cpu => mma_update_cpu
129 procedure, pass(this) :: update_device => mma_update_device
130
131 generic, public :: kkt => kkt_vector, kkt_cpu, kkt_device
132 procedure, pass(this) :: kkt_vector => mma_kkt_vector
133 procedure, pass(this) :: kkt_cpu => mma_kkt_cpu
134 procedure, pass(this) :: kkt_device => mma_kkt_device
135
136 procedure, pass(this) :: save_checkpoint => mma_save_checkpoint
137 procedure, pass(this) :: load_checkpoint => mma_load_checkpoint
138
139 ! Private utilities
140 procedure, pass(this) :: copy_from => mma_copy_from
141
142 end type mma_t
143
144 ! ========================================================================== !
145 ! Default parameters
146
147 real(kind=rp), parameter :: a0_default = 1.0_rp
148 real(kind=rp), parameter :: a_default = 0.0_rp
149 real(kind=rp), parameter :: c_default = 1000.0_rp
150 real(kind=rp), parameter :: d_default = 0.0_rp
151 real(kind=rp), parameter :: xmin_default = 0.0_rp
152 real(kind=rp), parameter :: xmax_default = 1.0_rp
153
154 real(kind=rp), parameter :: asyinit_default = 0.2_rp
155 real(kind=rp), parameter :: asyincr_default = 1.05_rp
156 real(kind=rp), parameter :: asydecr_default = 0.65_rp
157 real(kind=rp), parameter :: move_limit_default = 0.2_rp
158
159 integer, parameter :: max_iter_default = 100
160 character(len=*), parameter :: subsolver_default = "dip"
161 real(kind=rp), parameter :: scale_default = 1.0_rp
162 logical, parameter :: auto_scale_default = .false.
163
164 ! ========================================================================== !
165 ! interface for cpu backend module subroutines
166
167 interface
168 ! CPU update function, runs one iteration of MMA
169 module subroutine mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
170 class(mma_t), intent(inout) :: this
171 integer, intent(in) :: iter
172 real(kind=rp), dimension(this%n), intent(inout) :: x
173 real(kind=rp), dimension(this%n), intent(in) :: df0dx
174 real(kind=rp), dimension(this%m), intent(in) :: fval
175 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
176 end subroutine mma_update_cpu
177
178 ! CPU KKT check for convergence
179 module subroutine mma_kkt_cpu(this, x, df0dx, fval, dfdx)
180 class(mma_t), intent(inout) :: this
181 real(kind=rp), dimension(this%n), intent(in) :: x
182 real(kind=rp), dimension(this%n), intent(in) :: df0dx
183 real(kind=rp), dimension(this%m), intent(in) :: fval
184 real(kind=rp), dimension(this%m, this%n), intent(in) :: dfdx
185 end subroutine mma_kkt_cpu
186
187 ! ========================================================================== !
188 ! interface for device backend module subroutines
189
190 ! Device update function, runs one iteration of MMA
191 module subroutine mma_update_device(this, iter, x, df0dx, fval, dfdx)
192 class(mma_t), intent(inout) :: this
193 integer, intent(in) :: iter
194 type(c_ptr), intent(inout) :: x
195 type(c_ptr), intent(in) :: df0dx, fval, dfdx
196 end subroutine mma_update_device
197
199 module subroutine mma_kkt_device(this, x, df0dx, fval, dfdx)
200 class(mma_t), intent(inout) :: this
201 type(c_ptr), intent(in) :: x, df0dx, fval, dfdx
202 end subroutine mma_kkt_device
203
204 end interface
205
206 ! ========================================================================== !
207 ! Interface for IO routines
208
209 interface
210 module subroutine mma_save_checkpoint_hdf5(object, filename, overwrite)
211 class(mma_t), intent(inout) :: object
212 character(len=*), intent(in) :: filename
213 logical, intent(in), optional :: overwrite
214 end subroutine mma_save_checkpoint_hdf5
215
216 module subroutine mma_load_checkpoint_hdf5(object, filename)
217 class(mma_t), intent(inout) :: object
218 character(len=*), intent(in) :: filename
219 end subroutine mma_load_checkpoint_hdf5
220 end interface
221
222contains
223
224 ! ========================================================================== !
225 ! Initializers and destructors
226
228 subroutine mma_init_from_json(this, x, n, m, json, scale, auto_scale)
229 ! ----------------------------------------------------- !
230 ! Initializing the mma object and all the parameters !
231 ! required for MMA method. (a_i, c_i, d_i, ...) !
232 ! x: the design varaibles(DV), n: number of DV, !
233 ! m: number of constraints !
234 ! !
235 ! Note that residumax & residunorm of the KKT conditions!
236 ! are initialized with huge(0.0_rp). This is done to !
237 ! avoid unnecessary extra computation of KKT norms for !
238 ! the initial design. !
239 ! ----------------------------------------------------- !
240 class(mma_t), intent(inout) :: this
241 integer, intent(in) :: n, m
242 type(vector_t), intent(in) :: x
243
244 type(json_file), intent(inout) :: json
245
246 ! Read the scaling info for fval and dfdx from json
247 real(kind=rp), intent(out) :: scale
248 logical, intent(out) :: auto_scale
249 ! -------------------------------------------------------------------!
250 ! Internal parameters for MMA !
251 ! Minimize f_0(x) + a_0*z + sum( c_i*y_i + 0.5*d_i*(y_i)^2 ) !
252 ! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
253 ! xmin_j <= x_j <= xmax_j, j = 1,...,n !
254 ! z >= 0, y_i >= 0, i = 1,...,m !
255 ! -------------------------------------------------------------------!
256 real(kind=rp), dimension(n) :: xmax, xmin
257 real(kind=rp), dimension(m) :: a, c, d
258 character(len=:), allocatable :: subsolver, bcknd, bcknd_default
259
260 ! For reading the values from json and then set the value for the arrays
261 real(kind=rp) :: a0 , xmax_const, xmin_const, a_const, c_const, d_const
262 real(kind=rp) :: move_limit
263
264 integer :: max_iter, n_global, ierr
265 real(kind=rp) :: epsimin, asyinit, asyincr, asydecr
266
267 call mpi_allreduce(n, n_global, 1, mpi_integer, &
268 mpi_sum, neko_comm, ierr)
269
270 ! Assign default values for the backend based on the NEKO_BCKND_DEVICE
271 if (neko_bcknd_device .eq. 1) then
272 bcknd_default = "device"
273 else
274 bcknd_default = "cpu"
275 end if
276
277 ! ------------------------------------------------------------------------ !
278 ! Assign defaults if nothing is parsed
279 ! based on the Cpp Code by Niels
280 call json_get_or_default(json, 'mma.epsimin', epsimin, &
281 1.0e-9_rp * sqrt(real(m + n_global, rp)))
282 call json_get_or_default(json, 'mma.max_iter', max_iter, max_iter_default)
283
284 ! Following parameters are set based on eq.3.8:--------
285 call json_get_or_default(json, 'mma.asyinit', asyinit, asyinit_default)
286 call json_get_or_default(json, 'mma.asyincr', asyincr, asyincr_default)
287 call json_get_or_default(json, 'mma.asydecr', asydecr, asydecr_default)
288
289 call json_get_or_default(json, 'mma.backend', bcknd, bcknd_default)
290 call json_get_or_default(json, 'mma.subsolver', subsolver, subsolver_default)
291
292 call json_get_or_default(json, 'mma.xmin', xmin_const, xmin_default)
293 call json_get_or_default(json, 'mma.xmax', xmax_const, xmax_default)
294 call json_get_or_default(json, 'mma.a0', a0, a0_default)
295 call json_get_or_default(json, 'mma.a', a_const, a_default)
296 call json_get_or_default(json, 'mma.c', c_const, c_default)
297 call json_get_or_default(json, 'mma.d', d_const, d_default)
298 call json_get_or_default(json, 'mma.move_limit', move_limit, move_limit_default)
299
300 call json_get_or_default(json, 'mma.scale', scale, scale_default)
301 call json_get_or_default(json, 'mma.auto_scale', auto_scale, auto_scale_default)
302
303 ! Initialize the MMA object with the parsed parameters
304 a = a_const
305 c = c_const
306 d = d_const
307 xmin = xmin_const
308 xmax = xmax_const
309
310 ! ------------------------------------------------------------------------ !
311 ! Initialize the MMA object with the parameters read from json
312
313 call this%init(x, n, m, a0, a, c, d, xmin, xmax, &
314 max_iter, epsimin, asyinit, asyincr, asydecr, bcknd, subsolver, &
315 move_limit)
316
317 end subroutine mma_init_from_json
318
320 subroutine mma_free(this)
321 class(mma_t), intent(inout) :: this
322 ! Deallocate the internal vectors
323 call this%xold1%free()
324 call this%xold2%free()
325 call this%alpha%free()
326 call this%beta%free()
327 call this%a%free()
328 call this%c%free()
329 call this%d%free()
330 call this%low%free()
331 call this%upp%free()
332 call this%xmax%free()
333 call this%xmin%free()
334 call this%p0j%free()
335 call this%q0j%free()
336 call this%bi%free()
337 call this%y%free()
338 call this%lambda%free()
339 call this%s%free()
340 call this%mu%free()
341 call this%xsi%free()
342 call this%eta%free()
343
344 ! Deallocate the internal dummy matrices
345 call this%pij%free()
346 call this%qij%free()
347 call this%scratch%free()
348
349 this%is_initialized = .false.
350 this%is_updated = .false.
351 end subroutine mma_free
352
354 subroutine mma_init_from_components(this, x, n, m, a0, a, c, d, xmin, xmax, &
355 max_iter, epsimin, asyinit, asyincr, asydecr, bcknd, subsolver, &
356 move_limit)
357 ! ----------------------------------------------------- !
358 ! Initializing the mma object and all the parameters !
359 ! required for MMA method. (a_i, c_i, d_i, ...) !
360 ! x: the design varaibles(DV), n: number of DV, !
361 ! m: number of constraints !
362 ! !
363 ! Note that residumax & residunorm of the KKT conditions!
364 ! are initialized with huge(0.0_rp). This is done to !
365 ! avoid unnecessary extra computation of KKT norms for !
366 ! the initial design. !
367 ! ----------------------------------------------------- !
368 class(mma_t), intent(inout) :: this
369 integer, intent(in) :: n, m
370 type(vector_t), intent(in) :: x
371 ! -------------------------------------------------------------------!
372 ! Internal parameters for MMA !
373 ! Minimize f_0(x) + a_0*z + sum( c_i*y_i + 0.5*d_i*(y_i)^2 ) !
374 ! subject to f_i(x) - a_i*z - y_i <= 0, i = 1,...,m !
375 ! xmin_j <= x_j <= xmax_j, j = 1,...,n !
376 ! z >= 0, y_i >= 0, i = 1,...,m !
377 ! -------------------------------------------------------------------!
378 real(kind=rp), intent(in), dimension(n) :: xmax, xmin
379 real(kind=rp), intent(in), dimension(m) :: a, c, d
380 real(kind=rp), intent(in) :: a0
381 integer, intent(in), optional :: max_iter
382 real(kind=rp), intent(in), optional :: epsimin, asyinit, asyincr, asydecr
383 real(kind=rp), intent(in), optional :: move_limit
384 character(len=*), intent(in), optional :: bcknd, subsolver
385 character(len=256) :: log_msg
386 integer :: i, ierr
387
388 call this%free()
389 call this%scratch%init()
390
391 this%n = n
392 this%m = m
393
394 call this%xold1%init(n)
395 call this%xold2%init(n)
396 this%xold1 = x
397 this%xold2 = x
398
399 call this%alpha%init(n)
400 call this%beta%init(n)
401
402 call this%a%init(m)
403 call this%c%init(m)
404 call this%d%init(m)
405 call this%low%init(n)
406 call this%upp%init(n)
407 call this%xmax%init(n)
408 call this%xmin%init(n)
409
410 !internal dummy variables for MMA
411 call this%p0j%init(n)
412 call this%q0j%init(n)
413 call this%pij%init(m, n)
414 call this%qij%init(m, n)
415 call this%bi%init(m)
416
417 ! Necessary for KKT check after updating df0dx, fval, dfdx
418 call this%y%init(m)
419 call this%lambda%init(m)
420 call this%s%init(m)
421 call this%mu%init(m)
422 call this%xsi%init(n)
423 call this%eta%init(n)
424 this%z = 0.0_rp
425 this%zeta = 0.0_rp
426
427 this%a0 = a0
428 this%a%x = a
429 this%c%x = c
430 this%d%x = d
431
432 ! Set the bounds for the design variable based on the problem
433 this%xmax%x = xmax
434 this%xmin%x = xmin
435
436 if (neko_bcknd_device .eq. 1) then
437 call this%a%copy_from(host_to_device, sync = .false.)
438 call this%c%copy_from(host_to_device, sync = .false.)
439 call this%d%copy_from(host_to_device, sync = .false.)
440 call this%xmax%copy_from(host_to_device, sync = .false.)
441 call this%xmin%copy_from(host_to_device, sync = .true.)
442 end if
443
444 ! Set KKT norms to a large number for the initial design
445 this%residumax = huge(0.0_rp)
446 this%residunorm = huge(0.0_rp)
447
448 ! Sync parameters across MPI
449 call mpi_allreduce(n, this%n_global, 1, mpi_integer, mpi_sum, neko_comm, &
450 ierr)
451
452 ! ------------------------------------------------------------------------ !
453 ! Assign defaults if nothing is parsed
454
455 ! Based on the Cpp Code by Niels
456 if (.not. present(max_iter)) this%max_iter = max_iter_default
457 if (.not. present(epsimin)) then
458 this%epsimin = 1.0e-9_rp * sqrt(real(this%m + this%n_global, rp))
459 end if
460
461 ! Following parameters are set based on eq.3.8
462 if (.not. present(asyinit)) this%asyinit = asyinit_default
463 if (.not. present(asyincr)) this%asyincr = asyincr_default
464 if (.not. present(asydecr)) this%asydecr = asydecr_default
465 if (.not. present(move_limit)) this%move_limit = move_limit_default
466
467 ! Set default backend based on NEKO_BCKND_DEVICE
468 if (.not. present(bcknd) .and. neko_bcknd_device .eq. 0) then
469 this%bcknd = "cpu"
470 else if (.not. present(bcknd)) then
471 this%bcknd = "device"
472 end if
473
474 ! Set default subsolver
475 if (.not. present(subsolver)) this%subsolver = subsolver_default
476
477 ! Assign values from inputs when present
478 if (present(max_iter)) this%max_iter = max_iter
479 if (present(epsimin)) this%epsimin = epsimin
480 if (present(asyinit)) this%asyinit = asyinit
481 if (present(asyincr)) this%asyincr = asyincr
482 if (present(asydecr)) this%asydecr = asydecr
483 if (present(move_limit)) this%move_limit = move_limit
484 if (present(bcknd)) this%bcknd = bcknd
485 if (present(subsolver)) this%subsolver = subsolver
486
487 ! The backend selects the implementation of the update and the KKT check
488 if (this%bcknd .ne. "cpu" .and. this%bcknd .ne. "device") then
489 call neko_error("MMA: unknown backend '" // trim(this%bcknd) // &
490 "', expected 'cpu' or 'device'.")
491 end if
492
493 ! The subsolvers reduce epsilon towards epsimin by factors of 10
494 if (.not. (this%epsimin .gt. 0.0_rp)) then
495 call neko_error("MMA: epsimin must be positive.")
496 end if
497
498 call neko_log%section('MMA Parameters')
499
500 write(log_msg, '(A10,1X,A)') 'backend ', trim(this%bcknd)
501 call neko_log%message(log_msg)
502 write(log_msg, '(A10,1X,A)') 'subsolver ', trim(this%subsolver)
503 call neko_log%message(log_msg)
504
505 write(log_msg, '(A10,1X,I0)') 'n ', this%n_global
506 call neko_log%message(log_msg)
507 write(log_msg, '(A10,1X,I0)') 'm ', this%m
508 call neko_log%message(log_msg)
509 write(log_msg, '(A10,1X,I0)') 'max_iter ', this%max_iter
510 call neko_log%message(log_msg)
511
512 write(log_msg, '(A10,1X,E11.5)') 'epsimin ', this%epsimin
513 call neko_log%message(log_msg)
514
515 write(log_msg, '(A10,1X,E11.5)') 'asyinit ', this%asyinit
516 call neko_log%message(log_msg)
517 write(log_msg, '(A10,1X,E11.5)') 'asyincr ', this%asyincr
518 call neko_log%message(log_msg)
519 write(log_msg, '(A10,1X,E11.5)') 'asydecr ', this%asydecr
520 call neko_log%message(log_msg)
521 write(log_msg, '(A10,1X,E11.5)') 'a0 ', this%a0
522 call neko_log%message(log_msg)
523 write(log_msg, '(A10,1X,E11.5)') 'movelimit ', this%move_limit
524 call neko_log%message(log_msg)
525
526 call neko_log%message('Parameters a')
527 do i = 1, this%m
528 write(log_msg, '(3X,A,I2,A,E11.5)') 'a(', i, ') = ', this%a%x(i)
529 call neko_log%message(log_msg)
530 end do
531 call neko_log%message('Parameters c')
532 do i = 1, this%m
533 write(log_msg, '(3X,A,I2,A,E11.5)') 'c(', i, ') = ', this%c%x(i)
534 call neko_log%message(log_msg)
535 end do
536 call neko_log%message('Parameters d')
537 do i = 1, this%m
538 write(log_msg, '(3X,A,I2,A,E11.5)') 'd(', i, ') = ', this%d%x(i)
539 call neko_log%message(log_msg)
540 end do
541
542 call neko_log%end_section()
543
544 ! The object is correctly initialized
545 this%is_initialized = .true.
546 end subroutine mma_init_from_components
547
548 ! ========================================================================== !
549 ! Updator and KKT checker
550
552 subroutine mma_update_vector(this, iter, x, df0dx, fval, dfdx)
553 class(mma_t), intent(inout) :: this
554 integer, intent(in) :: iter
555 type(vector_t), intent(inout) :: x
556 type(vector_t), intent(inout) :: df0dx, fval
557 type(matrix_t), intent(inout) :: dfdx
558
559 ! Select backend type
560 select case (this%bcknd)
561 case ("cpu")
562 if (neko_bcknd_device .eq. 1) then
563 call x%copy_from(device_to_host, sync = .false.)
564 call df0dx%copy_from(device_to_host, sync = .false.)
565 call fval%copy_from(device_to_host, sync = .false.)
566 call dfdx%copy_from(device_to_host, sync = .true.)
567 end if
568
569 call mma_update_cpu(this, iter, x%x, df0dx%x, fval%x, dfdx%x)
570
571 if (neko_bcknd_device .eq. 1) then
572 call x%copy_from(host_to_device, sync = .true.)
573 end if
574
575 case ("device")
576 call mma_update_device(this, iter, x%x_d, df0dx%x_d, fval%x_d, dfdx%x_d)
577 case default
578 call neko_error('mma_update_vector: Unknown backend: ' // &
579 trim(this%bcknd))
580 end select
581
582 end subroutine mma_update_vector
583
585 subroutine mma_kkt_vector(this, x, df0dx, fval, dfdx)
586 class(mma_t), intent(inout) :: this
587 type(vector_t), intent(inout) :: x, df0dx, fval
588 type(matrix_t), intent(inout) :: dfdx
589
590 ! Select backend type
591 select case (this%bcknd )
592 case ("cpu")
593 if (neko_bcknd_device .eq. 1) then
594 call device_memcpy(x%x, x%x_d, this%n, device_to_host, &
595 sync = .false.)
596 call device_memcpy(df0dx%x, df0dx%x_d, this%n, device_to_host, &
597 sync = .false.)
598 call device_memcpy(fval%x, fval%x_d, this%m, device_to_host, &
599 sync = .false.)
600 call device_memcpy(dfdx%x, dfdx%x_d, this%m * this%n, device_to_host,&
601 sync = .true.)
602 end if
603
604 call mma_kkt_cpu(this, x%x, df0dx%x, fval%x, dfdx%x)
605 case ("device")
606 call mma_kkt_device(this, x%x_d, df0dx%x_d, fval%x_d, dfdx%x_d)
607 case default
608 call neko_error('mma_KKT_vector: Unknown backend: ' // &
609 trim(this%bcknd))
610 end select
611 end subroutine mma_kkt_vector
612
613 ! ========================================================================== !
614 ! IO Functions
615
620 subroutine mma_save_checkpoint(this, filename, overwrite)
621 class(mma_t), intent(inout) :: this
622 character(len=*), intent(in) :: filename
623 logical, intent(in), optional :: overwrite
624 character(len=12) :: file_ext
625
626 ! Get the file extension
627 call filename_suffix(filename, file_ext)
628
629 select case (trim(file_ext))
630 case ('h5', 'hdf5', 'hf5')
631 call mma_save_checkpoint_hdf5(this, filename, overwrite)
632 case default
633 call neko_error('mma_save_checkpoint: Unsupported file format: ' // &
634 trim(file_ext))
635 end select
636
637 end subroutine mma_save_checkpoint
638
642 subroutine mma_load_checkpoint(this, filename)
643 class(mma_t), intent(inout) :: this
644 character(len=*), intent(in) :: filename
645 character(len=12) :: file_ext
646
647 ! Get the file extension
648 call filename_suffix(filename, file_ext)
649
650 select case (trim(file_ext))
651 case ('h5', 'hdf5', 'hf5')
652 call mma_load_checkpoint_hdf5(this, filename)
653 case default
654 call neko_error('mma_load_checkpoint: Unsupported file format: ' // &
655 trim(file_ext))
656 end select
657 end subroutine mma_load_checkpoint
658
659 ! ========================================================================== !
660 ! Getters and setters
661
663 pure function mma_get_n(this) result(n)
664 class(mma_t), intent(in) :: this
665 integer :: n
666 n = this%n
667 end function mma_get_n
668
670 pure function mma_get_m(this) result(m)
671 class(mma_t), intent(in) :: this
672 integer :: m
673 m = this%m
674 end function mma_get_m
675
677 pure function mma_get_residumax(this) result(residumax)
678 class(mma_t), intent(in) :: this
679 real(kind=rp) :: residumax
680 residumax = this%residumax
681 end function mma_get_residumax
682
684 pure function mma_get_residunorm(this) result(residunorm)
685 class(mma_t), intent(in) :: this
686 real(kind=rp) :: residunorm
687 residunorm = this%residunorm
688 end function mma_get_residunorm
689
691 pure function mma_get_max_iter(this) result(max_iter_value)
692 class(mma_t), intent(in) :: this
693 integer :: max_iter_value
694 max_iter_value = this%max_iter
695 end function mma_get_max_iter
696
698 pure function mma_get_backend_and_subsolver(this) result(backend_subsolver)
699 class(mma_t), intent(in) :: this
700 character(len=:), allocatable :: backend_subsolver
701 character(len=:), allocatable :: backend
702
703 if (neko_bcknd_cuda .eq. 1) then
704 backend = "cuda"
705 else if (neko_bcknd_hip .eq. 1) then
706 backend = "hip"
707 else if (neko_bcknd_opencl .eq. 1) then
708 backend = "opencl"
709 else
710 backend = "cpu"
711 end if
712
713 backend_subsolver = 'backend:' // trim(backend) // ', subsolver:' // &
714 trim(this%subsolver)
715 end function mma_get_backend_and_subsolver
716
717 ! ========================================================================== !
718 ! Private utilities
719
721 subroutine mma_copy_from(this, direction, sync)
722 class(mma_t), intent(inout) :: this
723 integer, intent(in) :: direction
724 logical, intent(in) :: sync
725
726 call this%xold1%copy_from(direction, sync = .false.)
727 call this%xold2%copy_from(direction, sync = .false.)
728 call this%xmax%copy_from(direction, sync = .false.)
729 call this%xmin%copy_from(direction, sync = .false.)
730
731 call this%low%copy_from(direction, sync = .false.)
732 call this%upp%copy_from(direction, sync = .false.)
733
734 call this%a%copy_from(direction, sync = .false.)
735 call this%c%copy_from(direction, sync = .false.)
736 call this%d%copy_from(direction, sync = .false.)
737 call this%y%copy_from(direction, sync = .false.)
738 call this%s%copy_from(direction, sync = .false.)
739
740 call this%p0j%copy_from(direction, sync = .false.)
741 call this%q0j%copy_from(direction, sync = .false.)
742 call this%pij%copy_from(direction, sync = .false.)
743 call this%qij%copy_from(direction, sync = .false.)
744 call this%bi%copy_from(direction, sync = .false.)
745
746 call this%alpha%copy_from(direction, sync = .false.)
747 call this%beta%copy_from(direction, sync = .false.)
748 call this%lambda%copy_from(direction, sync = .false.)
749 call this%mu%copy_from(direction, sync = .false.)
750 call this%xsi%copy_from(direction, sync = .false.)
751 call this%eta%copy_from(direction, sync = sync)
752
753 end subroutine mma_copy_from
754
755 ! ========================================================================== !
756 ! Dummy implementations for module procedures
757
758#if !HAVE_HDF5
759 module subroutine mma_save_checkpoint_hdf5(object, filename, overwrite)
760 class(mma_t), intent(inout) :: object
761 character(len=*), intent(in) :: filename
762 logical, intent(in), optional :: overwrite
763 call neko_error('mma: HDF5 support not enabled rebuild with HAVE_HDF5')
764 end subroutine mma_save_checkpoint_hdf5
765
766 module subroutine mma_load_checkpoint_hdf5(object, filename)
767 class(mma_t), intent(inout) :: object
768 character(len=*), intent(in) :: filename
769 call neko_error('mma: HDF5 support not enabled rebuild with HAVE_HDF5')
770 end subroutine mma_load_checkpoint_hdf5
771#endif
772
773end module mma
MMA module.
Definition mma.f90:69
MMA type.
Definition mma.f90:90