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
41 use json_module, only: json_file
42 use simulation_m, only: simulation_t
43 use problem, only: problem_t
44 use design, only: design_t
45 use num_types, only: rp
46 use logger, only: neko_log, log_size
47 use profiler, only: profiler_start_region, profiler_end_region
48 use mpi_f08, only: mpi_wtime, mpi_allreduce, mpi_max
49 use utils, only: neko_error, filename_suffix, read_duration
50 use csv_file, only: csv_file_t
51 use vector, only: vector_t
52 use json_utils, only: json_get_or_default
53 use comm, only: pe_rank, mpi_real_precision, neko_comm
54 use continuation_scheduler, only: nekotop_continuation
55
56 implicit none
57 private
58
60 type, abstract, public :: optimizer_t
61
63 character(len=64), private :: optimizer_type = ''
65 integer, private :: max_iterations = 0
67 integer, private :: current_iteration = 0
68
69 ! ----------------------------------------------------------------------- !
70 ! Restart related members
71
73 character(len=256), private :: checkpoint_file = ''
74
75 ! Checkpoint related information
76 character(len=256), private :: checkpoint_path = './checkpoints/'
77 character(len=256), private :: checkpoint_base = 'optimizer_checkpoint'
78 character(len=256), private :: checkpoint_format = 'hdf5'
79 integer, private :: checkpoint_interval = -1
80
81 ! Variables for the runtime-based stopping criteria
82 real(kind=rp), private :: max_runtime = -1.0_rp
83 real(kind=rp), private :: start_time = 0.0_rp
84 real(kind=rp), private :: average_time = 0.0_rp
85 real(kind=rp), private :: step_count = 0.0_rp
86 ! Logging state
87 logical, private :: log_initialized = .false.
88 logical, private :: log_include_constraints = .true.
89 integer, private :: log_extra_size = 0
90 type(csv_file_t), private :: log_file
91 type(vector_t), private :: log_data
92
93 contains
94
95 ! ---------------------------------------------------------------------- !
96 ! Deferred procedures for specific optimizers
97
99 procedure(optimizer_init_from_json), pass(this), public, deferred :: &
100 init_from_json
102 procedure(optimizer_free), pass(this), public, deferred :: free
103
105 procedure(optimizer_initialize), pass(this), public, deferred :: initialize
107 procedure(optimizer_step), pass(this), public, deferred :: step
109 procedure(optimizer_validate), pass(this), public, deferred :: validate
110
112 procedure(optimizer_write), pass(this), public, deferred :: write
114 procedure(optimizer_save_checkpoint_components), pass(this), deferred :: &
115 save_checkpoint_components
117 procedure(optimizer_load_checkpoint_components), pass(this), deferred :: &
118 load_checkpoint_components
119
121 procedure, pass(this) :: save_checkpoint => optimizer_save_checkpoint
123 procedure, pass(this) :: load_checkpoint => optimizer_load_checkpoint
124
125 ! ----------------------------------------------------------------------- !
126 ! Public procedures
127
129 procedure, pass(this), public :: run => optimizer_run
130
131 ! ----------------------------------------------------------------------- !
132 ! Private procedures
133
135 procedure, pass(this) :: init_base => optimizer_init_base
137 procedure, pass(this) :: free_base => optimizer_free_base
139 procedure, pass(this) :: read_base_settings => optimizer_read_base_settings
141 procedure, pass(this) :: print_status => optimizer_print_status
143 procedure, pass(this) :: out_of_time => optimizer_out_of_time
145 procedure, pass(this) :: init_log => optimizer_init_log
147 procedure, pass(this) :: write_log => optimizer_write_log
148 end type optimizer_t
149
150 ! -------------------------------------------------------------------------- !
151 ! Interface for the optimizer module.
152
153 abstract interface
154
155 subroutine optimizer_init_from_json(this, parameters, problem, design, &
156 simulation)
157 import optimizer_t, json_file, simulation_t, problem_t, design_t, rp
158 class(optimizer_t), intent(inout) :: this
159 type(json_file), intent(inout) :: parameters
160 class(problem_t), intent(inout) :: problem
161 class(design_t), intent(in) :: design
162 type(simulation_t), optional, intent(in) :: simulation
163 end subroutine optimizer_init_from_json
164
168 subroutine optimizer_initialize(this, problem, design, simulation)
170 class(optimizer_t), intent(inout) :: this
171 class(problem_t), intent(inout) :: problem
172 class(design_t), intent(inout) :: design
173 type(simulation_t), optional, intent(inout) :: simulation
174 end subroutine optimizer_initialize
175
177 subroutine optimizer_free(this)
178 import optimizer_t
179 class(optimizer_t), intent(inout) :: this
180 end subroutine optimizer_free
181
183 logical function optimizer_step(this, iter, problem, design, simulation)
185 class(optimizer_t), intent(inout) :: this
186 integer, intent(in) :: iter
187 class(problem_t), intent(inout) :: problem
188 class(design_t), intent(inout) :: design
189 type(simulation_t), optional, intent(inout) :: simulation
190 end function optimizer_step
191
193 subroutine optimizer_validate(this, problem, design)
195 class(optimizer_t), intent(inout) :: this
196 class(problem_t), intent(in) :: problem
197 class(design_t), intent(in) :: design
198 end subroutine optimizer_validate
199
201 subroutine optimizer_write(this, iter, problem)
203 class(optimizer_t), intent(inout) :: this
204 integer, intent(in) :: iter
205 class(problem_t), intent(inout) :: problem
206 end subroutine optimizer_write
207
209 subroutine optimizer_save_checkpoint_components(this, filename, overwrite)
210 import optimizer_t
211 class(optimizer_t), intent(inout) :: this
212 character(len=*), intent(in) :: filename
213 logical, intent(in), optional :: overwrite
214 end subroutine optimizer_save_checkpoint_components
215
217 subroutine optimizer_load_checkpoint_components(this, filename)
218 import optimizer_t
219 class(optimizer_t), intent(inout) :: this
220 character(len=*), intent(in) :: filename
221 end subroutine optimizer_load_checkpoint_components
222
223 end interface
224
225 ! -------------------------------------------------------------------------- !
226 ! Interfaces for the factory functions
227
235 module subroutine optimizer_factory(object, parameters, problem, design, &
236 simulation)
237 class(optimizer_t), allocatable, intent(inout) :: object
238 type(json_file), intent(inout) :: parameters
239 class(problem_t), intent(inout) :: problem
240 class(design_t), intent(in) :: design
241 type(simulation_t), optional, intent(in) :: simulation
242 end subroutine optimizer_factory
243 end interface optimizer_factory
244
245 ! -------------------------------------------------------------------------- !
246 ! IO routines for HDF5 checkpoints
247
248 interface
249
250 module subroutine optimizer_save_checkpoint_hdf5(object, filename, iter, &
251 overwrite)
252 class(optimizer_t), intent(inout) :: object
253 character(len=*), intent(in) :: filename
254 integer, intent(in) :: iter
255 logical, intent(in), optional :: overwrite
256 end subroutine optimizer_save_checkpoint_hdf5
257
259 module subroutine optimizer_load_checkpoint_hdf5(object, filename, iter)
260 class(optimizer_t), intent(inout) :: object
261 character(len=*), intent(in) :: filename
262 integer, intent(out) :: iter
263 end subroutine optimizer_load_checkpoint_hdf5
264 end interface
265
266 public :: optimizer_factory
267
268contains
269
270 ! -------------------------------------------------------------------------- !
271 ! Base initializer and free routines
272
284 subroutine optimizer_init_base(this, optimizer_type, max_iterations, &
285 max_runtime, checkpoint_file, checkpoint_path, checkpoint_base, &
286 checkpoint_format, checkpoint_interval)
287 class(optimizer_t), intent(inout) :: this
288 character(len=*), intent(in) :: optimizer_type
289 integer, intent(in) :: max_iterations
290 real(kind=rp), intent(in), optional :: max_runtime
291 character(len=*), intent(in), optional :: checkpoint_file
292 character(len=*), intent(in), optional :: checkpoint_path
293 character(len=*), intent(in), optional :: checkpoint_base
294 character(len=*), intent(in), optional :: checkpoint_format
295 integer, intent(in), optional :: checkpoint_interval
296
297 ! Mandatory settings
298 this%optimizer_type = optimizer_type
299 this%max_iterations = max_iterations
300
301 ! Optional settings
302 if (present(max_runtime)) this%max_runtime = max_runtime
303 if (present(checkpoint_file)) this%checkpoint_file = checkpoint_file
304 if (present(checkpoint_path)) this%checkpoint_path = checkpoint_path
305 if (present(checkpoint_base)) this%checkpoint_base = checkpoint_base
306 if (present(checkpoint_format)) this%checkpoint_format = checkpoint_format
307 if (present(checkpoint_interval)) then
308 this%checkpoint_interval = checkpoint_interval
309 end if
310
311 ! Initialize internals
312 this%start_time = mpi_wtime()
313
314 end subroutine optimizer_init_base
315
318 subroutine optimizer_free_base(this)
319 class(optimizer_t), intent(inout) :: this
320
321 this%optimizer_type = ''
322 this%max_iterations = 0
323 this%max_runtime = -1.0_rp
324 this%checkpoint_file = ''
325 this%checkpoint_path = './checkpoints/'
326 this%checkpoint_base = 'optimizer_checkpoint'
327 this%checkpoint_format = 'hdf5'
328 this%checkpoint_interval = -1
329
330 this%start_time = 0.0_rp
331 this%current_iteration = 0
332 call this%log_data%free()
333 this%log_initialized = .false.
334 this%log_extra_size = 0
335 this%log_include_constraints = .true.
336
337 end subroutine optimizer_free_base
338
342 subroutine optimizer_read_base_settings(this, solver_params)
343 class(optimizer_t), intent(inout) :: this
344 type(json_file), intent(inout) :: solver_params
345 integer :: read_int
346 character(len=:), allocatable :: read_str
347
348 call json_get_or_default(solver_params, 'max_runtime', read_str, "")
349 call read_duration(read_str, this%max_runtime)
350
351 call json_get_or_default(solver_params, 'restart_file', read_str, &
352 this%checkpoint_file)
353 this%checkpoint_file = read_str
354
355 call json_get_or_default(solver_params, 'checkpoint.path', read_str, &
356 this%checkpoint_path)
357 this%checkpoint_path = read_str
358 call json_get_or_default(solver_params, 'checkpoint.base', read_str, &
359 this%checkpoint_base)
360 this%checkpoint_base = read_str
361 call json_get_or_default(solver_params, 'checkpoint.format', read_str, &
362 this%checkpoint_format)
363 this%checkpoint_format = read_str
364 call json_get_or_default(solver_params, 'checkpoint.interval', read_int, &
365 this%checkpoint_interval)
366 this%checkpoint_interval = read_int
367
368 end subroutine optimizer_read_base_settings
369
370 ! -------------------------------------------------------------------------- !
371 ! Optimization loop routine
372
385 subroutine optimizer_run(this, problem, design, simulation)
386 class(optimizer_t), intent(inout) :: this
387 class(problem_t), intent(inout) :: problem
388 class(design_t), intent(inout) :: design
389 type(simulation_t), optional, intent(inout) :: simulation
390 real(kind=rp) :: iteration_time
391 character(len=1024) :: checkpoint_file
392 logical :: converged, file_exists
393 integer :: stop_flag
394
395 ! Initialize variables
396 stop_flag = 1
397 converged = .false.
398
399 ! Restart from checkpoint if available
400 if (trim(this%checkpoint_file) .ne. '') then
401 checkpoint_file = trim(this%checkpoint_file)
402 else
403 select case (trim(this%checkpoint_format))
404 case ('h5', 'hdf5', 'hf5', 'hdf')
405 checkpoint_file = trim(this%checkpoint_path) // &
406 'optimizer_rt_checkpoint.h5'
407 end select
408 end if
409
410 inquire(file = checkpoint_file, exist = file_exists)
411 if (file_exists) then
412 call this%load_checkpoint(checkpoint_file, this%current_iteration, &
413 design)
414 end if
415
416 ! compute potential internals for for a potential restart
417 if (this%current_iteration .ne. 0) then
418 call design%set_output_counter(this%current_iteration - 1)
419 if (present(simulation)) then
420 call simulation%set_output_counter(this%current_iteration - 1)
421 end if
422 end if
423
424 ! Prepare the problem state before starting the optimization
425 call this%initialize(problem, design, simulation)
426
427 call this%write(this%current_iteration, problem)
428 call design%write(this%current_iteration)
429
430 call neko_log%section('Optimization Loop')
431
432 do while (this%current_iteration .lt. this%max_iterations)
433 this%current_iteration = this%current_iteration + 1
434 if (pe_rank .eq. 0) then
435 write(*,*) 'Starting iteration ', this%current_iteration
436 end if
437
438 call profiler_start_region('Optimizer iteration')
439 iteration_time = mpi_wtime()
440
441 ! Update the parameters in continuation scheduler
442 call nekotop_continuation%update(this%current_iteration)
443
444 converged = this%step(this%current_iteration, problem, design, &
445 simulation)
446
447 iteration_time = mpi_wtime() - iteration_time
448 call profiler_end_region('Optimizer iteration')
449
450 ! Log the progress and outputs
451 call this%write(this%current_iteration, problem)
452 call design%write(this%current_iteration)
453
454 ! Save checkpoint if enabled
455 if (this%checkpoint_interval .gt. 0 .and. &
456 mod(this%current_iteration, this%checkpoint_interval) == 0) then
457 call this%save_checkpoint(this%current_iteration, design, .false.)
458 end if
459
460 ! --------------------------------------------------------------------- !
461 ! Check stopping criteria
462
463 if (converged) then
464 stop_flag = 0
465 exit
466 else if (this%out_of_time(iteration_time)) then
467 call this%save_checkpoint(this%current_iteration, design, .true., &
468 basename = 'optimizer_rt_checkpoint')
469 stop_flag = 2
470 exit
471 end if
472 end do
473
474 ! Check that the final design is valid
475 call this%validate(problem, design)
476 call this%print_status(stop_flag, this%current_iteration)
477
478 call neko_log%end_section()
479
480 end subroutine optimizer_run
481
482 ! ========================================================================== !
483 ! Helper routines
484
494 subroutine optimizer_print_status(this, stop_flag, iter)
495 class(optimizer_t), intent(in) :: this
496 integer, intent(in) :: stop_flag
497 integer, intent(in) :: iter
498 character(len=256) :: msg
499
500 select case (stop_flag)
501 case (0)
502 write(msg, '(A,I0,A)') 'Optimizer converged successfully after ', &
503 iter, ' iterations.'
504 call neko_log%message(msg)
505 case (1)
506 write(msg, '(A,I0,A)') 'Optimizer did not converge in ', &
507 this%max_iterations, ' iterations.'
508 call neko_log%warning(msg)
509 case (2)
510 write(msg, '(A,A,F8.2,A)') 'Optimizer stopped after reaching the ', &
511 'maximum runtime of ', this%max_runtime, ' seconds.'
512 call neko_error(trim(msg))
513
514 case default
515 write(msg, '(A)') 'Optimizer stopped for an unknown reason.'
516 call neko_error(msg)
517 end select
518 end subroutine optimizer_print_status
519
526 function optimizer_out_of_time(this, step_time) result(out_of_time)
527 class(optimizer_t), intent(inout) :: this
528 real(kind=rp), intent(in) :: step_time
529 logical :: out_of_time
530 real(kind=rp) :: elapsed_time, time, old_avg_weight
531
532 out_of_time = .false.
533
534 if (this%max_runtime .lt. 0.0_rp) then
535 return
536 end if
537
538 call mpi_allreduce(step_time, time, 1, mpi_real_precision, mpi_max, &
539 neko_comm)
540
541 elapsed_time = mpi_wtime() - this%start_time
542 this%step_count = this%step_count + 1.0_rp
543 old_avg_weight = (this%step_count - 1) / this%step_count
544
545 ! Estimate Cumulative Average iteration time
546 this%average_time = time / this%step_count + &
547 this%average_time * old_avg_weight
548
549 ! Determine if next iteration would exceed max runtime
550 out_of_time = (elapsed_time + this%average_time) .gt. this%max_runtime
551
552 end function optimizer_out_of_time
553
554 ! ========================================================================== !
555 ! Logging helpers
556
563 subroutine optimizer_init_log(this, problem, extra_headers, &
564 include_constraints, filename)
565 class(optimizer_t), intent(inout) :: this
566 class(problem_t), intent(in) :: problem
567 character(len=*), intent(in), optional :: extra_headers(:)
568 logical, intent(in), optional :: include_constraints
569 character(len=*), intent(in), optional :: filename
570
571 character(len=4096) :: header
572 integer :: total_size, base_size, i, n_cont
573 character(len=256) :: log_name
574
575 if (present(include_constraints)) then
576 this%log_include_constraints = include_constraints
577 end if
578 n_cont = nekotop_continuation%get_n_params()
579
580 base_size = problem%get_log_size(this%log_include_constraints)
581
582 this%log_extra_size = 0
583 if (present(extra_headers)) this%log_extra_size = size(extra_headers)
584
585 total_size = 1 + base_size + this%log_extra_size + n_cont
586 call this%log_data%init(total_size)
587
588 if (present(filename)) then
589 log_name = trim(filename)
590 else
591 log_name = 'optimization_data.csv'
592 end if
593
594 call this%log_file%init(trim(log_name))
595
596 header = 'iter, ' // &
597 trim(problem%get_log_header(this%log_include_constraints))
598 if (present(extra_headers)) then
599 do i = 1, size(extra_headers)
600 if (trim(extra_headers(i)) .eq. '') then
601 call neko_error('some headers are empty')
602 end if
603 header = trim(header) // ', ' // trim(extra_headers(i))
604 end do
605 end if
606
607 ! continuation parameters
608 do i = 1, n_cont
609 header = trim(header) // ', ' // &
610 trim(nekotop_continuation%get_param_name(i))
611 end do
612 call this%log_file%set_header(trim(header))
613
614 this%log_initialized = .true.
615 end subroutine optimizer_init_log
616
622 subroutine optimizer_write_log(this, iter, problem, extra_values)
623 class(optimizer_t), intent(inout) :: this
624 integer, intent(in) :: iter
625 class(problem_t), intent(in) :: problem
626 real(kind=rp), intent(in), optional :: extra_values(:)
627 integer :: base_size, offset, n_cont, i
628
629 if (.not. this%log_initialized) return
630
631 ! Number of continuation parameters
632 n_cont = nekotop_continuation%get_n_params()
633
634 base_size = problem%get_log_size(this%log_include_constraints)
635 this%log_data%x(1) = real(iter, kind=rp)
636
637 call problem%get_log_values( &
638 this%log_data%x(2:1 + base_size), &
639 this%log_include_constraints)
640
641 offset = 2 + base_size
642 if (present(extra_values)) then
643 if (this%log_extra_size .eq. 0) then
644 call neko_error('got extra values but no headers')
645 end if
646 this%log_data%x(offset:offset + size(extra_values) - 1) = extra_values
647 end if
648
649 ! Continuation parameter values
650 do i = 1, n_cont
651 this%log_data%x(offset + size(extra_values) - 1 + i) = &
652 nekotop_continuation%params(i)%target
653 end do
654
655 call this%log_file%write(this%log_data)
656
657 end subroutine optimizer_write_log
658
659 ! ========================================================================== !
660 ! IO Functions
661
670 subroutine optimizer_save_checkpoint(this, iter, design, overwrite, &
671 path, basename, format)
672 class(optimizer_t), intent(inout) :: this
673 integer, intent(in) :: iter
674 class(design_t), intent(inout) :: design
675 logical, intent(in) :: overwrite
676 character(len=*), intent(in), optional :: path
677 character(len=*), intent(in), optional :: basename
678 character(len=*), intent(in), optional :: format
679 character(len=:), allocatable :: checkpoint_format
680 character(len=256) :: file_path, file_base, file_ext, file_full
681 character(len=LOG_SIZE) :: msg
682 real(kind=rp) :: t_start, t_total
683 logical :: exist
684
685 call neko_log%section('Optimizer checkpoint')
686 t_start = mpi_wtime()
687
688 ! Set default behaviour
689 file_path = trim(this%checkpoint_path)
690 file_base = trim(this%checkpoint_base)
691 checkpoint_format = trim(this%checkpoint_format)
692
693 ! Overwrite any user supplied components
694 if (present(path)) file_path = trim(path)
695 if (present(basename)) file_base = trim(basename)
696 if (present(format)) checkpoint_format = trim(format)
697
698 ! Make sure path is valid and exists
699 if (len_trim(file_path) .eq. 0) then
700 file_path = './'
701 else if (file_path(len_trim(file_path):len_trim(file_path)) .ne. '/') then
702 file_path = trim(file_path) // '/'
703 end if
704
705 inquire(file=file_path, exist=exist)
706 if (.not. exist) then
707 call execute_command_line('mkdir -p "' // trim(file_path) // '"')
708 end if
709
710 select case (trim(checkpoint_format))
711 case ('h5', 'hdf5', 'hf5', 'hdf')
712 file_ext = 'h5'
713 case default
714 call neko_error('optimizer: Unsupported checkpoint format: "' // &
715 trim(checkpoint_format) // '"')
716 end select
717
718 ! Construct the full filename based on overwrite flag
719 if (overwrite) then
720 write(file_full, '(4A)') &
721 trim(file_path), trim(file_base), ".", trim(file_ext)
722 else
723 write(file_full, '(3A,I5.5,2A)') &
724 trim(file_path), trim(file_base), "_", iter, ".", trim(file_ext)
725 end if
726
727 call neko_log%message('Save general optimizer components')
728 select case (trim(file_ext))
729 case ('h5', 'hdf5', 'hf5')
730 call optimizer_save_checkpoint_hdf5(this, file_full, iter, overwrite)
731 case default
732 call neko_error('optimizer: Unsupported checkpoint format: "' // &
733 trim(file_ext) // '"')
734 end select
735
736 call neko_log%message('Saving components of ' // this%optimizer_type)
737 call this%save_checkpoint_components(file_full, overwrite)
738
739 call neko_log%message('Save design checkpoint')
740 call design%save_checkpoint(file_full, overwrite)
741
742 t_total = mpi_wtime() - t_start
743 write(msg, '(A,F6.2)') "Checkpoint time: ", t_total
744 call neko_log%end_section(msg)
745
746 end subroutine optimizer_save_checkpoint
747
753 subroutine optimizer_load_checkpoint(this, filename, iter, design)
754 class(optimizer_t), intent(inout) :: this
755 character(len=*), intent(in) :: filename
756 integer, intent(out) :: iter
757 class(design_t), intent(inout) :: design
758 character(len=12) :: file_ext
759
760 ! Get the file extension
761 call filename_suffix(filename, file_ext)
762
763 select case (trim(file_ext))
764 case ('h5', 'hdf5', 'hf5')
765 call optimizer_load_checkpoint_hdf5(this, filename, iter)
766 case default
767 call neko_error('optimizer: Unsupported checkpoint format: "' // &
768 trim(file_ext) // '"')
769 end select
770
771 call this%load_checkpoint_components(filename)
772 call design%load_checkpoint(filename)
773
774 ! Set the current iteration to the loaded iteration
775 this%current_iteration = iter
776
777 if (pe_rank .eq. 0) then
778 write(*,*) 'Restarted simulation from checkpoint.'
779 write(*,*) ' Checkpoint file: "', trim(filename), '"'
780 write(*,*) ' Iteration : ', this%current_iteration
781 end if
782
783 end subroutine optimizer_load_checkpoint
784
785 ! ========================================================================== !
786 ! Dummy implementations for module procedures
787
788#if !HAVE_HDF5
789 module subroutine optimizer_save_checkpoint_hdf5(object, filename, iter, &
790 overwrite)
791 class(optimizer_t), intent(inout) :: object
792 character(len=*), intent(in) :: filename
793 integer, intent(in) :: iter
794 logical, intent(in), optional :: overwrite
795 call neko_error('optimizer: HDF5 support not enabled rebuild with ' // &
796 'HAVE_HDF5')
797 end subroutine optimizer_save_checkpoint_hdf5
798
799 module subroutine optimizer_load_checkpoint_hdf5(object, filename, iter)
800 class(optimizer_t), intent(inout) :: object
801 character(len=*), intent(in) :: filename
802 integer, intent(out) :: iter
803 call neko_error('optimizer: HDF5 support not enabled rebuild with ' // &
804 'HAVE_HDF5')
805 end subroutine optimizer_load_checkpoint_hdf5
806#endif
807
808end module optimizer
Factory function for the optimizer.
Interface for optimizer initialization.
Continuation scheduler for the optimization loop.
Implements the design_t.
Definition design.f90:36
Defines the abstract type optimizer.
Definition optimizer.f90:40
Module for handling the optimization problem.
Definition problem.f90:41
Implements the steady_problem_t type.
An abstract design type.
Definition design.f90:53
Abstract optimizer class.
Definition optimizer.f90:60
The abstract problem type.
Definition problem.f90:67