Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
neko_ext.f90
Go to the documentation of this file.
1
39
43 use case, only: case_t
44 use adjoint_case, only: adjoint_case_t
45 use json_utils, only: json_get, json_get_or_default
46 use num_types, only: rp
47 use simcomp_executor, only: neko_simcomps
48 use flow_ic, only: set_flow_ic
49 use scalar_ic, only: set_scalar_ic
50 use field, only: field_t
51 use chkp_output, only: chkp_output_t
52 use output_controller, only: output_controller_t
53 use math, only: copy
54 use device_math, only: device_copy
55 use neko_config, only : neko_bcknd_device
56 use vector, only: vector_t
57 use field, only: field_t
58 use utils, only: neko_error, filename_suffix_pos, filename_suffix
59 use json_module, only : json_file
60 use scalars, only: scalars_t
62 use field_math, only: field_rzero, field_copy
63 use fluid_pnpn, only: fluid_pnpn_t
65 use scalar_pnpn, only: scalar_pnpn_t
67
68 implicit none
69
70 ! ========================================================================= !
71 ! Module interface
72 ! ========================================================================= !
73 private
76
77contains
78
79 ! ========================================================================= !
80 ! Public routines
81 ! ========================================================================= !
82
97 subroutine reset(neko_case, design_iteration, output_base_fname)
98 type(case_t), intent(inout) :: neko_case
99 integer, intent(in) :: design_iteration
100 character(len=*), intent(in) :: output_base_fname
101 real(kind=rp) :: t
102 integer :: i
103 character(len=:), allocatable :: string_val
104 logical :: has_scalar, freezeflow
105 type(field_t), pointer :: u, v, w, p, s
106 type(json_file) :: json_subdict
107
108 ! ------------------------------------------------------------------------ !
109 ! Setup shorthand notation
110 ! ------------------------------------------------------------------------ !
111
112 u => neko_case%fluid%u
113 v => neko_case%fluid%v
114 w => neko_case%fluid%w
115 p => neko_case%fluid%p
116 if (allocated(neko_case%scalars)) then
117 s => neko_case%scalars%scalar_fields(1)%scalar%s
118 else
119 nullify(s)
120 end if
121
122 ! ------------------------------------------------------------------------ !
123 ! Reset the timing parameters
124 ! ------------------------------------------------------------------------ !
125
126 call neko_case%time%reset()
127 t = neko_case%time%start_time
128 do i = 1, size(neko_case%time%tlag)
129 neko_case%time%tlag(i) = t - i*neko_case%time%dtlag(i)
130 end do
131
132 ! Tag the field output filename with the design iteration, so this
133 ! iteration's forward field output does not overwrite the previous one.
134 ! Calling the base `generic_file_t%init` directly (rather than the
135 ! reallocating `file_t%init` wrapper) only touches the filename and
136 ! write counter, leaving the case-file-configured precision/layout/
137 ! subdivide/overwrite settings on the underlying `fld_file_t` untouched.
138 call neko_case%f_out%file_%file_type%init( &
139 trim(design_iteration_fname(output_base_fname, design_iteration)))
140
141 ! Reset the time step counter
142 call neko_case%output_controller%set_counter(neko_case%time)
143
144 ! Keep per-design-iteration output numbering anchored at 0.
145 ! output_controller%set_counter sets start_counter based on controller
146 ! executions (typically 1 at reset), so override it for this stream.
147 call neko_case%f_out%set_start_counter(0)
148 call neko_case%f_out%set_counter(-1)
149
150 ! Restart the fields
151 call neko_case%fluid%restart(neko_case%chkp)
152 if (allocated(neko_case%scalars)) then
153 call neko_case%scalars%restart(neko_case%chkp)
154 end if
155
156 ! Reset the external BDF coefficients
157 do i = 1, size(neko_case%time%dtlag)
158 call neko_case%fluid%ext_bdf%set_coeffs(neko_case%time%dtlag)
159 end do
160
161 ! Restart the simulation components
162 call neko_simcomps%restart(neko_case%time)
163
164 ! ------------------------------------------------------------------------ !
165 ! Reset the fluid field to the initial condition
166 ! ------------------------------------------------------------------------ !
167
168 call json_get(neko_case%params, &
169 'case.fluid.initial_condition.type', string_val)
170 call json_get(neko_case%params, 'case.fluid.initial_condition', &
171 json_subdict)
172
173 ! Reset the fields. The ICs often assumes these are 0.
174 call field_rzero(p)
175 call field_rzero(u)
176 call field_rzero(v)
177 call field_rzero(w)
178
179 if (trim(string_val) .ne. 'user') then
180 call set_flow_ic(u, v, w, p, &
181 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
182 string_val, json_subdict)
183 else
184 call set_flow_ic(u, v, w, p, &
185 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
186 neko_case%user%initial_conditions, neko_case%fluid%name)
187 end if
188
189 ! set lags to IC
190 call neko_case%fluid%ulag%set(u)
191 call neko_case%fluid%vlag%set(v)
192 call neko_case%fluid%wlag%set(w)
193 ! zero out RHS etc
194 select type (f => neko_case%fluid)
195 type is (fluid_pnpn_t)
196 call field_rzero(f%abx1)
197 call field_rzero(f%aby1)
198 call field_rzero(f%abz1)
199 call field_rzero(f%abx2)
200 call field_rzero(f%aby2)
201 call field_rzero(f%abz2)
202 call field_copy(f%u_e, u)
203 call field_copy(f%v_e, v)
204 call field_copy(f%w_e, w)
205 end select
206 call field_rzero(neko_case%fluid%f_x)
207 call field_rzero(neko_case%fluid%f_y)
208 call field_rzero(neko_case%fluid%f_z)
209 ! ------------------------------------------------------------------------ !
210 ! Reset the scalar field to the initial condition
211 ! ------------------------------------------------------------------------ !
212
213 ! check for a single scalar
214 call json_get_or_default(neko_case%params, &
215 'case.scalar.enabled', has_scalar, .false.)
216
217 if (has_scalar) then
218 ! check for multiple scalars
219 if (size(neko_case%scalars%scalar_fields) .gt. 1) then
220 call neko_error('Multiple scalars not supported')
221 end if
222 ! zero out RHS
223 call field_rzero(neko_case%scalars%scalar_fields(1)%scalar%f_Xh)
224
225 ! zero out the Adams-Bashforth history, mirroring the fluid above.
226 select type (s_scheme => &
227 neko_case%scalars%scalar_fields(1)%scalar)
228 type is (scalar_pnpn_t)
229 call field_rzero(s_scheme%abx1)
230 call field_rzero(s_scheme%abx2)
231 end select
232
233 ! reset the forward scalar
234 call json_get(neko_case%params, &
235 'case.scalar.initial_condition.type', string_val)
236 call json_get(neko_case%params, &
237 'case.scalar.initial_condition', json_subdict)
238 if (trim(string_val) .ne. 'user') then
239 if (trim(neko_case%scalars%scalar_fields(1)%scalar%name) .eq. &
240 'temperature') then
241 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%s, &
242 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, string_val, &
243 json_subdict, 0)
244 else
245 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%s, &
246 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, string_val, &
247 json_subdict, 1)
248 end if
249 else
250 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%name, &
251 neko_case%scalars%scalar_fields(1)%scalar%s, &
252 neko_case%scalars%scalar_fields(1)%scalar%c_Xh, &
253 neko_case%scalars%scalar_fields(1)%scalar%gs_Xh, &
254 neko_case%user%initial_conditions)
255 end if
256 ! set lags to IC
257 call neko_case%scalars%scalar_fields(1)%scalar%slag%set(&
258 neko_case%scalars%scalar_fields(1)%scalar%s)
259 end if
260
261 ! ------------------------------------------------------------------------ !
262 ! Reset the "freeze" parameter of the flow
263 ! ------------------------------------------------------------------------ !
264
265 call json_get_or_default(neko_case%params, &
266 'case.fluid.freeze_flow', freezeflow, .false.)
267
268 neko_case%fluid%freeze = freezeflow
269
270 end subroutine reset
271
288 subroutine reset_adjoint(adjoint_case, neko_case, design_iteration, &
289 output_base_fname)
290 type(adjoint_case_t), intent(inout) :: adjoint_case
291 type(case_t), intent(inout) :: neko_case
292 integer, intent(in) :: design_iteration
293 character(len=*), intent(in) :: output_base_fname
294 real(kind=rp) :: t
295 integer :: i
296 character(len=:), allocatable :: string_val
297 logical :: has_scalar, freezeflow
298 type(field_t), pointer :: u_adj, v_adj, w_adj, p_adj, s_adj
299 type(json_file) :: json_subdict
300
301 ! ------------------------------------------------------------------------ !
302 ! Setup shorthand notation
303 ! ------------------------------------------------------------------------ !
304
305 u_adj => adjoint_case%fluid_adj%u_adj
306 v_adj => adjoint_case%fluid_adj%v_adj
307 w_adj => adjoint_case%fluid_adj%w_adj
308 p_adj => adjoint_case%fluid_adj%p_adj
309 if (allocated(adjoint_case%adjoint_scalars)) then
310 s_adj => adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj
311 else
312 nullify(s_adj)
313 end if
314
315 ! ------------------------------------------------------------------------ !
316 ! Reset the timing parameters
317 ! ------------------------------------------------------------------------ !
318
319 call adjoint_case%time%reset()
320 t = adjoint_case%time%start_time
321 do i = 1, size(adjoint_case%time%tlag)
322 adjoint_case%time%tlag(i) = t - i*adjoint_case%time%dtlag(i)
323 end do
324
325 ! Tag the field output filename with the design iteration, so this
326 ! iteration's adjoint field output does not overwrite the previous one.
327 ! See the equivalent call in `reset` for why the base
328 ! `generic_file_t%init` is called directly here.
329 call adjoint_case%f_out%file_%file_type%init( &
330 trim(design_iteration_fname(output_base_fname, design_iteration)))
331
332 ! Reset the time step counter
333 call adjoint_case%output_controller%set_counter(adjoint_case%time)
334 if (adjoint_case%norm_output_enabled) then
335 call adjoint_case%norm_output_ctrl%set_counter(adjoint_case%time)
336 end if
337
338 ! Keep per-design-iteration output numbering anchored at 0.
339 call adjoint_case%f_out%set_start_counter(0)
340 call adjoint_case%f_out%set_counter(-1)
341
342 ! Reset the external BDF coefficients
343 do i = 1, size(adjoint_case%time%dtlag)
344 call adjoint_case%fluid_adj%ext_bdf%set_coeffs(adjoint_case%time%dtlag)
345 end do
346
347 ! ------------------------------------------------------------------------ !
348 ! Reset the adjoint fluid to the initial (final) condition
349 ! ------------------------------------------------------------------------ !
350
351 ! don't fallback to the fluid here
352 call json_get(neko_case%params, &
353 'case.adjoint_fluid.initial_condition.type', string_val)
354 call json_get(neko_case%params, 'case.adjoint_fluid.initial_condition', &
355 json_subdict)
356
357 ! Zero the adjoint pressure first, for the same reason as in `reset`.
358 call field_rzero(p_adj)
359 call field_rzero(u_adj)
360 call field_rzero(v_adj)
361 call field_rzero(w_adj)
362
363 if (trim(string_val) .ne. 'user') then
364 call set_flow_ic(u_adj, v_adj, w_adj, p_adj, &
365 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
366 string_val, json_subdict)
367 else
368 call neko_error("adjoint user initial conditions not supported")
369 end if
370
371 ! set lags to IC
372 call adjoint_case%fluid_adj%ulag%set(u_adj)
373 call adjoint_case%fluid_adj%vlag%set(v_adj)
374 call adjoint_case%fluid_adj%wlag%set(w_adj)
375 ! zero out RHS etc
376 select type (f => adjoint_case%fluid_adj)
377 type is (adjoint_fluid_pnpn_t)
378 call field_rzero(f%abx1)
379 call field_rzero(f%aby1)
380 call field_rzero(f%abz1)
381 call field_rzero(f%abx2)
382 call field_rzero(f%aby2)
383 call field_rzero(f%abz2)
384 end select
385 ! zero out all lags etc
386 ! (not sure what to do with the abx's_adj)
387 call field_rzero(adjoint_case%fluid_adj%f_adj_x)
388 call field_rzero(adjoint_case%fluid_adj%f_adj_y)
389 call field_rzero(adjoint_case%fluid_adj%f_adj_z)
390 ! ------------------------------------------------------------------------ !
391 ! Reset the scalar field to the initial condition
392 ! ------------------------------------------------------------------------ !
393
394 ! check for a single scalar
395 call json_get_or_default(neko_case%params, 'case.scalar.enabled', &
396 has_scalar, .false.)
397
398 if (has_scalar) then
399 ! check for multiple adjoint_scalars
400 if (size(adjoint_case%adjoint_scalars%adjoint_scalar_fields) .gt. 1) then
401 call neko_error('Multiple adjoint scalars not supported')
402 end if
403 ! zero out lag terms
404 call field_rzero( &
405 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%f_Xh)
406
407 ! zero out the Adams-Bashforth history, mirroring the fluid above.
408 select type (s_scheme => &
409 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1))
410 type is (adjoint_scalar_pnpn_t)
411 call field_rzero(s_scheme%abx1)
412 call field_rzero(s_scheme%abx2)
413 end select
414
415 ! reset the forward scalar
416 call json_get(neko_case%params, &
417 'case.adjoint_scalar.initial_condition.type', string_val)
418 call json_get(neko_case%params, &
419 'case.adjoint_scalar.initial_condition', json_subdict)
420 if (trim(string_val) .ne. 'user') then
421 if (trim(neko_case%scalars%scalar_fields(1)%scalar%name) .eq. &
422 'temperature') then
423 call set_scalar_ic( &
424 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
425 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
426 string_val, json_subdict, 0)
427 else
428 call set_scalar_ic( &
429 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
430 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
431 string_val, json_subdict, 1)
432 end if
433 else
434 call neko_error("adjoint scalar user IC not supported")
435 end if
436 ! set lags to IC
437 call adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj_lag% &
438 set(adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj)
439 end if
440
441 ! ------------------------------------------------------------------------ !
442 ! Reset the "freeze" parameter of the flow
443 ! ------------------------------------------------------------------------ !
444
445 call json_get_or_default(neko_case%params, &
446 'case.adjoint_fluid.freeze_flow', freezeflow, .false.)
447
448 adjoint_case%fluid_adj%freeze = freezeflow
449
450 end subroutine reset_adjoint
451
459 subroutine vector_to_field(field, vector)
460 type(field_t), intent(inout) :: field
461 type(vector_t), intent(in) :: vector
462
463 ! first check they're the same size
464 if (field%size() .ne. vector%size()) then
465 call neko_error("vector and field are not the same size")
466 end if
467
468 if (neko_bcknd_device .eq. 1) then
469 call device_copy(field%x_d, vector%x_d, field%size())
470 else
471 call copy(field%x, vector%x, field%size())
472 end if
473
474 end subroutine vector_to_field
475
483 subroutine field_to_vector(vector, field)
484 type(vector_t), intent(inout) :: vector
485 type(field_t), intent(in) :: field
486
487 ! first check they're the same size
488 if (field%size() .ne. vector%size()) then
489 call neko_error("vector and field are not the same size")
490 end if
491
492 if (neko_bcknd_device .eq. 1) then
493 call device_copy(vector%x_d, field%x_d, field%size())
494 else
495 call copy(vector%x, field%x, field%size())
496 end if
497
498 end subroutine field_to_vector
499
508 subroutine get_scalar_indicies(i_primal, i_adjoint, scalars, &
509 adjoint_scalars, primal_name)
510 integer, intent(out) :: i_primal
511 integer, intent(out) :: i_adjoint
512 type(scalars_t), intent(inout) :: scalars
513 type(adjoint_scalars_t), intent(inout) :: adjoint_scalars
514 character(len=*), intent(in) :: primal_name
515 integer :: i, n_primal_scalars, n_adjoint_scalars
516
517 i_primal = -1
518 i_adjoint = -1
519 n_adjoint_scalars = size(adjoint_scalars%adjoint_scalar_fields)
520 n_primal_scalars = size(scalars%scalar_fields)
521
522 if ((n_adjoint_scalars .eq. 1) .and. (n_primal_scalars .eq. 1)) then
523 i_primal = 1
524 i_adjoint = 1
525 return
526 end if
527
528 do i = 1, n_adjoint_scalars
529 if (adjoint_scalars%adjoint_scalar_fields(i)%primal_name &
530 .eq. primal_name) then
531 i_adjoint = i
532 exit
533 end if
534 end do
535
536 do i = 1, n_primal_scalars
537 if (scalars%scalar_fields(i)%scalar%name .eq. primal_name) then
538 i_primal = i
539 exit
540 end if
541 end do
542
543 if (i_primal .le. 0 .or. i_adjoint .le. 0) then
544 call neko_error('could not find matching primal and adjoint' // &
545 ' scalar fields')
546 end if
547
548 end subroutine get_scalar_indicies
549
550 ! ========================================================================= !
551 ! Private routines
552 ! ========================================================================= !
553
578 function design_iteration_fname(base_fname, design_iteration) result(fname)
579 character(len=*), intent(in) :: base_fname
580 integer, intent(in) :: design_iteration
581 character(len=1024) :: fname
582 character(len=80) :: suffix
583 integer :: suffix_pos
584 character(len=32) :: tag
585
586 call filename_suffix(base_fname, suffix)
587 suffix_pos = filename_suffix_pos(base_fname)
588 write(tag, '(a,i5.5)') '_iter', design_iteration
589
590 ! Add extra underscore to the tag if the suffix is `fld` or `nek5000`, so that
591 ! the file's own per-write numeric identifier is visually separated from the
592 ! design-iteration tag.
593 if (trim(suffix) .eq. 'fld' .or. trim(suffix) .eq. 'nek5000') then
594 tag = trim(tag) // '_'
595 end if
596
597 if (suffix_pos .eq. 0) then
598 fname = trim(base_fname) // trim(tag)
599 else
600 fname = base_fname(1:suffix_pos - 1) // trim(tag) // &
601 base_fname(suffix_pos:len_trim(base_fname))
602 end if
603
604 end function design_iteration_fname
605
606end module neko_ext
Adjoint Pn/Pn formulation.
Contains the adjoint_scalar_pnpn_t type.
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:98
subroutine, public field_to_vector(vector, field)
Field to vector.
Definition neko_ext.f90:484
subroutine, public reset_adjoint(adjoint_case, neko_case, design_iteration, output_base_fname)
Reset the adjoint case data structure.
Definition neko_ext.f90:290
subroutine, public vector_to_field(field, vector)
Vector to field.
Definition neko_ext.f90:460
subroutine, public get_scalar_indicies(i_primal, i_adjoint, scalars, adjoint_scalars, primal_name)
get scalar indices
Definition neko_ext.f90:510
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.