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
40 use constraint, only: constraint_t, constraint_wrapper_t, constraint_factory
41 use vector, only: vector_t
42 use matrix, only: matrix_t
43 use device, only: device_memcpy, host_to_device, device_to_host
44 use neko_config, only: neko_bcknd_device
45 use json_module, only: json_file
46 use json_utils, only: json_extract_item, json_get
47 use simulation_m, only: simulation_t
48 use logger, only: neko_log
49 use device_math, only: device_copy
50 use vector_math, only: vector_add2
51
52 implicit none
53 private
54
61 type, public :: problem_t
62 private
63
65 integer :: n_design
67 integer :: n_objectives
69 integer :: n_constraints
70
72 class(objective_wrapper_t), allocatable, dimension(:) :: objective_list
74 class(constraint_wrapper_t), allocatable, dimension(:) :: constraint_list
75
76 contains
77
78 ! ----------------------------------------------------------------------- !
79 ! Interfaces
80
82 procedure, pass(this), public :: init => problem_init
84 procedure, pass(this), public :: free => problem_free
85
89 procedure, pass(this), public :: compute => problem_compute
90
94 procedure, pass(this), public :: compute_sensitivity => &
95 problem_compute_sensitivity
96
97 ! ----------------------------------------------------------------------- !
98 ! Base class methods
99
101 procedure, pass(this), public :: read_objectives => problem_read_objectives
103 procedure, pass(this), public :: read_constraints => &
104 problem_read_constraints
105
106 ! ----------------------------------------------------------------------- !
107 ! Actual methods
108
110 procedure, pass(this), public :: write => problem_write
111
113 procedure, pass(this), public :: add_objective => problem_add_objective
115 procedure, pass(this), public :: add_constraint => problem_add_constraint
116
117 ! ----------------------------------------------------------------------- !
118 ! Internal Updater methods
119
121 procedure, pass(this) :: update_objectives => &
122 problem_update_objectives
124 procedure, pass(this) :: update_constraints => &
125 problem_update_constraints
127 procedure, pass(this) :: update_objective_sensitivities => &
128 problem_update_objective_sensitivities
130 procedure, pass(this) :: update_constraint_sensitivities => &
131 problem_update_constraint_sensitivities
132
133 ! ----------------------------------------------------------------------- !
134 ! Public Getters
135
137 procedure, pass(this), public :: get_objective_value => &
138 problem_get_objective_value
140 procedure, pass(this), public :: get_all_objective_values => &
141 problem_get_all_objective_values
143 procedure, pass(this), public :: get_constraint_values => &
144 problem_get_constraint_values
146 procedure, pass(this), public :: get_objective_sensitivities => &
147 problem_get_objective_sensitivities
149 procedure, pass(this), public :: get_constraint_sensitivities => &
150 problem_get_constraint_sensitivities
151
153 procedure, pass(this) :: get_n_objectives => problem_get_num_objectives
155 procedure, pass(this) :: get_n_constraints => problem_get_num_constraints
156
158 procedure, pass(this) :: get_log_header => problem_get_log_header
159
160 end type problem_t
161
162contains
163
164 ! ========================================================================== !
165 ! Base class methods
166
168 subroutine problem_init(this, parameters, design, simulation)
169 class(problem_t), intent(inout) :: this
170 type(json_file), intent(inout) :: parameters
171 class(design_t), intent(in) :: design
172 type(simulation_t), optional, intent(inout) :: simulation
173
174 this%n_design = design%size()
175 this%n_objectives = 0
176 this%n_constraints = 0
177
178 ! minimum dissipation objective function
179 call this%read_objectives(parameters, design, simulation)
180
181 ! volume constraint
182 call this%read_constraints(parameters, design, simulation)
183
184 end subroutine problem_init
185
187 subroutine problem_free(this)
188 class(problem_t), intent(inout) :: this
189 integer :: i
190
191 ! Free the objective list
192 if (allocated(this%objective_list)) then
193 do i = 1, size(this%objective_list)
194 call this%objective_list(i)%free()
195 end do
196 deallocate(this%objective_list)
197 end if
198
199 ! Free the constraint list
200 if (allocated(this%constraint_list)) then
201 do i = 1, size(this%constraint_list)
202 call this%constraint_list(i)%free()
203 end do
204 deallocate(this%constraint_list)
205 end if
206 end subroutine problem_free
207
209 subroutine problem_write(this, idx)
210 class(problem_t), intent(inout) :: this
211 integer, intent(in) :: idx
212
213 end subroutine problem_write
214
215 ! ========================================================================== !
216 ! Handling constraints and objectives
217
219 subroutine problem_read_objectives(this, parameters, design, simulation)
220 class(problem_t), intent(inout) :: this
221 type(json_file), intent(inout) :: parameters
222 class(design_t), intent(in) :: design
223 class(objective_t), allocatable :: objective
224 type(simulation_t), optional, intent(inout) :: simulation
225
226 ! A single objective term as its own json_file.
227 character(len=:), allocatable :: path, type
228 type(json_file) :: objective_json
229 integer :: n_objectives, i
230
231 call neko_log%section("Reading objectives")
232
233 ! Get the number of objectives.
234 path = "optimization.objectives"
235 if (parameters%valid_path(path)) then
236 call parameters%info(path, n_children = n_objectives)
237
238 ! Grab a single parameters entry and create a constraint from it.
239 do i = 1, n_objectives
240 call json_extract_item(parameters, path, i, objective_json)
241 call json_get(objective_json, "type", type)
242 call neko_log%message(type)
243
244 call objective_factory(objective, objective_json, design, simulation)
245 call this%add_objective(objective)
246 end do
247 end if
248
249 call neko_log%end_section()
250
251 end subroutine problem_read_objectives
252
254 subroutine problem_read_constraints(this, parameters, design, simulation)
255 class(problem_t), intent(inout) :: this
256 type(json_file), intent(inout) :: parameters
257 class(design_t), intent(in) :: design
258 class(constraint_t), allocatable :: constraint
259 type(simulation_t), optional, intent(inout) :: simulation
260
261 ! A single constraint term as its own json_file.
262 character(len=:), allocatable :: path, type
263 type(json_file) :: constraint_json
264 integer :: n_constraints, i
265
266 call neko_log%section("Reading constraints")
267
268 ! Get the number of constraints.
269 path = "optimization.constraints"
270
271 if (parameters%valid_path(path)) then
272 call parameters%info(path, n_children = n_constraints)
273
274 ! Grab a single parameters entry and create a constraint from it.
275 do i = 1, n_constraints
276 call json_extract_item(parameters, path, i, constraint_json)
277 call json_get(constraint_json, "type", type)
278 call neko_log%message(type)
279
280 call constraint_factory(constraint, constraint_json, design, simulation)
281 call this%add_constraint(constraint)
282 end do
283 end if
284
285 call neko_log%end_section()
286
287 end subroutine problem_read_constraints
288
290 subroutine problem_add_objective(this, objective)
291 class(problem_t), intent(inout) :: this
292 class(objective_t), allocatable, intent(inout) :: objective
293 class(objective_wrapper_t), allocatable, dimension(:) :: temp_list
294 integer :: i, n
295
296 n = 0
297 if (allocated(this%objective_list)) then
298 n = size(this%objective_list)
299 call move_alloc(this%objective_list, temp_list)
300 allocate(this%objective_list(n + 1))
301 if (allocated(temp_list)) then
302 do i = 1, n
303 call move_alloc(temp_list(i)%objective, &
304 this%objective_list(i)%objective)
305 end do
306 end if
307 else
308 allocate(this%objective_list(1))
309 end if
310
311 call move_alloc(objective, this%objective_list(n + 1)%objective)
312 this%n_objectives = n + 1
313 end subroutine problem_add_objective
314
316 subroutine problem_add_constraint(this, constraint)
317 class(problem_t), intent(inout) :: this
318 class(constraint_t), allocatable, intent(inout) :: constraint
319 class(constraint_wrapper_t), allocatable, dimension(:) :: temp_list
320 integer :: i, n
321
322 n = 0
323 if (allocated(this%constraint_list)) then
324 n = size(this%constraint_list)
325 call move_alloc(this%constraint_list, temp_list)
326 allocate(this%constraint_list(n + 1))
327 if (allocated(temp_list)) then
328 do i = 1, n
329 call move_alloc(temp_list(i)%constraint, &
330 this%constraint_list(i)%constraint)
331 end do
332 end if
333 else
334 allocate(this%constraint_list(1))
335 end if
336
337 call move_alloc(constraint, this%constraint_list(n + 1)%constraint)
338 this%n_constraints = n + 1
339 end subroutine problem_add_constraint
340
341 ! ========================================================================== !
342 ! Problem part computation
343
345 subroutine problem_compute(this, design, simulation)
346 class(problem_t), intent(inout) :: this
347 class(design_t), intent(inout) :: design
348 class(simulation_t), optional, intent(inout) :: simulation
349
350 if (present(simulation)) then
351 call simulation%reset()
352 call simulation%run_forward()
353 end if
354
355 call this%update_objectives(design)
356 call this%update_constraints(design)
357
358 end subroutine problem_compute
359
361 subroutine problem_compute_sensitivity(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 type(vector_t) :: objective_sensitivity
367
368 if (present(simulation)) call simulation%run_backward()
369
370 call this%update_objective_sensitivities(design)
371 call this%update_constraint_sensitivities(design)
372
373 call objective_sensitivity%init(this%n_design)
374 call this%get_objective_sensitivities(objective_sensitivity)
375
376 call design%map_backward(objective_sensitivity)
377
378 call objective_sensitivity%free()
379 end subroutine problem_compute_sensitivity
380
381 ! ========================================================================== !
382 ! Update the objectives and constraints
383
390 subroutine problem_update_objectives(this, design)
391 class(problem_t), intent(inout) :: this
392 class(design_t), intent(in) :: design
393 integer :: i
394
395 do i = 1, this%n_objectives
396 call this%objective_list(i)%objective%update_value(design)
397 end do
398 end subroutine problem_update_objectives
399
406 subroutine problem_update_constraints(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_constraints
412 call this%constraint_list(i)%constraint%update_value(design)
413 end do
414 end subroutine problem_update_constraints
415
422 subroutine problem_update_objective_sensitivities(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_objectives
428 call this%objective_list(i)%objective%update_sensitivity(design)
429 end do
430 end subroutine problem_update_objective_sensitivities
431
438 subroutine problem_update_constraint_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_constraints
444 call this%constraint_list(i)%constraint%update_sensitivity(design)
445 end do
446 end subroutine problem_update_constraint_sensitivities
447
448 ! ========================================================================== !
449 ! Problem part getters
450
457 subroutine problem_get_objective_value(this, objective_value)
458 class(problem_t), intent(in) :: this
459 real(kind=rp), intent(out) :: objective_value
460 integer :: i
461
462 objective_value = 0.0_rp
463 do i = 1, this%n_objectives
464 objective_value = objective_value + &
465 this%objective_list(i)%objective%get_weight() * &
466 this%objective_list(i)%objective%get_value()
467 end do
468
469 end subroutine problem_get_objective_value
470
477 subroutine problem_get_all_objective_values(this, all_objective_values)
478 class(problem_t), intent(in) :: this
479 type(vector_t), intent(inout) :: all_objective_values
480 integer :: i
481
482 call all_objective_values%init(this%n_objectives)
483 do i = 1, this%n_objectives
484 all_objective_values%x(i) = this%objective_list(i)%objective%value
485 end do
486
487 if (neko_bcknd_device .eq. 1) then
488 call device_memcpy(all_objective_values%x, all_objective_values%x_d, &
489 this%n_objectives, host_to_device, sync = .true.)
490 end if
491
492 end subroutine problem_get_all_objective_values
493
500 subroutine problem_get_constraint_values(this, constraint_value)
501 class(problem_t), intent(in) :: this
502 type(vector_t), intent(inout) :: constraint_value
503 integer :: i
504
505 call constraint_value%init(this%n_constraints)
506 do i = 1, this%n_constraints
507 constraint_value%x(i) = this%constraint_list(i)%constraint%value
508 end do
509
510 if (neko_bcknd_device .eq. 1) then
511 call device_memcpy(constraint_value%x, constraint_value%x_d, &
512 this%n_constraints, host_to_device, sync = .true.)
513 end if
514
515 end subroutine problem_get_constraint_values
516
523 subroutine problem_get_objective_sensitivities(this, sensitivity)
524 class(problem_t), intent(in) :: this
525 type(vector_t), intent(inout) :: sensitivity
526 integer :: i
527
528 call sensitivity%init(this%n_design)
529 do i = 1, this%n_objectives
530 call vector_add2(sensitivity, &
531 this%objective_list(i)%objective%sensitivity)
532 end do
533
534 end subroutine problem_get_objective_sensitivities
535
542 subroutine problem_get_constraint_sensitivities(this, sensitivity)
543 class(problem_t), intent(in) :: this
544 type(matrix_t), intent(inout) :: sensitivity
545 type(vector_t) :: tmp
546 integer :: i, j, n
547
548 n = this%n_constraints * this%n_design
549 call sensitivity%init(this%n_constraints, this%n_design)
550 if (neko_bcknd_device .eq. 1) then
551 call tmp%init(this%n_design)
552 end if
553
554 do i = 1, this%n_constraints
555 if (neko_bcknd_device .eq. 1) then
556 tmp = this%constraint_list(i)%constraint%sensitivity
557 call device_memcpy(tmp%x, tmp%x_d, &
558 this%n_design, device_to_host, sync = .true.)
559 do j = 1, this%n_design
560 sensitivity%x(i, j) = tmp%x(j)
561 end do
562 else
563 do j = 1, this%n_design
564 sensitivity%x(i, j) = &
565 this%constraint_list(i)%constraint%sensitivity%x(j)
566 end do
567 end if
568 end do
569
570 if (neko_bcknd_device .eq. 1) then
571 call device_memcpy(sensitivity%x, sensitivity%x_d, n, &
572 host_to_device, sync = .true.)
573 end if
574
575 ! Free the temporary vector
576 if (neko_bcknd_device .eq. 1) then
577 call tmp%free()
578 end if
579
580 end subroutine problem_get_constraint_sensitivities
581
582 ! ========================================================================== !
583 ! Simple getters
584
586 pure function problem_get_num_objectives(this) result(n)
587 class(problem_t), intent(in) :: this
588 integer :: n
589
590 n = this%n_objectives
591 end function problem_get_num_objectives
592
594 pure function problem_get_num_constraints(this) result(n)
595 class(problem_t), intent(in) :: this
596 integer :: n
597
598 n = this%n_constraints
599 end function problem_get_num_constraints
600
602 function problem_get_log_header(this) result(buff)
603 class(problem_t), intent(in) :: this
604 character(len=1024) :: buff
605 character(len=50) :: mini_buff
606 integer :: i
607
608 ! When it comes to multi-objective optimization
609 ! (handled in the way that we do) we want to know the value of each
610 ! objective individually, not just the combined effect.
611 !
612 ! my vision is:
613 !
614 ! | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m |
615 !
616 ! And then if we also want things like thie iteration or KKT they can be
617 ! appended to the begining or end of this by the optimizer.
618 !
619 ! iter | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m | KKT
620 buff = "Total objective function"
621 do i = 1, this%get_n_objectives()
622 mini_buff = ""
623 write(mini_buff, '(", ", A)') this%objective_list(i)%objective%name
624 buff = trim(buff)//trim(mini_buff)
625 end do
626
627 do i = 1, this%get_n_constraints()
628 mini_buff = ""
629 write(mini_buff, '(", ", A)') &
630 this%constraint_list(i)%constraint%name
631 buff = trim(buff)//trim(mini_buff)
632 end do
633
634 end function problem_get_log_header
635end module problem
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:169
Implements the steady_problem_t type.
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:61