39 use num_types,
only: rp
40 use utils,
only: neko_error
41 use json_utils,
only: json_get, json_get_or_default
49 use json_module,
only: json_file
50 use vector,
only: vector_t
51 use matrix,
only: matrix_t
52 use math,
only: abscmp
53 use profiler,
only: profiler_start_region, profiler_end_region
54 use logger,
only: neko_log
55 use csv_file,
only: csv_file_t
56 use vector_math,
only: vector_cmult
57 use matrix_math,
only: matrix_cmult
58 use device,
only: device_memcpy, device_to_host
59 use scratch_registry,
only: neko_scratch_registry
68 type(mma_t),
private :: mma
76 real(kind=rp),
private :: scale = 1.0_rp
77 real(kind=rp),
private :: scaling_factor = 1.0_rp
78 logical,
private :: auto_scale = .false.
81 logical,
private :: unconstrained_problem = .false.
84 logical,
private :: enable_output = .true.
85 type(csv_file_t),
private :: csv_log
89 generic :: init => init_from_json, init_from_components
90 procedure, pass(this) :: init_from_json => mma_optimizer_init_from_json
91 procedure, pass(this) :: init_from_components => &
92 mma_optimizer_init_from_components
94 procedure, pass(this) :: initialize => mma_optimizer_initialize
95 procedure, pass(this) :: step => mma_optimizer_step
96 procedure, pass(this) :: validate => mma_optimizer_validate
97 procedure, pass(this) :: write => mma_optimizer_write
98 procedure, pass(this) :: free => mma_optimizer_free
108 subroutine mma_optimizer_init_from_json(this, parameters, problem, design, &
111 type(json_file),
intent(inout) :: parameters
112 class(
problem_t),
intent(inout) :: problem
113 class(
design_t),
intent(in) :: design
117 type(json_file) :: solver_parameters
118 logical :: enable_output
119 integer :: max_iterations
120 real(kind=rp) :: tolerance
123 call json_get(parameters,
'optimization.solver', solver_parameters)
124 call json_get_or_default(solver_parameters,
'max_iterations', &
126 call json_get_or_default(solver_parameters,
'tolerance', &
127 tolerance, 1.0e-3_rp)
128 call json_get_or_default(solver_parameters,
'enable_output', &
129 enable_output, .true.)
131 call this%init_from_components(
problem,
design, max_iterations, tolerance, &
132 enable_output, solver_parameters, simulation)
134 end subroutine mma_optimizer_init_from_json
137 subroutine mma_optimizer_init_from_components(this, problem, design, &
138 max_iterations, tolerance, enable_output, solver_parameters, simulation)
140 class(
problem_t),
intent(inout) :: problem
141 class(
design_t),
intent(in) :: design
142 integer,
intent(in) :: max_iterations
143 real(kind=rp),
intent(in) :: tolerance
144 logical,
intent(in) :: enable_output
145 type(json_file),
intent(inout),
optional :: solver_parameters
149 type(vector_t),
pointer :: x
151 character(len=1024) :: header
154 call neko_log%section(
'Optimizer Initialization')
157 this%unconstrained_problem =
problem%get_n_constraints() .eq. 0
158 if (this%unconstrained_problem)
then
159 call neko_log%message(
'Unconstrained problem detected. ' // &
160 'Adding a dummy constraint to enable MMA optimization.')
163 select type (con => dummy_con)
165 call con%init_from_attributes(
design)
168 call problem%add_constraint(dummy_con)
169 if (
allocated(dummy_con))
deallocate(dummy_con)
174 call neko_scratch_registry%request(x, ind,
design%size(), .false.)
177 call this%mma%init(x,
design%size(),
problem%get_n_constraints(), &
178 solver_parameters, this%scale, this%auto_scale)
180 call neko_scratch_registry%relinquish(ind)
183 this%enable_output = enable_output
184 this%scaling_factor = this%scale
187 if (this%enable_output)
then
188 call this%csv_log%init(
'optimization_data.csv')
189 header =
'iter, ' // trim(
problem%get_log_header()) // &
190 ', KKTmax, KKTnorm2, scaling factor, ' // &
191 trim(this%mma%get_backend_and_subsolver())
193 call this%csv_log%set_header(trim(header))
196 call this%init_base(max_iterations, tolerance)
198 call neko_log%end_section()
200 end subroutine mma_optimizer_init_from_components
203 subroutine mma_optimizer_free(this)
207 call this%free_base()
209 end subroutine mma_optimizer_free
215 subroutine mma_optimizer_initialize(this, problem, design, simulation)
217 class(
problem_t),
intent(inout) :: problem
218 class(
design_t),
intent(inout) :: design
219 type(
simulation_t),
optional,
intent(inout) :: simulation
221 type(vector_t),
pointer :: x
222 type(vector_t),
pointer :: constraint_value
223 type(vector_t),
pointer :: objective_sensitivities
224 type(matrix_t),
pointer :: constraint_sensitivities
225 integer :: n_design, n_constraint, indices(4)
228 n_constraint =
problem%get_n_constraints()
231 call neko_scratch_registry%request(x, indices(1), n_design, .false.)
232 call neko_scratch_registry%request(constraint_value, indices(2), &
233 n_constraint, .false.)
234 call neko_scratch_registry%request(objective_sensitivities, indices(3), &
236 call neko_scratch_registry%request(constraint_sensitivities, indices(4), &
237 n_constraint, n_design, .false.)
245 call problem%get_constraint_values(constraint_value)
247 select type (des =>
design)
249 call des%get_sensitivity(objective_sensitivities)
251 call problem%get_objective_sensitivities(objective_sensitivities)
254 call problem%get_constraint_sensitivities(constraint_sensitivities)
257 call this%mma%KKT(x, objective_sensitivities, &
258 constraint_value, constraint_sensitivities)
260 call neko_scratch_registry%relinquish(indices)
261 end subroutine mma_optimizer_initialize
264 function mma_optimizer_step(this, iter, problem, design, simulation) &
267 integer,
intent(in) :: iter
268 class(
problem_t),
intent(inout) :: problem
269 class(
design_t),
intent(inout) :: design
270 type(
simulation_t),
optional,
intent(inout) :: simulation
272 type(vector_t),
pointer :: x
273 type(vector_t),
pointer :: constraint_value
274 type(vector_t),
pointer :: objective_sensitivities
275 type(matrix_t),
pointer :: constraint_sensitivities
276 integer :: n_design, n_constraint, indices(4)
281 n_constraint =
problem%get_n_constraints()
284 call neko_scratch_registry%request(x, indices(1), n_design, .false.)
285 call neko_scratch_registry%request(constraint_value, indices(2), &
286 n_constraint, .false.)
287 call neko_scratch_registry%request(objective_sensitivities, indices(3), &
289 call neko_scratch_registry%request(constraint_sensitivities, indices(4), &
290 n_constraint, n_design, .false.)
294 call problem%get_constraint_values(constraint_value)
296 select type (des =>
design)
298 call des%get_sensitivity(objective_sensitivities)
300 call problem%get_objective_sensitivities(objective_sensitivities)
303 call problem%get_constraint_sensitivities(constraint_sensitivities)
306 if (this%auto_scale)
then
307 call constraint_value%copy_from(device_to_host, sync = .true.)
308 this%scaling_factor = abs(this%scale / constraint_value%x(1))
311 if (.not. abscmp(this%scaling_factor, 1.0_rp))
then
312 call vector_cmult(constraint_value, this%scaling_factor)
313 call matrix_cmult(constraint_sensitivities, this%scaling_factor)
317 call this%mma%update(iter, x, objective_sensitivities, &
318 constraint_value, constraint_sensitivities)
319 call design%update_design(x)
323 if (
present(simulation) .and. this%enable_output)
then
324 call simulation%write_forward(iter)
327 if (
present(simulation) .and. this%enable_output)
then
328 call simulation%write_adjoint(iter)
332 call problem%get_constraint_values(constraint_value)
334 select type (des =>
design)
336 call des%get_sensitivity(objective_sensitivities)
338 call problem%get_objective_sensitivities(objective_sensitivities)
341 call problem%get_constraint_sensitivities(constraint_sensitivities)
344 call this%mma%KKT(x, objective_sensitivities, &
345 constraint_value, constraint_sensitivities)
346 converged = this%mma%get_residumax() .lt. this%tolerance
349 call neko_scratch_registry%relinquish(indices)
351 end function mma_optimizer_step
354 subroutine mma_optimizer_validate(this, problem, design)
357 class(
design_t),
intent(in) :: design
359 type(vector_t),
pointer :: constraint_values
362 call neko_scratch_registry%request(constraint_values, ind, &
363 problem%get_n_constraints(), .false.)
365 call problem%get_constraint_values(constraint_values)
366 call constraint_values%copy_from(device_to_host, sync = .true.)
368 if (any(constraint_values%x .gt. 0.0_rp))
then
369 call neko_error(
'MMA optimizer validation failed: ' // &
370 'Constraints are not satisfied.')
374 call neko_scratch_registry%relinquish(ind)
376 end subroutine mma_optimizer_validate
387 subroutine mma_optimizer_write(this, iter, problem)
389 integer,
intent(in) :: iter
392 type(vector_t),
pointer :: log_data
393 type(vector_t),
pointer :: all_objectives
394 type(vector_t),
pointer :: constraint_value
395 real(kind=rp) :: objective_value
397 integer :: log_size, ind(3), n, m, i_tmp1, i_tmp2
399 if (.not. this%enable_output)
return
400 call profiler_start_region(
'Optimizer logging')
403 m =
problem%get_n_constraints()
404 if (this%unconstrained_problem)
then
410 call neko_scratch_registry%request(log_data, ind(1), log_size, .false.)
411 call neko_scratch_registry%request(all_objectives, ind(2), n, .false.)
412 call neko_scratch_registry%request(constraint_value, ind(3), m, .false.)
415 call problem%get_objective_value(objective_value)
416 call problem%get_all_objective_values(all_objectives)
417 call problem%get_constraint_values(constraint_value)
419 call all_objectives%copy_from(device_to_host, sync = .true.)
420 call constraint_value%copy_from(device_to_host, sync = .true.)
423 log_data%x(1) = real(iter, kind=rp)
426 log_data%x(2) = objective_value
430 i_tmp2 = i_tmp1 + n - 1
431 log_data%x(i_tmp1 : i_tmp2) = all_objectives%x
434 if (.not. this%unconstrained_problem)
then
436 i_tmp2 = i_tmp1 + m - 1
437 log_data%x(i_tmp1 : i_tmp2) = constraint_value%x
441 if (iter .eq. 0)
then
442 log_data%x(i_tmp2 + 1) = 0.0_rp
443 log_data%x(i_tmp2 + 2) = 0.0_rp
445 log_data%x(i_tmp2 + 1) = this%mma%get_residumax()
446 log_data%x(i_tmp2 + 2) = this%mma%get_residunorm()
448 log_data%x(i_tmp2 + 3) = this%scaling_factor
450 call this%csv_log%write(log_data)
453 call neko_scratch_registry%relinquish(ind)
455 call profiler_end_region(
'Optimizer logging')
456 end subroutine mma_optimizer_write
458end module mma_optimizer
Implements the constraint_t type.
Implements the dummy_constraint_t type.
Module for handling the optimization problem.
Implements the steady_problem_t type.
A topology optimization design variable.
The abstract constraint type.
Abstract optimizer class.
The abstract problem type.