5 use num_types,
only: rp
6 use utils,
only: neko_error
7 use json_utils,
only: json_get, json_get_or_default
15 use json_module,
only: json_file
16 use vector,
only: vector_t
17 use matrix,
only: matrix_t
18 use comm,
only: pe_rank
19 use neko_config,
only: neko_bcknd_device
20 use scratch_registry,
only: neko_scratch_registry
21 use profiler,
only: profiler_start_region, profiler_end_region
22 use logger,
only: neko_log
23 use csv_file,
only: csv_file_t
24 use vector_math,
only: vector_cmult
25 use matrix_math,
only: matrix_cmult
26 use device,
only: device_memcpy, host_to_device
43 real(kind=rp) :: scale = 1.0_rp
44 real(kind=rp) :: scaling_factor = 1.0_rp
45 logical :: auto_scale = .false.
48 logical :: unconstrained_problem = .false.
51 logical :: enable_output = .true.
52 type(csv_file_t) :: csv_log
56 generic :: init => init_from_json, init_from_components
57 procedure, pass(this) :: init_from_json => mma_optimizer_init_from_json
58 procedure, pass(this) :: init_from_components => &
59 mma_optimizer_init_from_components
61 procedure, pass(this) :: run => mma_optimizer_run
62 procedure, pass(this) :: validate => mma_optimizer_validate
63 procedure, pass(this) :: write => mma_optimizer_write
64 procedure, pass(this) :: free => mma_optimizer_free
71 subroutine mma_optimizer_init_from_json(this, parameters, problem, design, &
74 type(json_file),
intent(inout) :: parameters
80 type(json_file) :: solver_parameters
81 logical :: enable_output
82 integer :: max_iterations
83 real(kind=rp) :: tolerance
86 call json_get(parameters,
'optimization.solver', solver_parameters)
87 call json_get_or_default(solver_parameters,
'max_iterations', &
89 call json_get_or_default(solver_parameters,
'tolerance', &
91 call json_get_or_default(solver_parameters,
'enable_output', &
92 enable_output, .true.)
94 call this%init_from_components(
problem,
design, max_iterations, tolerance, &
95 enable_output, solver_parameters, simulation)
97 end subroutine mma_optimizer_init_from_json
100 subroutine mma_optimizer_init_from_components(this, problem, design, &
101 max_iterations, tolerance, enable_output, solver_parameters, simulation)
105 integer,
intent(in) :: max_iterations
106 real(kind=rp),
intent(in) :: tolerance
107 logical,
intent(in) :: enable_output
108 type(json_file),
intent(inout),
optional :: solver_parameters
112 type(vector_t),
pointer :: x
118 call neko_log%section(
'Optimizer Initialization')
121 this%unconstrained_problem = (
problem%get_n_constraints() .eq. 0)
122 if (this%unconstrained_problem)
then
123 call neko_log%message(
'Unconstrained problem detected. ' // &
124 'Adding a dummy constraint to enable MMA optimization.')
127 select type (con => dummy_con)
129 call con%init_from_attributes(
design)
132 call problem%add_constraint(dummy_con)
137 call neko_scratch_registry%request(x, ind,
design%size(), .false.)
140 call this%mma%init(x,
design%size(),
problem%get_n_constraints(), &
141 solver_parameters, this%scale, this%auto_scale)
143 call neko_scratch_registry%relinquish_vector(ind)
146 this%enable_output = enable_output
147 this%scaling_factor = this%scale
150 if (this%enable_output)
then
151 call this%csv_log%init(
'optimization_data.csv')
154 call this%init_base(max_iterations, tolerance)
156 call neko_log%end_section()
158 end subroutine mma_optimizer_init_from_components
161 subroutine mma_optimizer_run(this, problem, design, simulation)
165 type(
simulation_t),
optional,
intent(inout) :: simulation
167 type(vector_t),
pointer :: x
171 real(kind=rp) :: objective_value
172 type(vector_t),
pointer :: constraint_value
173 type(vector_t),
pointer :: objective_sensitivities
174 type(matrix_t),
pointer :: constraint_sensitivities
180 call neko_scratch_registry%request(x, ind(1), n, .false.)
181 call neko_scratch_registry%request(constraint_value, ind(2), &
182 problem%get_n_constraints(), .false.)
183 call neko_scratch_registry%request(objective_sensitivities, ind(3), &
185 call neko_scratch_registry%request(constraint_sensitivities, ind(4), &
186 problem%get_n_constraints(), n, .false.)
189 if (pe_rank .eq. 0)
then
190 print *,
'max_iterations for the optimization loop = ', &
193 call profiler_start_region(
'Optimizer iteration')
196 if (
present(simulation) .and. this%enable_output)
then
197 call simulation%write_forward(0)
200 if (
present(simulation) .and. this%enable_output)
then
201 call simulation%write_adjoint(0)
204 call problem%get_objective_value(objective_value)
205 call problem%get_constraint_values(constraint_value)
207 select type (des =>
design)
209 call des%get_sensitivity(objective_sensitivities)
211 call problem%get_objective_sensitivities(objective_sensitivities)
214 call problem%get_constraint_sensitivities(constraint_sensitivities)
216 call profiler_end_region(
'Optimizer iteration')
221 do iter = 1, this%max_iterations
222 if (this%mma%get_residumax() .lt. this%tolerance)
exit
224 call profiler_start_region(
'Optimizer iteration')
227 if (this%auto_scale)
then
228 this%scaling_factor = abs(this%scale / constraint_value%x(1))
231 call vector_cmult(constraint_value, this%scaling_factor)
232 call matrix_cmult(constraint_sensitivities, this%scaling_factor)
236 call this%mma%update(iter, x, objective_sensitivities, &
237 constraint_value, constraint_sensitivities)
239 call design%update_design(x)
242 if (
present(simulation) .and. this%enable_output)
then
243 call simulation%write_forward(iter)
246 if (
present(simulation) .and. this%enable_output)
then
247 call simulation%write_adjoint(iter)
250 call problem%get_constraint_values(constraint_value)
252 select type (des =>
design)
254 call des%get_sensitivity(objective_sensitivities)
256 call problem%get_objective_sensitivities(objective_sensitivities)
259 call problem%get_constraint_sensitivities(constraint_sensitivities)
261 call this%mma%KKT(x, objective_sensitivities, &
262 constraint_value, constraint_sensitivities)
264 call profiler_end_region(
'Optimizer iteration')
274 if (pe_rank .eq. 0)
then
275 print *,
'MMA Optimization completed after', iter-1,
'iterations.'
279 call neko_scratch_registry%relinquish(ind)
281 end subroutine mma_optimizer_run
284 subroutine mma_optimizer_validate(this, problem, design)
289 type(vector_t),
pointer :: constraint_values
292 call neko_scratch_registry%request( &
293 constraint_values, ind,
problem%get_n_constraints(), .false.)
295 call problem%get_constraint_values(constraint_values)
296 if (neko_bcknd_device .eq. 1)
then
297 call device_memcpy(constraint_values%x, constraint_values%x_d, &
298 constraint_values%size(), host_to_device, .true.)
301 if (any(constraint_values%x .gt. 0.0_rp))
then
302 call neko_error(
'MMA optimizer validation failed: ' // &
303 'Constraints are not satisfied.')
307 call neko_scratch_registry%relinquish_vector(ind)
309 end subroutine mma_optimizer_validate
312 subroutine mma_optimizer_free(this)
316 call this%free_base()
318 end subroutine mma_optimizer_free
320 subroutine mma_optimizer_write(this, iter, problem)
322 integer,
intent(in) :: iter
325 type(vector_t),
pointer :: log_data
326 type(vector_t),
pointer :: all_objectives
327 type(vector_t),
pointer :: constraint_value
328 real(kind=rp) :: objective_value
329 character(len=1024) :: header
331 integer :: log_size, ind(3), n, m, i_tmp1, i_tmp2
333 if (.not. this%enable_output)
return
334 call profiler_start_region(
'Optimizer logging')
337 m =
problem%get_n_constraints()
338 if (this%unconstrained_problem)
then
344 call neko_scratch_registry%request(log_data, ind(1), log_size, .false.)
345 call neko_scratch_registry%request(all_objectives, ind(2), n, .false.)
346 call neko_scratch_registry%request(constraint_value, ind(3), m, .false.)
348 if (iter .eq. 0)
then
349 header =
'iter, ' // &
350 trim(
problem%get_log_header()) // &
351 ', KKTmax, KKTnorm2, scaling factor, ' // &
352 trim(this%mma%get_backend_and_subsolver())
354 call this%csv_log%set_header(trim(header))
358 call problem%get_objective_value(objective_value)
359 call problem%get_all_objective_values(all_objectives)
360 call problem%get_constraint_values(constraint_value)
363 log_data%x(1) = real(iter, kind=rp)
366 log_data%x(2) = objective_value
370 i_tmp2 = i_tmp1 + n - 1
371 log_data%x(i_tmp1 : i_tmp2) = all_objectives%x
374 if (.not. this%unconstrained_problem)
then
376 i_tmp2 = i_tmp1 + m - 1
377 log_data%x(i_tmp1 : i_tmp2) = constraint_value%x
381 if (iter .eq. 0)
then
382 log_data%x(i_tmp2 + 1) = 0.0_rp
383 log_data%x(i_tmp2 + 2) = 0.0_rp
385 log_data%x(i_tmp2 + 1) = this%mma%get_residumax()
386 log_data%x(i_tmp2 + 2) = this%mma%get_residunorm()
388 log_data%x(i_tmp2 + 3) = this%scaling_factor
390 call this%csv_log%write(log_data)
393 call neko_scratch_registry%relinquish(ind)
395 call profiler_end_region(
'Optimizer logging')
396 end subroutine mma_optimizer_write
398end 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.