Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
optimizer.f90
Go to the documentation of this file.
1
34
40 use json_module, only: json_file
41 use simulation_m, only: simulation_t
42 use problem, only: problem_t
43 use design, only: design_t
44 use num_types, only: rp
45 use logger, only: neko_log
46 use profiler, only: profiler_start_region, profiler_end_region
47 use mpi_f08, only: mpi_wtime
48 use utils, only: neko_error, filename_suffix
49
50 implicit none
51 private
52
54 type, abstract, public :: optimizer_t
55
57 character(len=64), private :: optimizer_type = ''
59 integer, private :: max_iterations = 0
60
61 ! ----------------------------------------------------------------------- !
62 ! Restart related members
63
64 ! Variables for the runtime-based stopping criteria
65 integer, private :: current_iteration = 0
66 real(kind=rp), private :: max_runtime = -1.0_rp
67 real(kind=rp), private :: start_time = 0.0_rp
68 real(kind=rp), private :: average_time = 0.0_rp
69 real(kind=rp), private :: step_count = 0.0_rp
70
71 contains
72
73 ! ---------------------------------------------------------------------- !
74 ! Deferred procedures for specific optimizers
75
77 procedure(optimizer_init_from_json), pass(this), public, deferred :: &
78 init_from_json
80 procedure(optimizer_free), pass(this), public, deferred :: free
81
83 procedure(optimizer_initialize), pass(this), public, deferred :: initialize
85 procedure(optimizer_step), pass(this), public, deferred :: step
87 procedure(optimizer_validate), pass(this), public, deferred :: validate
88
90 procedure(optimizer_write), pass(this), public, deferred :: write
92 procedure(optimizer_save_checkpoint_components), pass(this), deferred :: &
93 save_checkpoint_components
95 procedure(optimizer_load_checkpoint_components), pass(this), deferred :: &
96 load_checkpoint_components
97
99 procedure, pass(this) :: save_checkpoint => optimizer_save_checkpoint
101 procedure, pass(this) :: load_checkpoint => optimizer_load_checkpoint
102
103 ! ----------------------------------------------------------------------- !
104 ! Public procedures
105
107 procedure, pass(this), public :: run => optimizer_run
108
109 ! ----------------------------------------------------------------------- !
110 ! Private procedures
111
113 procedure, pass(this) :: init_base => optimizer_init_base
115 procedure, pass(this) :: free_base => optimizer_free_base
117 procedure, pass(this) :: print_status => optimizer_print_status
119 procedure, pass(this) :: out_of_time => optimizer_out_of_time
120 end type optimizer_t
121
122 ! -------------------------------------------------------------------------- !
123 ! Interface for the optimizer module.
124
125 abstract interface
126
127 subroutine optimizer_init_from_json(this, parameters, problem, design, &
128 simulation)
129 import optimizer_t, json_file, simulation_t, problem_t, design_t, rp
130 class(optimizer_t), intent(inout) :: this
131 type(json_file), intent(inout) :: parameters
132 class(problem_t), intent(inout) :: problem
133 class(design_t), intent(in) :: design
134 type(simulation_t), optional, intent(in) :: simulation
135 end subroutine optimizer_init_from_json
136
140 subroutine optimizer_initialize(this, problem, design, simulation)
142 class(optimizer_t), intent(inout) :: this
143 class(problem_t), intent(inout) :: problem
144 class(design_t), intent(inout) :: design
145 type(simulation_t), optional, intent(inout) :: simulation
146 end subroutine optimizer_initialize
147
149 subroutine optimizer_free(this)
150 import optimizer_t
151 class(optimizer_t), intent(inout) :: this
152 end subroutine optimizer_free
153
155 logical function optimizer_step(this, iter, problem, design, simulation)
157 class(optimizer_t), intent(inout) :: this
158 integer, intent(in) :: iter
159 class(problem_t), intent(inout) :: problem
160 class(design_t), intent(inout) :: design
161 type(simulation_t), optional, intent(inout) :: simulation
162 end function optimizer_step
163
165 subroutine optimizer_validate(this, problem, design)
167 class(optimizer_t), intent(inout) :: this
168 class(problem_t), intent(in) :: problem
169 class(design_t), intent(in) :: design
170 end subroutine optimizer_validate
171
173 subroutine optimizer_write(this, iter, problem)
175 class(optimizer_t), intent(inout) :: this
176 integer, intent(in) :: iter
177 class(problem_t), intent(in) :: problem
178 end subroutine optimizer_write
179
181 subroutine optimizer_save_checkpoint_components(this, filename, overwrite)
182 import optimizer_t
183 class(optimizer_t), intent(inout) :: this
184 character(len=*), intent(in) :: filename
185 logical, intent(in), optional :: overwrite
186 end subroutine optimizer_save_checkpoint_components
187
189 subroutine optimizer_load_checkpoint_components(this, filename)
190 import optimizer_t
191 class(optimizer_t), intent(inout) :: this
192 character(len=*), intent(in) :: filename
193 end subroutine optimizer_load_checkpoint_components
194
195 end interface
196
197 ! -------------------------------------------------------------------------- !
198 ! Interfaces for the factory functions
199
207 module subroutine optimizer_factory(object, parameters, problem, design, &
208 simulation)
209 class(optimizer_t), allocatable, intent(inout) :: object
210 type(json_file), intent(inout) :: parameters
211 class(problem_t), intent(inout) :: problem
212 class(design_t), intent(in) :: design
213 type(simulation_t), optional, intent(in) :: simulation
214 end subroutine optimizer_factory
215 end interface optimizer_factory
216
217 ! -------------------------------------------------------------------------- !
218 ! IO routines for HDF5 checkpoints
219
220 interface
221
222 module subroutine optimizer_save_checkpoint_hdf5(object, filename, iter, &
223 overwrite)
224 class(optimizer_t), intent(inout) :: object
225 character(len=*), intent(in) :: filename
226 integer, intent(in) :: iter
227 logical, intent(in), optional :: overwrite
228 end subroutine optimizer_save_checkpoint_hdf5
229
231 module subroutine optimizer_load_checkpoint_hdf5(object, filename, iter)
232 class(optimizer_t), intent(inout) :: object
233 character(len=*), intent(in) :: filename
234 integer, intent(out) :: iter
235 end subroutine optimizer_load_checkpoint_hdf5
236 end interface
237
238 public :: optimizer_factory
239
240contains
241
242 ! -------------------------------------------------------------------------- !
243 ! Base initializer and free routines
244
250 subroutine optimizer_init_base(this, optimizer_type, max_iterations, &
251 max_runtime)
252 class(optimizer_t), intent(inout) :: this
253 character(len=*), intent(in) :: optimizer_type
254 integer, intent(in) :: max_iterations
255 real(kind=rp), intent(in), optional :: max_runtime
256
257 ! Mandatory settings
258 this%optimizer_type = optimizer_type
259 this%max_iterations = max_iterations
260
261 ! Optional settings
262 if (present(max_runtime)) this%max_runtime = max_runtime
263
264 ! Initialize internals
265 this%start_time = mpi_wtime()
266
267 end subroutine optimizer_init_base
268
271 subroutine optimizer_free_base(this)
272 class(optimizer_t), intent(inout) :: this
273
274 this%optimizer_type = ''
275 this%max_iterations = 0
276 this%max_runtime = -1.0_rp
277
278 this%start_time = 0.0_rp
279 this%current_iteration = 0
280
281 end subroutine optimizer_free_base
282
283 ! -------------------------------------------------------------------------- !
284 ! Optimization loop routine
285
298 subroutine optimizer_run(this, problem, design, simulation)
299 class(optimizer_t), intent(inout) :: this
300 class(problem_t), intent(inout) :: problem
301 class(design_t), intent(inout) :: design
302 type(simulation_t), optional, intent(inout) :: simulation
303 real(kind=rp) :: iteration_time
304 logical :: converged, file_exists
305 integer :: stop_flag
306
307 ! Initialize variables
308 stop_flag = 1
309 converged = .false.
310
311 ! Restart from checkpoint if available
312 if (this%max_runtime .gt. 0.0_rp) then
313 inquire(file = 'optimizer_rt_checkpoint.hdf5', exist = file_exists)
314 if (file_exists) then
315 call this%load_checkpoint('optimizer_rt_checkpoint.hdf5', &
316 this%current_iteration, design)
317
318 write(*, '(A,I0)') 'Loaded runtime checkpoint: ', &
319 this%current_iteration
320 end if
321 end if
322
323 ! Prepare the problem state before starting the optimization
324 call this%initialize(problem, design, simulation)
325
326 call this%write(this%current_iteration, problem)
327 call design%write(this%current_iteration)
328
329 call neko_log%section('Optimization Loop')
330
331 do while (this%current_iteration .lt. this%max_iterations)
332 this%current_iteration = this%current_iteration + 1
333 call profiler_start_region('Optimizer iteration')
334 iteration_time = mpi_wtime()
335
336 converged = this%step(this%current_iteration, problem, design, &
337 simulation)
338
339 iteration_time = mpi_wtime() - iteration_time
340 call profiler_end_region('Optimizer iteration')
341
342 ! Log the progress and outputs
343 call this%write(this%current_iteration, problem)
344 call design%write(this%current_iteration)
345
346 ! --------------------------------------------------------------------- !
347 ! Check stopping criteria
348
349 if (converged) then
350 stop_flag = 0
351 exit
352 else if (this%out_of_time(iteration_time)) then
353 call this%save_checkpoint('optimizer_rt_checkpoint.hdf5', &
354 this%current_iteration, design, .true.)
355 stop_flag = 2
356 exit
357 end if
358 end do
359
360 ! Check that the final design is valid
361 call this%validate(problem, design)
362 call this%print_status(stop_flag, this%current_iteration)
363
364 call neko_log%end_section()
365
366 end subroutine optimizer_run
367
368 ! ========================================================================== !
369 ! Helper routines
370
380 subroutine optimizer_print_status(this, stop_flag, iter)
381 class(optimizer_t), intent(in) :: this
382 integer, intent(in) :: stop_flag
383 integer, intent(in) :: iter
384 character(len=256) :: msg
385
386 select case (stop_flag)
387 case (0)
388 write(msg, '(A,I0,A)') 'Optimizer converged successfully after ', &
389 iter, ' iterations.'
390 call neko_log%message(msg)
391 case (1)
392 write(msg, '(A,I0,A)') 'Optimizer did not converge in ', &
393 this%max_iterations, ' iterations.'
394 call neko_log%warning(msg)
395 case (2)
396 write(msg, '(A,A,F8.2,A)') 'Optimizer stopped after reaching the ', &
397 'maximum runtime of ', this%max_runtime, ' seconds.'
398 call neko_error(trim(msg))
399
400 case default
401 write(msg, '(A)') 'Optimizer stopped for an unknown reason.'
402 call neko_error(msg)
403 end select
404 end subroutine optimizer_print_status
405
412 function optimizer_out_of_time(this, step_time) result(out_of_time)
413 class(optimizer_t), intent(inout) :: this
414 real(kind=rp), intent(in) :: step_time
415 logical :: out_of_time
416 real(kind=rp) :: elapsed_time, old_avg_weight
417
418 out_of_time = .false.
419
420 if (this%max_runtime .lt. 0.0_rp) then
421 return
422 end if
423
424 elapsed_time = mpi_wtime() - this%start_time
425 this%step_count = this%step_count + 1.0_rp
426 old_avg_weight = (this%step_count - 1) / this%step_count
427
428 ! Estimate Cumulative Average iteration time
429 this%average_time = step_time / this%step_count + &
430 this%average_time * old_avg_weight
431
432 ! Determine if next iteration would exceed max runtime
433 out_of_time = (elapsed_time + this%average_time) .gt. this%max_runtime
434
435 end function optimizer_out_of_time
436
437 ! ========================================================================== !
438 ! IO Functions
439
446 subroutine optimizer_save_checkpoint(this, filename, iter, design, overwrite)
447 class(optimizer_t), intent(inout) :: this
448 character(len=*), intent(in) :: filename
449 integer, intent(in) :: iter
450 class(design_t), intent(inout) :: design
451 logical, intent(in), optional :: overwrite
452 character(len=12) :: file_ext
453
454 ! Get the file extension
455 call filename_suffix(filename, file_ext)
456
457 select case (trim(file_ext))
458 case ('h5', 'hdf5', 'hf5')
459 call optimizer_save_checkpoint_hdf5(this, filename, iter, overwrite)
460 case default
461 call neko_error('optimizer: Unsupported checkpoint format: ' // &
462 trim(file_ext))
463 end select
464
465 call this%save_checkpoint_components(filename, overwrite)
466 call design%save_checkpoint(filename, overwrite)
467
468 end subroutine optimizer_save_checkpoint
469
475 subroutine optimizer_load_checkpoint(this, filename, iter, design)
476 class(optimizer_t), intent(inout) :: this
477 character(len=*), intent(in) :: filename
478 integer, intent(out) :: iter
479 class(design_t), intent(inout) :: design
480 character(len=12) :: file_ext
481
482 ! Get the file extension
483 call filename_suffix(filename, file_ext)
484
485 select case (trim(file_ext))
486 case ('h5', 'hdf5', 'hf5')
487 call optimizer_load_checkpoint_hdf5(this, filename, iter)
488 case default
489 call neko_error('optimizer: Unsupported checkpoint format: ' // &
490 trim(file_ext))
491 end select
492
493 call this%load_checkpoint_components(filename)
494 call design%load_checkpoint(filename)
495
496 end subroutine optimizer_load_checkpoint
497
498 ! ========================================================================== !
499 ! Dummy implementations for module procedures
500
501#if !HAVE_HDF5
502 module subroutine optimizer_save_checkpoint_hdf5(object, filename, iter, &
503 overwrite)
504 class(optimizer_t), intent(inout) :: object
505 character(len=*), intent(in) :: filename
506 integer, intent(in) :: iter
507 logical, intent(in), optional :: overwrite
508 call neko_error('optimizer: HDF5 support not enabled rebuild with ' // &
509 'HAVE_HDF5')
510 end subroutine optimizer_save_checkpoint_hdf5
511
512 module subroutine optimizer_load_checkpoint_hdf5(object, filename, iter)
513 class(optimizer_t), intent(inout) :: object
514 character(len=*), intent(in) :: filename
515 integer, intent(out) :: iter
516 call neko_error('optimizer: HDF5 support not enabled rebuild with ' // &
517 'HAVE_HDF5')
518 end subroutine optimizer_load_checkpoint_hdf5
519#endif
520
521end module optimizer
Factory function for the optimizer.
Interface for optimizer initialization.
Implements the design_t.
Definition design.f90:36
Defines the abstract type optimizer The optimizer type is defined to provide a generic interface to u...
Definition optimizer.f90:39
Module for handling the optimization problem.
Definition problem.f90:41
Implements the steady_problem_t type.
An abstract design type.
Definition design.f90:54
Abstract optimizer class.
Definition optimizer.f90:54
The abstract problem type.
Definition problem.f90:67