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, 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 => &
96
97 ! ----------------------------------------------------------------------- !
98 ! Base class methods
99
101 procedure, pass(this), public :: read_objectives => problem_read_objectives
103 procedure, pass(this), public :: 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 => &
124 procedure, pass(this) :: update_constraints => &
127 procedure, pass(this) :: update_objective_sensitivities => &
130 procedure, pass(this) :: update_constraint_sensitivities => &
132
133 ! ----------------------------------------------------------------------- !
134 ! Public Getters
135
137 procedure, pass(this), public :: get_objective_value => &
140 procedure, pass(this), public :: get_all_objective_values => &
143 procedure, pass(this), public :: get_constraint_values => &
146 procedure, pass(this), public :: get_objective_sensitivities => &
149 procedure, pass(this), public :: 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), 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, simulation, design)
180
181 ! volume constraint
182 call this%read_constraints(parameters, simulation, design)
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, simulation, design)
220 class(problem_t), intent(inout) :: this
221 type(json_file), intent(inout) :: parameters
222 type(simulation_t), intent(inout) :: simulation
223 class(design_t), intent(in) :: design
224 class(objective_t), allocatable :: objective
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 call parameters%info(path, n_children = n_objectives)
236
237 ! Grab a single parameters entry and create a constraint from it.
238 do i = 1, n_objectives
239 call json_extract_item(parameters, path, i, objective_json)
240 call json_get(objective_json, "type", type)
241 call neko_log%message(type)
242
243 call objective_factory(objective, objective_json, design, simulation)
244 call this%add_objective(objective)
245
246 end do
247
248 call neko_log%end_section()
249
250 end subroutine problem_read_objectives
251
253 subroutine problem_read_constraints(this, parameters, simulation, design)
254 class(problem_t), intent(inout) :: this
255 type(json_file), intent(inout) :: parameters
256 type(simulation_t), intent(inout) :: simulation
257 class(design_t), intent(in) :: design
258 class(constraint_t), allocatable :: constraint
259
260 ! A single constraint term as its own json_file.
261 character(len=:), allocatable :: path, type
262 type(json_file) :: constraint_json
263 integer :: n_constraints, i
264
265 call neko_log%section("Reading constraints")
266
267 ! Get the number of constraints.
268 path = "optimization.constraints"
269 call parameters%info(path, n_children = n_constraints)
270
271 ! Grab a single parameters entry and create a constraint from it.
272 do i = 1, n_constraints
273 call json_extract_item(parameters, path, i, constraint_json)
274 call json_get(constraint_json, "type", type)
275 call neko_log%message(type)
276
277 call constraint_factory(constraint, constraint_json, design, simulation)
278 call this%add_constraint(constraint)
279
280 end do
281
282 call neko_log%end_section()
283
284 end subroutine problem_read_constraints
285
287 subroutine problem_add_objective(this, objective)
288 class(problem_t), intent(inout) :: this
289 class(objective_t), allocatable, intent(inout) :: objective
290 class(objective_wrapper_t), allocatable, dimension(:) :: temp_list
291 integer :: i, n
292
293 n = 0
294 if (allocated(this%objective_list)) then
295 n = size(this%objective_list)
296 call move_alloc(this%objective_list, temp_list)
297 allocate(this%objective_list(n + 1))
298 if (allocated(temp_list)) then
299 do i = 1, n
300 call move_alloc(temp_list(i)%objective, &
301 this%objective_list(i)%objective)
302 end do
303 end if
304 else
305 allocate(this%objective_list(1))
306 end if
307
308 call move_alloc(objective, this%objective_list(n + 1)%objective)
309 this%n_objectives = n + 1
310 end subroutine problem_add_objective
311
313 subroutine problem_add_constraint(this, constraint)
314 class(problem_t), intent(inout) :: this
315 class(constraint_t), allocatable, intent(inout) :: constraint
316 class(constraint_wrapper_t), allocatable, dimension(:) :: temp_list
317 integer :: i, n
318
319 n = 0
320 if (allocated(this%constraint_list)) then
321 n = size(this%constraint_list)
322 call move_alloc(this%constraint_list, temp_list)
323 allocate(this%constraint_list(n + 1))
324 if (allocated(temp_list)) then
325 do i = 1, n
326 call move_alloc(temp_list(i)%constraint, &
327 this%constraint_list(i)%constraint)
328 end do
329 end if
330 else
331 allocate(this%constraint_list(1))
332 end if
333
334 call move_alloc(constraint, this%constraint_list(n + 1)%constraint)
335 this%n_constraints = n + 1
336 end subroutine problem_add_constraint
337
338 ! ========================================================================== !
339 ! Problem part computation
340
342 subroutine problem_compute(this, design)
343 class(problem_t), intent(inout) :: this
344 class(design_t), intent(inout) :: design
345
346 call this%update_objectives(design)
347 call this%update_constraints(design)
348
349 end subroutine problem_compute
350
352 subroutine problem_compute_sensitivity(this, design)
353 class(problem_t), intent(inout) :: this
354 class(design_t), intent(inout) :: design
355
356 type(vector_t) :: objective_sensitivity
357
358 call this%update_objective_sensitivities(design)
359 call this%update_constraint_sensitivities(design)
360
361 call this%get_objective_sensitivities(objective_sensitivity)
362
363 call design%map_backward(objective_sensitivity)
364
365 end subroutine problem_compute_sensitivity
366
367 ! ========================================================================== !
368 ! Update the objectives and constraints
369
375 subroutine problem_update_objectives(this, design)
376 class(problem_t), intent(inout) :: this
377 class(design_t), intent(in) :: design
378 integer :: i
379
380 do i = 1, this%n_objectives
381 call this%objective_list(i)%objective%update_value(design)
382 end do
383 end subroutine problem_update_objectives
384
390 subroutine problem_update_constraints(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_constraints
396 call this%constraint_list(i)%constraint%update_value(design)
397 end do
398 end subroutine problem_update_constraints
399
406 class(problem_t), intent(inout) :: this
407 class(design_t), intent(in) :: design
408 integer :: i
409
410 do i = 1, this%n_objectives
411 call this%objective_list(i)%objective%update_sensitivity(design)
412 end do
414
421 class(problem_t), intent(inout) :: this
422 class(design_t), intent(in) :: design
423 integer :: i
424
425 do i = 1, this%n_constraints
426 call this%constraint_list(i)%constraint%update_sensitivity(design)
427 end do
429
430 ! ========================================================================== !
431 ! Problem part getters
432
438 subroutine problem_get_objective_value(this, objective_value)
439 class(problem_t), intent(inout) :: this
440 real(kind=rp), intent(out) :: objective_value
441 integer :: i
442
443 objective_value = 0.0_rp
444 do i = 1, this%n_objectives
445 objective_value = objective_value + &
446 this%objective_list(i)%objective%weight * &
447 this%objective_list(i)%objective%value
448 end do
449
450 end subroutine problem_get_objective_value
451
457 subroutine problem_get_all_objective_values(this, all_objective_values)
458 class(problem_t), intent(inout) :: this
459 type(vector_t), intent(out) :: all_objective_values
460 integer :: i
461
462 call all_objective_values%init(this%n_objectives)
463
464 do i = 1, this%n_objectives
465 all_objective_values%x(i) = this%objective_list(i)%objective%value
466 end do
467
468 if (neko_bcknd_device .eq. 1) then
469 call device_memcpy(all_objective_values%x, all_objective_values%x_d, &
470 this%n_objectives, host_to_device, sync = .true.)
471 end if
472
474
480 subroutine problem_get_constraint_values(this, constraint_value)
481 class(problem_t), intent(inout) :: this
482 type(vector_t), intent(out) :: constraint_value
483 integer :: i
484
485 call constraint_value%init(this%n_constraints)
486
487 do i = 1, this%n_constraints
488 constraint_value%x(i) = this%constraint_list(i)%constraint%value
489 end do
490
491 if (neko_bcknd_device .eq. 1) then
492 call device_memcpy(constraint_value%x, constraint_value%x_d, &
493 this%n_constraints, host_to_device, sync = .true.)
494 end if
495
496 end subroutine problem_get_constraint_values
497
503 subroutine problem_get_objective_sensitivities(this, sensitivity)
504 class(problem_t), intent(inout) :: this
505 type(vector_t), intent(out) :: sensitivity
506 integer :: i
507
508 call sensitivity%init(this%n_design)
509
510 do i = 1, this%n_objectives
511 sensitivity = sensitivity + this%objective_list(i)%objective%sensitivity
512 end do
513
515
521 subroutine problem_get_constraint_sensitivities(this, sensitivity)
522 class(problem_t), intent(inout) :: this
523 type(matrix_t), intent(out) :: sensitivity
524 integer :: i, j
525
526 call sensitivity%init(this%n_constraints, this%n_design)
527
528 do i = 1, this%n_constraints
529 if (neko_bcknd_device .eq. 1) then
530 call device_memcpy( &
531 this%constraint_list(i)%constraint%sensitivity%x, &
532 this%constraint_list(i)%constraint%sensitivity%x_d, &
533 this%n_design, device_to_host, sync = .true.)
534 end if
535 do j = 1, this%n_design
536 sensitivity%x(i, j) = &
537 this%constraint_list(i)%constraint%sensitivity%x(j)
538 end do
539 end do
540
541 if (neko_bcknd_device .eq. 1) then
542 call device_memcpy(sensitivity%x, sensitivity%x_d, &
543 this%n_design * this%n_constraints, host_to_device, sync = .true.)
544 end if
545
547
548 ! ========================================================================== !
549 ! Simple getters
550
552 pure function problem_get_num_objectives(this) result(n)
553 class(problem_t), intent(in) :: this
554 integer :: n
555
556 n = this%n_objectives
557 end function problem_get_num_objectives
558
560 pure function problem_get_num_constraints(this) result(n)
561 class(problem_t), intent(in) :: this
562 integer :: n
563
564 n = this%n_constraints
565 end function problem_get_num_constraints
566
568 function problem_get_log_header(this) result(buff)
569 class(problem_t), intent(in) :: this
570 character(len=1024) :: buff
571 character(len=50) :: mini_buff
572 integer :: i
573
574 ! When it comes to multi-objective optimization
575 ! (handled in the way that we do) we want to know the value of each
576 ! objective individually, not just the combined effect.
577 !
578 ! my vision is:
579 !
580 ! | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m |
581 !
582 ! And then if we also want things like thie iteration or KKT they can be
583 ! appended to the begining or end of this by the optimizer.
584 !
585 ! iter | Total F | F_1 | F_2 | ... | F_n | C_1 | C_2 | ... | C_m | KKT
586 buff = "Total objective function"
587 do i = 1, this%get_n_objectives()
588 mini_buff = ""
589 write(mini_buff, '(", ", A)') this%objective_list(i)%objective%name
590 buff = trim(buff)//trim(mini_buff)
591 end do
592
593 do i = 1, this%get_n_constraints()
594 mini_buff = ""
595 write(mini_buff, '(", ", A)') &
596 this%constraint_list(i)%constraint%name
597 buff = trim(buff)//trim(mini_buff)
598 end do
599
600 end function problem_get_log_header
601end 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
pure integer function problem_get_num_objectives(this)
Return the number of objectives.
Definition problem.f90:553
pure integer function problem_get_num_constraints(this)
Return the number of constraints.
Definition problem.f90:561
subroutine problem_update_constraints(this, design)
Update the constraints.
Definition problem.f90:391
subroutine problem_get_all_objective_values(this, all_objective_values)
Construct and get the objective.
Definition problem.f90:458
subroutine problem_get_objective_value(this, objective_value)
Construct and get the objective.
Definition problem.f90:439
subroutine problem_write(this, idx)
Sample the fields/design.
Definition problem.f90:210
subroutine problem_get_constraint_sensitivities(this, sensitivity)
Construct and get the sensitivity of the constraints.
Definition problem.f90:522
subroutine problem_compute_sensitivity(this, design)
The computation of the objective function and constraints.
Definition problem.f90:353
subroutine problem_add_constraint(this, constraint)
Add an objective to the list.
Definition problem.f90:314
subroutine problem_update_objective_sensitivities(this, design)
Update the sensitivity of the objectives.
Definition problem.f90:406
character(len=1024) function problem_get_log_header(this)
Return the header for the problem.
Definition problem.f90:569
subroutine problem_free(this)
Destructor for the base class.
Definition problem.f90:188
subroutine problem_update_objectives(this, design)
Update the objectives.
Definition problem.f90:376
subroutine problem_init(this, parameters, design, simulation)
The constructor for the base problem.
Definition problem.f90:169
subroutine problem_get_constraint_values(this, constraint_value)
Construct and get the constraints.
Definition problem.f90:481
subroutine problem_get_objective_sensitivities(this, sensitivity)
Construct and get the sensitivity of the objective.
Definition problem.f90:504
subroutine problem_read_constraints(this, parameters, simulation, design)
Read the constraint from a parameters file.
Definition problem.f90:254
subroutine problem_read_objectives(this, parameters, simulation, design)
Read the objective from a parameters file.
Definition problem.f90:220
subroutine problem_update_constraint_sensitivities(this, design)
Update the sensitivity of the constraints.
Definition problem.f90:421
subroutine problem_add_objective(this, objective)
Add an objective to the list.
Definition problem.f90:288
subroutine problem_compute(this, design)
The computation of the objective function and constraints.
Definition problem.f90:343
Sensitivity module. This module contains the sensitivity computation of the topology optimization.
Implements the steady_problem_t type.
The abstract constraint type.
Wrapper for constraints for use in lists.
An abstract design type.
Definition design.f90:48
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