36 use num_types,
only: rp
37 use json_module,
only: json_file
38 use json_utils,
only: json_get_or_default
39 use vector,
only: vector_t
40 use matrix,
only: matrix_t
41 use mpi_f08,
only: mpi_allreduce, mpi_integer, mpi_sum, mpi_comm_world, &
43 use comm,
only: pe_rank, neko_comm, mpi_real_precision
44 use,
intrinsic :: iso_fortran_env, only: stderr => error_unit
45 use utils,
only: neko_error
46 use device,
only: device_memcpy, host_to_device
53 integer :: n, m, max_iter
54 real(kind=rp) :: a0, f0val, asyinit, asyincr, asydecr, epsimin, &
56 type(vector_t) :: xold1, xold2, low, upp, alpha, beta, a, c, d, xmax, xmin
57 logical :: is_initialized = .false.
58 logical :: is_updated = .false.
59 character(len=:),
allocatable :: bcknd
62 type(vector_t) :: p0j, q0j
63 type(matrix_t) :: pij, qij
67 real(kind=rp) :: z, zeta
68 type(vector_t) :: y, lambda, s, mu
69 type(vector_t) :: xsi, eta
72 generic,
public :: init => init_from_json, init_from_components
74 procedure,
public, pass(this) :: init_from_components => &
76 procedure,
public, pass(this) :: free =>
mma_free
83 procedure,
public, pass(this) :: kkt =>
mma_kkt
93 module subroutine mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
94 class(mma_t),
intent(inout) :: this
95 integer,
intent(in) :: iter
96 real(kind=rp),
dimension(this%n),
intent(inout) :: x
97 type(vector_t) :: df0dx, fval
98 type(matrix_t) :: dfdx
99 end subroutine mma_update_cpu
102 module subroutine mma_kkt_cpu(this, x, df0dx, fval, dfdx)
103 class(mma_t),
intent(inout) :: this
104 real(kind=rp),
dimension(this%n),
intent(in) :: x
105 type(vector_t),
intent(in) :: df0dx, fval
106 type(matrix_t),
intent(in) :: dfdx
107 end subroutine mma_kkt_cpu
113 module subroutine mma_update_device(this, iter, x, df0dx, fval, dfdx)
114 class(mma_t),
intent(inout) :: this
115 integer,
intent(in) :: iter
116 real(kind=rp),
dimension(this%n),
intent(inout) :: x
117 type(vector_t) :: df0dx, fval
118 type(matrix_t) :: dfdx
119 end subroutine mma_update_device
122 module subroutine mma_kkt_device(this, x, df0dx, fval, dfdx)
123 class(mma_t),
intent(inout) :: this
124 real(kind=rp),
dimension(this%n),
intent(in) :: x
125 type(vector_t),
intent(in) :: df0dx, fval
126 type(matrix_t),
intent(in) :: dfdx
127 end subroutine mma_kkt_device
134 subroutine mma_init_from_json(this, x, n, m, json, scale, auto_scale)
146 class(mma_t),
intent(inout) :: this
147 integer,
intent(in) :: n, m
148 real(kind=rp),
intent(in),
dimension(n) :: x
150 type(json_file),
intent(inout) :: json
153 real(kind=rp),
intent(out) :: scale
154 logical,
intent(out) :: auto_scale
162 real(kind=rp),
dimension(n) :: xmax, xmin
163 real(kind=rp),
dimension(m) :: a, c, d
164 character(len=:),
allocatable :: bcknd
167 real(kind=rp) :: a0 , xmax_const, xmin_const, a_const, c_const, d_const
169 integer :: max_iter, n_global, ierr
170 real(kind=rp) :: epsimin, asyinit, asyincr, asydecr
172 call mpi_allreduce(n, n_global, 1, mpi_integer, &
173 mpi_sum, mpi_comm_world, ierr)
178 call json_get_or_default(json,
'mma.epsimin', epsimin, &
179 1.0e-9_rp * sqrt(real(m + n_global, rp)))
180 call json_get_or_default(json,
'mma.max_iter', max_iter, 100)
183 call json_get_or_default(json,
'mma.asyinit', asyinit, 0.5_rp)
184 call json_get_or_default(json,
'mma.asyincr', asyincr, 1.2_rp)
185 call json_get_or_default(json,
'mma.asydecr', asydecr, 0.7_rp)
187 call json_get_or_default(json,
'mma.backend', bcknd,
'cpu')
189 call json_get_or_default(json,
'mma.xmin', xmin_const, 0.0_rp)
190 call json_get_or_default(json,
'mma.xmax', xmax_const, 1.0_rp)
191 call json_get_or_default(json,
'mma.a0', a0, 1.0_rp)
192 call json_get_or_default(json,
'mma.a', a_const, 0.0_rp)
193 call json_get_or_default(json,
'mma.c', c_const, 100.0_rp)
194 call json_get_or_default(json,
'mma.d', d_const, 0.0_rp)
196 call json_get_or_default(json,
'mma.scale', scale, 10.0_rp)
197 call json_get_or_default(json,
'mma.auto_scale', auto_scale, .true.)
199 call json_get_or_default(json,
'mma.epsimin', epsimin, 1.0e-9_rp)
207 if (pe_rank .eq. 0)
then
208 print *,
"Initializing MMA backend to >>> ", bcknd
215 call this%init(x, n, m, a0, a, c, d, xmin, xmax, &
216 max_iter, epsimin, asyinit, asyincr, asydecr, bcknd)
218 end subroutine mma_init_from_json
221 subroutine mma_free(this)
222 class(mma_t),
intent(inout) :: this
224 call this%xold1%free()
225 call this%xold2%free()
226 call this%alpha%free()
227 call this%beta%free()
233 call this%xmax%free()
234 call this%xmin%free()
239 call this%lambda%free()
249 this%is_initialized = .false.
250 this%is_updated = .false.
251 end subroutine mma_free
254 subroutine mma_init_from_components(this, x, n, m, a0, a, c, d, xmin, xmax, &
255 max_iter, epsimin, asyinit, asyincr, asydecr, bcknd)
267 class(mma_t),
intent(inout) :: this
268 integer,
intent(in) :: n, m
269 real(kind=rp),
intent(in),
dimension(n) :: x
277 real(kind=rp),
intent(in),
dimension(n) :: xmax, xmin
278 real(kind=rp),
intent(in),
dimension(m) :: a, c, d
279 real(kind=rp),
intent(in) :: a0
280 integer,
intent(in),
optional :: max_iter
281 real(kind=rp),
intent(in),
optional :: epsimin, asyinit, asyincr, asydecr
282 character(len=:),
intent(in),
allocatable :: bcknd
289 call this%xold1%init(n)
290 call this%xold2%init(n)
294 call this%alpha%init(n)
295 call this%beta%init(n)
300 call this%low%init(n)
301 call this%upp%init(n)
302 call this%xmax%init(n)
303 call this%xmin%init(n)
306 call this%p0j%init(n)
307 call this%q0j%init(n)
308 call this%pij%init(m, n)
309 call this%qij%init(m, n)
314 call this%lambda%init(m)
317 call this%xsi%init(n)
318 call this%eta%init(n)
329 this%low%x(:) = minval(x)
330 this%upp%x(:) = maxval(x)
333 this%residumax = huge(0.0_rp)
334 this%residunorm = huge(0.0_rp)
339 if (pe_rank == 0)
then
340 print *,
"MMA initialized with CPU backend!"
344 call device_memcpy(this%xold1%x, this%xold1%x_d, this%n, &
345 host_to_device, sync = .false.)
346 call device_memcpy(this%xold1%x, this%xold2%x_d, this%n, &
347 host_to_device, sync = .false.)
348 call device_memcpy(this%a%x, this%a%x_d, this%m, host_to_device, &
350 call device_memcpy(this%c%x, this%c%x_d, this%m, host_to_device, &
352 call device_memcpy(this%d%x, this%d%x_d, this%m, host_to_device, &
354 call device_memcpy(this%xmax%x, this%xmax%x_d, this%n, host_to_device, &
356 call device_memcpy(this%xmin%x, this%xmin%x_d, this%n, host_to_device, &
358 if (pe_rank == 0)
then
359 print *,
"MMA initialized with CUDA backend!"
362 call neko_error(
'Unknown backend in mma_init_attributes')
369 if (.not.
present(epsimin)) this%epsimin = 1.0e-9_rp * sqrt(real(m + n, rp))
370 if (.not.
present(max_iter)) this%max_iter = 100
373 if (.not.
present(asyinit)) this%asyinit = 0.5_rp
374 if (.not.
present(asyincr)) this%asyincr = 1.2_rp
375 if (.not.
present(asydecr)) this%asydecr = 0.7_rp
378 if (
present(max_iter)) this%max_iter = max_iter
379 if (
present(epsimin)) this%epsimin = epsimin
380 if (
present(asyinit)) this%asyinit = asyinit
381 if (
present(asyincr)) this%asyincr = asyincr
382 if (
present(asydecr)) this%asydecr = asydecr
385 if (pe_rank .eq. 0)
then
386 print *,
"MMA is initialized with a0 = ", a0,
", a = ", a,
", c = ", c, &
387 ", d = ", d,
"epsimin = ", this%epsimin
390 this%is_initialized = .true.
391 end subroutine mma_init_from_components
394 subroutine mma_update(this, iter, x, df0dx, fval, dfdx)
395 class(mma_t),
intent(inout) :: this
396 integer,
intent(in) :: iter
397 real(kind=rp),
dimension(this%n),
intent(inout) :: x
398 type(vector_t) :: df0dx, fval
399 type(matrix_t) :: dfdx
402 select case (this%bcknd )
404 call mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
406 call mma_update_device(this, iter, x, df0dx, fval, dfdx)
408 call mma_update_cpu(this, iter, x, df0dx, fval, dfdx)
410 end subroutine mma_update
413 subroutine mma_kkt(this, x, df0dx, fval, dfdx)
414 class(mma_t),
intent(inout) :: this
415 real(kind=rp),
dimension(this%n),
intent(in) :: x
416 type(vector_t),
intent(in) :: df0dx, fval
417 type(matrix_t),
intent(in) :: dfdx
420 select case (this%bcknd )
422 call mma_kkt_cpu(this, x, df0dx, fval, dfdx)
424 call mma_kkt_device(this, x, df0dx, fval, dfdx)
426 call mma_kkt_cpu(this,x, df0dx, fval, dfdx)
428 end subroutine mma_kkt
434 pure function mma_get_n(this)
result(n)
435 class(mma_t),
intent(in) :: this
438 end function mma_get_n
441 pure function mma_get_m(this)
result(m)
442 class(mma_t),
intent(in) :: this
445 end function mma_get_m
448 pure function mma_get_residumax(this)
result(residumax)
449 class(mma_t),
intent(in) :: this
450 real(kind=rp) :: residumax
451 residumax = this%residumax
452 end function mma_get_residumax
455 pure function mma_get_residunorm(this)
result(residunorm)
456 class(mma_t),
intent(in) :: this
457 real(kind=rp) :: residunorm
458 residunorm = this%residunorm
459 end function mma_get_residunorm
462 pure function mma_get_max_iter(this)
result(max_iter_value)
463 class(mma_t),
intent(in) :: this
464 integer :: max_iter_value
465 max_iter_value = this%max_iter
466 end function mma_get_max_iter
pure real(kind=rp) function mma_get_residumax(this)
Get L^{inf} norm (Max Norm) of the KKT conditions.
subroutine mma_init_from_json(this, x, n, m, json, scale, auto_scale)
CPU update function, runs one iteration of MMA.
subroutine mma_kkt(this, x, df0dx, fval, dfdx)
Call the KKT ckeck function based on the backend.
subroutine mma_init_from_components(this, x, n, m, a0, a, c, d, xmin, xmax, max_iter, epsimin, asyinit, asyincr, asydecr, bcknd)
Initialize the mma object based on the attributes from the json file.
pure integer function mma_get_m(this)
Get the number of constriants.
pure integer function mma_get_max_iter(this)
Get the maximum number of iterations for the mma_subsolve inner loop.
pure real(kind=rp) function mma_get_residunorm(this)
Get L^{2} norm (Euclidean Norm) of the KKT conditions.
pure integer function mma_get_n(this)
Get the number of design variables (nloc)
subroutine mma_update(this, iter, x, df0dx, fval, dfdx)
Call the update function based on the backend.
subroutine mma_free(this)
Deallocate mma object.