Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
problem.f90
Go to the documentation of this file.
1
33
35module problem
36 use num_types, only: rp
37 use fld_file_output, only: fld_file_output_t
38 use design, only: design_t
39 use objective, only: objective_t, objective_wrapper_t, objective_factory
41 use constraint, only: constraint_t, constraint_wrapper_t, constraint_factory
42 use vector, only: vector_t
43 use matrix, only: matrix_t
44 use device, only: device_memcpy, host_to_device, device_to_host
45 use neko_config, only: neko_bcknd_device
46 use json_module, only: json_file
47 use json_utils, only: json_extract_item, json_get, json_get_or_default
48 use simulation_m, only: simulation_t
49 use logger, only: neko_log
50 use device_math, only: device_copy
51 use vector_math, only: vector_add2
52
53 implicit none
54 private
55
62 type, public :: problem_t
63 private
64
66 integer :: n_design
68 integer :: n_objectives
70 integer :: n_constraints
71
73 class(objective_wrapper_t), allocatable, dimension(:) :: objective_list
75 class(constraint_wrapper_t), allocatable, dimension(:) :: constraint_list
76
77 contains
78
79 ! ----------------------------------------------------------------------- !
80 ! Interfaces
81
83 procedure, pass(this), public :: init => problem_init
85 procedure, pass(this), public :: free => problem_free
86
90 procedure, pass(this), public :: compute => problem_compute
91
95 procedure, pass(this), public :: compute_sensitivity => &
96 problem_compute_sensitivity
97
98 ! ----------------------------------------------------------------------- !
99 ! Base class methods
100
102 procedure, pass(this), public :: read_objectives => problem_read_objectives
104 procedure, pass(this), public :: read_constraints => &
105 problem_read_constraints
106
107 ! ----------------------------------------------------------------------- !
108 ! Actual methods
109
111 procedure, pass(this), public :: write => problem_write
112
114 procedure, pass(this), public :: add_objective => problem_add_objective
116 procedure, pass(this), public :: add_constraint => problem_add_constraint
117
118 ! ----------------------------------------------------------------------- !
119 ! Internal Updater methods
120
122 procedure, pass(this) :: update_objectives => &
123 problem_update_objectives
125 procedure, pass(this) :: update_constraints => &
126 problem_update_constraints
128 procedure, pass(this) :: update_objective_sensitivities => &
129 problem_update_objective_sensitivities
131 procedure, pass(this) :: update_constraint_sensitivities => &
132 problem_update_constraint_sensitivities
133
134 ! ----------------------------------------------------------------------- !
135 ! Public Getters
136
138 procedure, pass(this), public :: get_objective_value => &
139 problem_get_objective_value
141 procedure, pass(this), public :: get_all_objective_values => &
142 problem_get_all_objective_values
144 procedure, pass(this), public :: get_constraint_values => &
145 problem_get_constraint_values
147 procedure, pass(this), public :: get_objective_sensitivities => &
148 problem_get_objective_sensitivities
150 procedure, pass(this), public :: get_constraint_sensitivities => &
151 problem_get_constraint_sensitivities
152
154 procedure, pass(this) :: get_n_objectives => problem_get_num_objectives
156 procedure, pass(this) :: get_n_constraints => problem_get_num_constraints
157
159 procedure, pass(this) :: get_log_header => problem_get_log_header
160
161 end type problem_t
162
163contains
164
165 ! ========================================================================== !
166 ! Base class methods
167
169 subroutine problem_init(this, parameters, design, simulation)
170 class(problem_t), intent(inout) :: this
171 type(json_file), intent(inout) :: parameters
172 class(design_t), intent(in) :: design
173 type(simulation_t), optional, intent(inout) :: simulation
174
175 this%n_design = design%size()
176 this%n_objectives = 0
177 this%n_constraints = 0
178
179 ! minimum dissipation objective function
180 call this%read_objectives(parameters, design, simulation)
181
182 ! volume constraint
183 call this%read_constraints(parameters, design, simulation)
184
185 end subroutine problem_init
186
188 subroutine problem_free(this)
189 class(problem_t), intent(inout) :: this
190 integer :: i
191
192 ! Free the objective list
193 if (allocated(this%objective_list)) then
194 do i = 1, size(this%objective_list)
195 call this%objective_list(i)%free()
196 end do
197 deallocate(this%objective_list)
198 end if
199
200 ! Free the constraint list
201 if (allocated(this%constraint_list)) then
202 do i = 1, size(this%constraint_list)
203 call this%constraint_list(i)%free()
204 end do
205 deallocate(this%constraint_list)
206 end if
207 end subroutine problem_free
208
210 subroutine problem_write(this, idx)
211 class(problem_t), intent(inout) :: this
212 integer, intent(in) :: idx
213
214 end subroutine problem_write
215
216 ! ========================================================================== !
217 ! Handling constraints and objectives
218
220 subroutine problem_read_objectives(this, parameters, design, simulation)
221 class(problem_t), intent(inout) :: this
222 type(json_file), intent(inout) :: parameters
223 class(design_t), intent(in) :: design
224 class(objective_t), allocatable :: objective
225 type(simulation_t), optional, intent(inout) :: simulation
226
227 ! A single objective term as its own json_file.
228 character(len=:), allocatable :: path, type
229 type(json_file) :: objective_json
230 integer :: n_objectives, i
231 logical :: dealias
232
233 call neko_log%section("Reading objectives")
234
235 ! Get the number of objectives.
236 path = "optimization.objectives"
237 if (parameters%valid_path(path)) then
238 call parameters%info(path, n_children = n_objectives)
239
240 ! Grab a single parameters entry and create a constraint from it.
241 do i = 1, n_objectives
242 call json_extract_item(parameters, path, i, objective_json)
243 call json_get(objective_json, "type", type)
244 call neko_log%message(type)
245
246 call objective_factory(objective, objective_json, design, simulation)
247 call this%add_objective(objective)
248 end do
249 end if
250
251 if (present(simulation)) then
252 if (allocated(objective)) deallocate(objective)
254 select type(alo => objective)
256 call json_get_or_default(parameters, &
257 "adjoint_fluid.dealias_sensitivity", dealias, .true.)
258 call alo%init_from_attributes(design, simulation, weight = 1.0_rp, &
259 name = "Augmented Lagrangian", mask_name = "", &
260 dealias = dealias)
261 end select
262 call this%add_objective(objective)
263 end if
264
265 call neko_log%end_section()
266
267 end subroutine problem_read_objectives
268
270 subroutine problem_read_constraints(this, parameters, design, simulation)
271 class(problem_t), intent(inout) :: this
272 type(json_file), intent(inout) :: parameters
273 class(design_t), intent(in) :: design
274 class(constraint_t), allocatable :: constraint
275 type(simulation_t), optional, intent(inout) :: simulation
276
277 ! A single constraint term as its own json_file.
278 character(len=:), allocatable :: path, type
279 type(json_file) :: constraint_json
280 integer :: n_constraints, i
281
282 call neko_log%section("Reading constraints")
283
284 ! Get the number of constraints.
285 path = "optimization.constraints"
286
287 if (parameters%valid_path(path)) then
288 call parameters%info(path, n_children = n_constraints)
289
290 ! Grab a single parameters entry and create a constraint from it.
291 do i = 1, n_constraints
292 call json_extract_item(parameters, path, i, constraint_json)
293 call json_get(constraint_json, "type", type)
294 call neko_log%message(type)
295
296 call constraint_factory(constraint, constraint_json, design, simulation)
297 call this%add_constraint(constraint)
298 end do
299 end if
300
301 call neko_log%end_section()
302
303 end subroutine problem_read_constraints
304
306 subroutine problem_add_objective(this, objective)
307 class(problem_t), intent(inout) :: this
308 class(objective_t), allocatable, intent(inout) :: objective
309 class(objective_wrapper_t), allocatable, dimension(:) :: temp_list
310 integer :: i, n
311
312 n = 0
313 if (allocated(this%objective_list)) then
314 n = size(this%objective_list)
315 call move_alloc(this%objective_list, temp_list)
316 allocate(this%objective_list(n + 1))
317 if (allocated(temp_list)) then
318 do i = 1, n
319 call move_alloc(temp_list(i)%objective, &
320 this%objective_list(i)%objective)
321 end do
322 end if
323 else
324 allocate(this%objective_list(1))
325 end if
326
327 call move_alloc(objective, this%objective_list(n + 1)%objective)
328 this%n_objectives = n + 1
329 end subroutine problem_add_objective
330
332 subroutine problem_add_constraint(this, constraint)
333 class(problem_t), intent(inout) :: this
334 class(constraint_t), allocatable, intent(inout) :: constraint
335 class(constraint_wrapper_t), allocatable, dimension(:) :: temp_list
336 integer :: i, n
337
338 n = 0
339 if (allocated(this%constraint_list)) then
340 n = size(this%constraint_list)
341 call move_alloc(this%constraint_list, temp_list)
342 allocate(this%constraint_list(n + 1))
343 if (allocated(temp_list)) then
344 do i = 1, n
345 call move_alloc(temp_list(i)%constraint, &
346 this%constraint_list(i)%constraint)
347 end do
348 end if
349 else
350 allocate(this%constraint_list(1))
351 end if
352
353 call move_alloc(constraint, this%constraint_list(n + 1)%constraint)
354 this%n_constraints = n + 1
355 end subroutine problem_add_constraint
356
357 ! ========================================================================== !
358 ! Problem part computation
359
361 subroutine problem_compute(this, design, simulation)
362 class(problem_t), intent(inout) :: this
363 class(design_t), intent(inout) :: design
364 class(simulation_t), optional, intent(inout) :: simulation
365
366 if (present(simulation)) then
367 call simulation%reset()
368 call simulation%run_forward()
369 end if
370
371 call this%update_objectives(design)
372 call this%update_constraints(design)
373
374 end subroutine problem_compute
375
377 subroutine problem_compute_sensitivity(this, design, simulation)
378 class(problem_t), intent(inout) :: this
379 class(design_t), intent(inout) :: design
380 class(simulation_t), optional, intent(inout) :: simulation
381
382 type(vector_t) :: objective_sensitivity
383
384 if (present(simulation)) call simulation%run_backward()
385
386 call this%update_objective_sensitivities(design)
387 call this%update_constraint_sensitivities(design)
388
389 call objective_sensitivity%init(this%n_design)
390 call this%get_objective_sensitivities(objective_sensitivity)
391
392 call design%map_backward(objective_sensitivity)
393
394 call objective_sensitivity%free()
395 end subroutine problem_compute_sensitivity
396
397 ! ========================================================================== !
398 ! Update the objectives and constraints
399
406 subroutine problem_update_objectives(this, design)
407 class(problem_t), intent(inout) :: this
408 class(design_t), intent(in) :: design
409 integer :: i
410
411 do i = 1, this%n_objectives
412 call this%objective_list(i)%objective%update_value(design)
413 end do
414 end subroutine problem_update_objectives
415
422 subroutine problem_update_constraints(this, design)
423 class(problem_t), intent(inout) :: this
424 class(design_t), intent(in) :: design
425 integer :: i
426
427 do i = 1, this%n_constraints
428 call this%constraint_list(i)%constraint%update_value(design)
429 end do
430 end subroutine problem_update_constraints
431
438 subroutine problem_update_objective_sensitivities(this, design)
439 class(problem_t), intent(inout) :: this
440 class(design_t), intent(in) :: design
441 integer :: i
442
443 do i = 1, this%n_objectives
444 call this%objective_list(i)%objective%update_sensitivity(design)
445 end do
446 end subroutine problem_update_objective_sensitivities
447
454 subroutine problem_update_constraint_sensitivities(this, design)
455 class(problem_t), intent(inout) :: this
456 class(design_t), intent(in) :: design
457 integer :: i
458
459 do i = 1, this%n_constraints
460 call this%constraint_list(i)%constraint%update_sensitivity(design)
461 end do
462 end subroutine problem_update_constraint_sensitivities
463
464 ! ========================================================================== !
465 ! Problem part getters
466
473 subroutine problem_get_objective_value(this, objective_value)
474 class(problem_t), intent(in) :: this
475 real(kind=rp), intent(out) :: objective_value
476 integer :: i
477
478 objective_value = 0.0_rp
479 do i = 1, this%n_objectives
480 objective_value = objective_value + &
481 this%objective_list(i)%objective%get_weight() * &
482 this%objective_list(i)%objective%get_value()
483 end do
484
485 end subroutine problem_get_objective_value
486
493 subroutine problem_get_all_objective_values(this, all_objective_values)
494 class(problem_t), intent(in) :: this
495 type(vector_t), intent(inout) :: all_objective_values
496 integer :: i
497
498 call all_objective_values%init(this%n_objectives)
499 do i = 1, this%n_objectives
500 all_objective_values%x(i) = this%objective_list(i)%objective%value
501 end do
502
503 if (neko_bcknd_device .eq. 1) then
504 call device_memcpy(all_objective_values%x, all_objective_values%x_d, &
505 this%n_objectives, host_to_device, sync = .true.)
506 end if
507
508 end subroutine problem_get_all_objective_values
509
516 subroutine problem_get_constraint_values(this, constraint_value)
517 class(problem_t), intent(in) :: this
518 type(vector_t), intent(inout) :: constraint_value
519 integer :: i
520
521 call constraint_value%init(this%n_constraints)
522 do i = 1, this%n_constraints
523 constraint_value%x(i) = this%constraint_list(i)%constraint%value
524 end do
525
526 if (neko_bcknd_device .eq. 1) then
527 call device_memcpy(constraint_value%x, constraint_value%x_d, &
528 this%n_constraints, host_to_device, sync = .true.)
529 end if
530
531 end subroutine problem_get_constraint_values
532
539 subroutine problem_get_objective_sensitivities(this, sensitivity)
540 class(problem_t), intent(in) :: this
541 type(vector_t), intent(inout) :: sensitivity
542 integer :: i
543
544 call sensitivity%init(this%n_design)
545 do i = 1, this%n_objectives
546 call vector_add2(sensitivity, &
547 this%objective_list(i)%objective%sensitivity)
548 end do
549
550 end subroutine problem_get_objective_sensitivities
551
558 subroutine problem_get_constraint_sensitivities(this, sensitivity)
559 class(problem_t), intent(in) :: this
560 type(matrix_t), intent(inout) :: sensitivity
561 type(vector_t) :: tmp
562 integer :: i, j, n
563
564 n = this%n_constraints * this%n_design
565 call sensitivity%init(this%n_constraints, this%n_design)
566 if (neko_bcknd_device .eq. 1) then
567 call tmp%init(this%n_design)
568 end if
569
570 do i = 1, this%n_constraints
571 if (neko_bcknd_device .eq. 1) then
572 tmp = this%constraint_list(i)%constraint%sensitivity
573 call device_memcpy(tmp%x, tmp%x_d, &
574 this%n_design, device_to_host, sync = .true.)
575 do j = 1, this%n_design
576 sensitivity%x(i, j) = tmp%x(j)
577 end do
578 else
579 do j = 1, this%n_design
580 sensitivity%x(i, j) = &
581 this%constraint_list(i)%constraint%sensitivity%x(j)
582 end do
583 end if
584 end do
585
586 if (neko_bcknd_device .eq. 1) then
587 call device_memcpy(sensitivity%x, sensitivity%x_d, n, &
588 host_to_device, sync = .true.)
589 end if
590
591 ! Free the temporary vector
592 if (neko_bcknd_device .eq. 1) then
593 call tmp%free()
594 end if
595
596 end subroutine problem_get_constraint_sensitivities
597
598 ! ========================================================================== !
599 ! Simple getters
600
602 pure function problem_get_num_objectives(this) result(n)
603 class(problem_t), intent(in) :: this
604 integer :: n
605
606 n = this%n_objectives
607 end function problem_get_num_objectives
608
610 pure function problem_get_num_constraints(this) result(n)
611 class(problem_t), intent(in) :: this
612 integer :: n
613
614 n = this%n_constraints
615 end function problem_get_num_constraints
616
618 function problem_get_log_header(this) result(buff)
619 class(problem_t), intent(in) :: this
620 character(len=1024) :: buff
621 character(len=50) :: mini_buff
622 integer :: i
623
624 ! When it comes to multi-objective optimization
625 ! (handled in the way that we do) we want to know the value of each
626 ! objective individually, not just the combined effect.
627 !
628 ! my vision is:
629 !
630 ! | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m |
631 !
632 ! And then if we also want things like thie iteration or KKT they can be
633 ! appended to the begining or end of this by the optimizer.
634 !
635 ! iter | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m | KKT
636 buff = "Total objective function"
637 do i = 1, this%get_n_objectives()
638 mini_buff = ""
639 write(mini_buff, '(", ", A)') this%objective_list(i)%objective%name
640 buff = trim(buff)//trim(mini_buff)
641 end do
642
643 do i = 1, this%get_n_constraints()
644 mini_buff = ""
645 write(mini_buff, '(", ", A)') &
646 this%constraint_list(i)%constraint%name
647 buff = trim(buff)//trim(mini_buff)
648 end do
649
650 end function problem_get_log_header
651end module problem
Implements the augmented_lagrangian_objective_t type.
Implements the constraint_t type.
Implements the design_t.
Definition design.f90:34
Implements the objective_t type.
Definition objective.f90:35
Module for handling the optimization problem.
Definition problem.f90:35
subroutine problem_init(this, parameters, design, simulation)
The constructor for the base problem.
Definition problem.f90:170
Implements the steady_problem_t type.
An objective function implementing our augmented lagrangian sensitivity contribution.
The abstract constraint type.
Wrapper for constraints for use in lists.
An abstract design type.
Definition design.f90:52
The abstract objective type.
Definition objective.f90:51
Wrapper for objectives for use in lists.
Definition objective.f90:66
The abstract problem type.
Definition problem.f90:62