Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
simulation.f90
Go to the documentation of this file.
1
34!
36! Here, we simply march forward to steady state solutions
38 use case, only: case_t
39 use user_access_singleton, only: neko_user_access
40 use adjoint_case, only: adjoint_case_t
41 use fluid_scheme_incompressible, only: fluid_scheme_incompressible_t
42 use adjoint_fluid_scheme, only: adjoint_fluid_scheme_t
45 use scalars, only: scalars_t
46 use fluid_pnpn, only: fluid_pnpn_t
47 use time_step_controller, only: time_step_controller_t
48 use field_output, only: field_output_t
49 use simcomp_executor, only: neko_simcomps
50 use neko_ext, only: reset, reset_adjoint
51 use json_file_module, only: json_file
52 use json_utils, only: json_get, json_get_or_default
53 use num_types, only: rp, sp, dp
54 use mpi_f08, only: mpi_wtime
55 use profiler, only: profiler_start, profiler_stop, &
56 profiler_start_region, profiler_end_region
59 use simulation, only: simulation_init, simulation_step, simulation_finalize, &
60 simulation_restart
61 use state_recover, only: state_recover_t, state_recover_factory
62 use runtime_stats, only: neko_rt_stats
63 implicit none
64 private
65
67
69 type(case_t), public :: neko_case
71 type(adjoint_case_t), public :: adjoint_case
73 class(fluid_scheme_incompressible_t), public, pointer :: fluid => null()
75 type(scalars_t), public, pointer :: scalars => null()
77 class(adjoint_fluid_scheme_t), public, pointer :: adjoint_fluid => null()
79 type(adjoint_scalars_t), public, pointer :: adjoint_scalars => null()
82 type(field_output_t), public :: output_forward
85 type(field_output_t), public :: output_adjoint
89 character(len=:), allocatable :: forward_field_base_fname
93 character(len=:), allocatable :: adjoint_field_base_fname
97 integer :: current_design_iteration = 0
99 logical :: unsteady = .false.
100
101 logical :: have_scalar = .false.
102 integer :: n_timesteps = 0
103
104 ! ----------------------------------------------------------------------- !
105 ! State recovery system
106
108 class(state_recover_t), allocatable :: state_recover
109
110 contains
112 procedure, pass(this) :: init => simulation_initialize
114 procedure, pass(this) :: free => simulation_free
116 procedure, pass(this) :: run_forward => simulation_run_forward
118 procedure, pass(this) :: run_backward => simulation_run_backward
120 procedure, pass(this) :: reset => simulation_reset
122 procedure, pass(this) :: set_output_counter => &
123 simulation_set_output_counter
125 procedure, pass(this) :: set_design_iteration => &
126 simulation_set_design_iteration
128 procedure, pass(this) :: write => simulation_write
130 procedure, pass(this) :: write_forward => simulation_write_forward
132 procedure, pass(this) :: write_adjoint => simulation_write_adjoint
133
134 end type simulation_t
135 public :: simulation_t
136contains
137
139 subroutine simulation_initialize(this, parameters)
140 class(simulation_t), intent(inout), target :: this
141 type(json_file), intent(inout) :: parameters
142 type(json_file) :: state_recovery_params
143 integer :: i, n_scalars
144 character(len=:), allocatable :: output_directory, precision_s, file_format
145 integer :: precision
146 logical :: unsteady, subdivide
147
148 ! initialize the primal Neko objects
149 call this%neko_case%init(parameters)
150 call neko_user_access%init(this%neko_case)
151
152 call neko_rt_stats%init(parameters)
153 call neko_simcomps%init(this%neko_case)
154
155 ! initialize the adjoint
156 call this%adjoint_case%init(this%neko_case)
157
158 ! Capture Neko's own field output filenames before any design-iteration
159 ! tag ever gets spliced into them (see `reset`/`neko_ext::reset`).
160 this%forward_field_base_fname = &
161 trim(this%neko_case%f_out%file_%get_base_fname())
162 this%adjoint_field_base_fname = &
163 trim(this%adjoint_case%f_out%file_%get_base_fname())
164
165 ! Start the profiler
166 call profiler_start
167
168 select type (fluid => this%neko_case%fluid)
169 type is (fluid_pnpn_t)
170 this%fluid => fluid
171 end select
172
173 select type (adjoint_fluid => this%adjoint_case%fluid_adj)
174 type is (adjoint_fluid_pnpn_t)
175 this%adjoint_fluid => adjoint_fluid
176 end select
177
178 if (allocated(this%neko_case%scalars)) then
179 this%scalars => this%neko_case%scalars
180 end if
181
182 if (allocated(this%adjoint_case%adjoint_scalars)) then
183 this%adjoint_scalars => this%adjoint_case%adjoint_scalars
184 end if
185
186 !---------------------------------------------------------
187 ! Initialize the output types
188
189 ! Read settings for the output types, with some reasonable defaults
190 call json_get_or_default(parameters, 'case.output_directory', &
191 output_directory, '')
192 call json_get_or_default(parameters, 'case.output_precision', precision_s, &
193 'single')
194 call json_get_or_default(parameters, 'case.fluid.output_format', &
195 file_format, 'fld')
196 call json_get_or_default(parameters, 'case.fluid.output_subdivide', &
197 subdivide, .false.)
198
199 if (trim(precision_s) .eq. 'double') then
200 precision = dp
201 else
202 precision = sp
203 end if
204
205 ! Allocate the output type
206 n_scalars = 0
207 if (allocated(this%neko_case%scalars)) then
208 n_scalars = size(this%neko_case%scalars%scalar_fields)
209 end if
210 call this%output_forward%init('forward_fields', 4 + n_scalars, &
211 precision = precision, &
212 path = trim(output_directory), &
213 format = trim(file_format))
214 call this%output_forward%file_%set_subdivide(subdivide)
215
216 call this%output_forward%fields%assign(1, this%fluid%p)
217 call this%output_forward%fields%assign(2, this%fluid%u)
218 call this%output_forward%fields%assign(3, this%fluid%v)
219 call this%output_forward%fields%assign(4, this%fluid%w)
220
221 ! Assign all scalar fields
222 if (allocated(this%neko_case%scalars)) then
223 do i = 1, n_scalars
224 call this%output_forward%fields%assign(4 + i, &
225 this%scalars%scalar_fields(i)%scalar%s)
226 end do
227 end if
228
229 ! Read settings for the output types, with some reasonable defaults
230 call json_get_or_default(parameters, &
231 'case.adjoint_fluid.output_format', file_format, 'fld')
232 call json_get_or_default(parameters, &
233 'case.adjoint_fluid.output_subdivide', subdivide, .false.)
234
235 n_scalars = 0
236 if (allocated(this%adjoint_case%adjoint_scalars)) then
237 n_scalars = size(this%adjoint_case%adjoint_scalars%adjoint_scalar_fields)
238 end if
239 call this%output_adjoint%init('adjoint_fields', 4 + n_scalars, &
240 precision = precision, &
241 path = trim(output_directory), &
242 format = trim(file_format))
243 call this%output_adjoint%file_%set_subdivide(subdivide)
244
245 call this%output_adjoint%fields%assign(1, this%adjoint_fluid%p_adj)
246 call this%output_adjoint%fields%assign(2, this%adjoint_fluid%u_adj)
247 call this%output_adjoint%fields%assign(3, this%adjoint_fluid%v_adj)
248 call this%output_adjoint%fields%assign(4, this%adjoint_fluid%w_adj)
249
250 ! Assign all scalar fields
251 if (allocated(this%adjoint_case%adjoint_scalars)) then
252 do i = 1, n_scalars
253 call this%output_adjoint%fields%assign(4 + i, &
254 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj)
255 end do
256 end if
257
258 ! Check if the simulation is steady or unsteady
259 call json_get_or_default(parameters, "unsteady", unsteady, .false.)
260 this%unsteady = unsteady
261
262 ! State recovery is only needed for unsteady runs.
263 if (this%unsteady) then
264 call json_get(parameters, 'state_recovery', state_recovery_params)
265 call state_recover_factory(this%state_recover, this%neko_case, &
266 state_recovery_params)
267 end if
268
269
270 end subroutine simulation_initialize
271
273 subroutine simulation_free(this)
274 class(simulation_t), intent(inout) :: this
275
276 ! Stop the profiler
277 call profiler_stop
278
279 if (allocated(this%state_recover)) then
280 call this%state_recover%free()
281 deallocate(this%state_recover)
282 end if
283
284 ! Free the objects
285 call this%neko_case%free()
286 call this%adjoint_case%free()
287 call this%output_forward%free()
288 call this%output_adjoint%free()
289
290 ! Nullify pointers
291 nullify(this%fluid)
292 nullify(this%scalars)
293 nullify(this%adjoint_fluid)
294 nullify(this%adjoint_scalars)
295
296 ! Reset flags and counters
297 this%unsteady = .false.
298 this%have_scalar = .false.
299 this%n_timesteps = 0
300 this%current_design_iteration = 0
301 if (allocated(this%forward_field_base_fname)) then
302 deallocate(this%forward_field_base_fname)
303 end if
304 if (allocated(this%adjoint_field_base_fname)) then
305 deallocate(this%adjoint_field_base_fname)
306 end if
307
308 ! Close global objects
309 call neko_simcomps%free()
310
311 end subroutine simulation_free
312
314 subroutine simulation_run_forward(this)
315 class(simulation_t), intent(inout) :: this
316 type(time_step_controller_t) :: dt_controller
317 real(kind=dp) :: loop_start
318
319 call dt_controller%init(this%neko_case%params)
320
321 call this%neko_case%time%reset()
322 call simulation_init(this%neko_case, dt_controller)
323
324 call profiler_start_region("Forward simulation")
325 loop_start = mpi_wtime()
326 this%n_timesteps = 0
327 do while (.not. this%neko_case%time%is_done())
328 this%n_timesteps = this%n_timesteps + 1
329
330 call simulation_step(this%neko_case, dt_controller, loop_start)
331
332 if (this%unsteady) then
333 call this%state_recover%save()
334 end if
335 end do
336 call profiler_end_region("Forward simulation")
337
338 call simulation_finalize(this%neko_case)
339
340 end subroutine simulation_run_forward
341
343 subroutine simulation_run_backward(this)
344 class(simulation_t), intent(inout) :: this
345 type(time_step_controller_t) :: dt_controller
346 real(kind=dp) :: loop_start
347 real(kind=rp) :: cfl
348 integer :: i
349
350 call dt_controller%init(this%neko_case%params)
351
352 call simulation_adjoint_init(this%adjoint_case, dt_controller)
353
354 call profiler_start_region("Adjoint simulation")
355 cfl = this%adjoint_case%fluid_adj%compute_cfl(this%adjoint_case%time%dt)
356 loop_start = mpi_wtime()
357 do i = this%n_timesteps, 1, -1
358 if (this%unsteady) then
359 call this%state_recover%restore(i)
360 end if
361
362 call simulation_adjoint_step(this%adjoint_case, dt_controller, cfl, &
363 loop_start)
364 end do
365 call profiler_end_region("Adjoint simulation")
366
367 call simulation_adjoint_finalize(this%adjoint_case)
368
369 end subroutine simulation_run_backward
370
372 subroutine simulation_reset(this)
373 class(simulation_t), intent(inout) :: this
374
375 call reset(this%neko_case, this%current_design_iteration, &
376 this%forward_field_base_fname)
377 call reset_adjoint(this%adjoint_case, this%neko_case, &
378 this%current_design_iteration, this%adjoint_field_base_fname)
379 if (this%unsteady) then
380 call this%state_recover%reset()
381 end if
382
383 end subroutine simulation_reset
384
390 subroutine simulation_set_design_iteration(this, iteration)
391 class(simulation_t), intent(inout) :: this
392 integer, intent(in) :: iteration
393
394 this%current_design_iteration = iteration
395
396 end subroutine simulation_set_design_iteration
397
398 subroutine simulation_set_output_counter(this, idx)
399 class(simulation_t), intent(inout) :: this
400 integer, intent(in) :: idx
401
402 call this%output_forward%set_counter(idx)
403 call this%output_adjoint%set_counter(idx)
404
405 end subroutine simulation_set_output_counter
406
408 subroutine simulation_write(this, idx)
409 class(simulation_t), intent(inout) :: this
410 integer, intent(in) :: idx
411
412 call this%output_forward%sample(real(idx, kind=rp))
413 call this%output_adjoint%sample(real(idx, kind=rp))
414
415 end subroutine simulation_write
416
418 subroutine simulation_write_forward(this, idx)
419 class(simulation_t), intent(inout) :: this
420 integer, intent(in) :: idx
421
422 call this%output_forward%sample(real(idx, kind=rp))
423
424 end subroutine simulation_write_forward
425
427 subroutine simulation_write_adjoint(this, idx)
428 class(simulation_t), intent(inout) :: this
429 integer, intent(in) :: idx
430
431 call this%output_adjoint%sample(real(idx, kind=rp))
432
433 end subroutine simulation_write_adjoint
434
435end module simulation_m
Adjoint Pn/Pn formulation.
Contains the adjoint_scalars_t type that manages multiple scalar fields.
Contains extensions to the neko library required to run the topology optimization code.
Definition neko_ext.f90:42
subroutine, public reset(neko_case, design_iteration, output_base_fname)
Reset the case data structure.
Definition neko_ext.f90:96
subroutine, public reset_adjoint(adjoint_case, neko_case, design_iteration, output_base_fname)
Reset the adjoint case data structure.
Definition neko_ext.f90:273
Adjoint simulation driver.
subroutine, public simulation_adjoint_init(c, dt_controller)
Initialise a simulation_adjoint of a case.
subroutine, public simulation_adjoint_step(c, dt_controller, cfl, tstep_loop_start_time, final_time)
Compute a single time-step of an adjoint case.
subroutine, public simulation_adjoint_finalize(c)
Finalize a simulation of a case.
Implements the steady_problem_t type.
subroutine simulation_initialize(this, parameters)
Initialize the simulation.
Abstract interface for state recovery strategies.
Adjoint case type. Todo: This should Ideally be a subclass of case_t, however, that is not yet suppor...
Type to manage multiple adjoint scalar transport equations.
Abstract base type for state recovery implementations.