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, only: vector_t
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)
346 class(problem_t), intent(inout) :: this
347 class(design_t), intent(inout) :: design
348
349 call this%update_objectives(design)
350 call this%update_constraints(design)
351
352 end subroutine problem_compute
353
355 subroutine problem_compute_sensitivity(this, design)
356 class(problem_t), intent(inout) :: this
357 class(design_t), intent(inout) :: design
358
359 type(vector_t) :: objective_sensitivity
360
361 call this%update_objective_sensitivities(design)
362 call this%update_constraint_sensitivities(design)
363
364 call this%get_objective_sensitivities(objective_sensitivity)
365
366 call design%map_backward(objective_sensitivity)
367
368 end subroutine problem_compute_sensitivity
369
370 ! ========================================================================== !
371 ! Update the objectives and constraints
372
379 subroutine problem_update_objectives(this, design)
380 class(problem_t), intent(inout) :: this
381 class(design_t), intent(in) :: design
382 integer :: i
383
384 do i = 1, this%n_objectives
385 call this%objective_list(i)%objective%update_value(design)
386 end do
387 end subroutine problem_update_objectives
388
395 subroutine problem_update_constraints(this, design)
396 class(problem_t), intent(inout) :: this
397 class(design_t), intent(in) :: design
398 integer :: i
399
400 do i = 1, this%n_constraints
401 call this%constraint_list(i)%constraint%update_value(design)
402 end do
403 end subroutine problem_update_constraints
404
411 subroutine problem_update_objective_sensitivities(this, design)
412 class(problem_t), intent(inout) :: this
413 class(design_t), intent(in) :: design
414 integer :: i
415
416 do i = 1, this%n_objectives
417 call this%objective_list(i)%objective%update_sensitivity(design)
418 end do
419 end subroutine problem_update_objective_sensitivities
420
427 subroutine problem_update_constraint_sensitivities(this, design)
428 class(problem_t), intent(inout) :: this
429 class(design_t), intent(in) :: design
430 integer :: i
431
432 do i = 1, this%n_constraints
433 call this%constraint_list(i)%constraint%update_sensitivity(design)
434 end do
435 end subroutine problem_update_constraint_sensitivities
436
437 ! ========================================================================== !
438 ! Problem part getters
439
446 subroutine problem_get_objective_value(this, objective_value)
447 class(problem_t), intent(inout) :: this
448 real(kind=rp), intent(out) :: objective_value
449 integer :: i
450
451 objective_value = 0.0_rp
452 do i = 1, this%n_objectives
453 objective_value = objective_value + &
454 this%objective_list(i)%objective%weight * &
455 this%objective_list(i)%objective%value
456 end do
457
458 end subroutine problem_get_objective_value
459
466 subroutine problem_get_all_objective_values(this, all_objective_values)
467 class(problem_t), intent(inout) :: this
468 type(vector_t), intent(out) :: all_objective_values
469 integer :: i
470
471 call all_objective_values%init(this%n_objectives)
472
473 do i = 1, this%n_objectives
474 all_objective_values%x(i) = this%objective_list(i)%objective%value
475 end do
476
477 if (neko_bcknd_device .eq. 1) then
478 call device_memcpy(all_objective_values%x, all_objective_values%x_d, &
479 this%n_objectives, host_to_device, sync = .true.)
480 end if
481
482 end subroutine problem_get_all_objective_values
483
490 subroutine problem_get_constraint_values(this, constraint_value)
491 class(problem_t), intent(inout) :: this
492 type(vector_t), intent(out) :: constraint_value
493 integer :: i
494
495 call constraint_value%init(this%n_constraints)
496
497 do i = 1, this%n_constraints
498 constraint_value%x(i) = this%constraint_list(i)%constraint%value
499 end do
500
501 if (neko_bcknd_device .eq. 1) then
502 call device_memcpy(constraint_value%x, constraint_value%x_d, &
503 this%n_constraints, host_to_device, sync = .true.)
504 end if
505
506 end subroutine problem_get_constraint_values
507
514 subroutine problem_get_objective_sensitivities(this, sensitivity)
515 class(problem_t), intent(inout) :: this
516 type(vector_t), intent(out) :: sensitivity
517 integer :: i
518
519 call sensitivity%init(this%n_design)
520
521 do i = 1, this%n_objectives
522 sensitivity = sensitivity + this%objective_list(i)%objective%sensitivity
523 end do
524
525 end subroutine problem_get_objective_sensitivities
526
533 subroutine problem_get_constraint_sensitivities(this, sensitivity)
534 class(problem_t), intent(inout) :: this
535 type(matrix_t), intent(out) :: sensitivity
536 integer :: i, j
537
538 call sensitivity%init(this%n_constraints, this%n_design)
539
540 do i = 1, this%n_constraints
541 if (neko_bcknd_device .eq. 1) then
542 call device_memcpy( &
543 this%constraint_list(i)%constraint%sensitivity%x, &
544 this%constraint_list(i)%constraint%sensitivity%x_d, &
545 this%n_design, device_to_host, sync = .true.)
546 end if
547 do j = 1, this%n_design
548 sensitivity%x(i, j) = &
549 this%constraint_list(i)%constraint%sensitivity%x(j)
550 end do
551 end do
552
553 if (neko_bcknd_device .eq. 1) then
554 call device_memcpy(sensitivity%x, sensitivity%x_d, &
555 this%n_design * this%n_constraints, host_to_device, sync = .true.)
556 end if
557
558 end subroutine problem_get_constraint_sensitivities
559
560 ! ========================================================================== !
561 ! Simple getters
562
564 pure function problem_get_num_objectives(this) result(n)
565 class(problem_t), intent(in) :: this
566 integer :: n
567
568 n = this%n_objectives
569 end function problem_get_num_objectives
570
572 pure function problem_get_num_constraints(this) result(n)
573 class(problem_t), intent(in) :: this
574 integer :: n
575
576 n = this%n_constraints
577 end function problem_get_num_constraints
578
580 function problem_get_log_header(this) result(buff)
581 class(problem_t), intent(in) :: this
582 character(len=1024) :: buff
583 character(len=50) :: mini_buff
584 integer :: i
585
586 ! When it comes to multi-objective optimization
587 ! (handled in the way that we do) we want to know the value of each
588 ! objective individually, not just the combined effect.
589 !
590 ! my vision is:
591 !
592 ! | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m |
593 !
594 ! And then if we also want things like thie iteration or KKT they can be
595 ! appended to the begining or end of this by the optimizer.
596 !
597 ! iter | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m | KKT
598 buff = "Total objective function"
599 do i = 1, this%get_n_objectives()
600 mini_buff = ""
601 write(mini_buff, '(", ", A)') this%objective_list(i)%objective%name
602 buff = trim(buff)//trim(mini_buff)
603 end do
604
605 do i = 1, this%get_n_constraints()
606 mini_buff = ""
607 write(mini_buff, '(", ", A)') &
608 this%constraint_list(i)%constraint%name
609 buff = trim(buff)//trim(mini_buff)
610 end do
611
612 end function problem_get_log_header
613end 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:50
The abstract objective type.
Definition objective.f90:51
Wrapper for objectives for use in lists.
Definition objective.f90:64
The abstract problem type.
Definition problem.f90:61