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
66 implicit none
67
68 ! ========================================================================= !
69 ! Module interface
70 ! ========================================================================= !
71 private
74
75contains
76
77 ! ========================================================================= !
78 ! Public routines
79 ! ========================================================================= !
80
95 subroutine reset(neko_case, design_iteration, output_base_fname)
96 type(case_t), intent(inout) :: neko_case
97 integer, intent(in) :: design_iteration
98 character(len=*), intent(in) :: output_base_fname
99 real(kind=rp) :: t
100 integer :: i
101 character(len=:), allocatable :: string_val
102 logical :: has_scalar, freezeflow
103 type(field_t), pointer :: u, v, w, p, s
104 type(json_file) :: json_subdict
105
106 ! ------------------------------------------------------------------------ !
107 ! Setup shorthand notation
108 ! ------------------------------------------------------------------------ !
109
110 u => neko_case%fluid%u
111 v => neko_case%fluid%v
112 w => neko_case%fluid%w
113 p => neko_case%fluid%p
114 if (allocated(neko_case%scalars)) then
115 s => neko_case%scalars%scalar_fields(1)%scalar%s
116 else
117 nullify(s)
118 end if
119
120 ! ------------------------------------------------------------------------ !
121 ! Reset the timing parameters
122 ! ------------------------------------------------------------------------ !
123
124 call neko_case%time%reset()
125 t = neko_case%time%start_time
126 do i = 1, size(neko_case%time%tlag)
127 neko_case%time%tlag(i) = t - i*neko_case%time%dtlag(i)
128 end do
129
130 ! Tag the field output filename with the design iteration, so this
131 ! iteration's forward field output does not overwrite the previous one.
132 ! Calling the base `generic_file_t%init` directly (rather than the
133 ! reallocating `file_t%init` wrapper) only touches the filename and
134 ! write counter, leaving the case-file-configured precision/layout/
135 ! subdivide/overwrite settings on the underlying `fld_file_t` untouched.
136 call neko_case%f_out%file_%file_type%init( &
137 trim(design_iteration_fname(output_base_fname, design_iteration)))
138
139 ! Reset the time step counter
140 call neko_case%output_controller%set_counter(neko_case%time)
141
142 ! Keep per-design-iteration output numbering anchored at 0.
143 ! output_controller%set_counter sets start_counter based on controller
144 ! executions (typically 1 at reset), so override it for this stream.
145 call neko_case%f_out%set_start_counter(0)
146 call neko_case%f_out%set_counter(-1)
147
148 ! Restart the fields
149 call neko_case%fluid%restart(neko_case%chkp)
150 if (allocated(neko_case%scalars)) then
151 call neko_case%scalars%restart(neko_case%chkp)
152 end if
153
154 ! Reset the external BDF coefficients
155 do i = 1, size(neko_case%time%dtlag)
156 call neko_case%fluid%ext_bdf%set_coeffs(neko_case%time%dtlag)
157 end do
158
159 ! Restart the simulation components
160 call neko_simcomps%restart(neko_case%time)
161
162 ! ------------------------------------------------------------------------ !
163 ! Reset the fluid field to the initial condition
164 ! ------------------------------------------------------------------------ !
165
166 call json_get(neko_case%params, &
167 'case.fluid.initial_condition.type', string_val)
168 call json_get(neko_case%params, 'case.fluid.initial_condition', &
169 json_subdict)
170
171 if (trim(string_val) .ne. 'user') then
172 call set_flow_ic(u, v, w, p, &
173 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
174 string_val, json_subdict)
175 else
176 call set_flow_ic(u, v, w, p, &
177 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
178 neko_case%user%initial_conditions, neko_case%fluid%name)
179 end if
180
181 ! set lags to IC
182 call neko_case%fluid%ulag%set(u)
183 call neko_case%fluid%vlag%set(v)
184 call neko_case%fluid%wlag%set(w)
185 ! zero out RHS etc
186 select type (f => neko_case%fluid)
187 type is (fluid_pnpn_t)
188 call field_rzero(f%abx1)
189 call field_rzero(f%aby1)
190 call field_rzero(f%abz1)
191 call field_rzero(f%abx2)
192 call field_rzero(f%aby2)
193 call field_rzero(f%abz2)
194 call field_copy(f%u_e, u)
195 call field_copy(f%v_e, v)
196 call field_copy(f%w_e, w)
197 end select
198 call field_rzero(neko_case%fluid%f_x)
199 call field_rzero(neko_case%fluid%f_y)
200 call field_rzero(neko_case%fluid%f_z)
201 ! ------------------------------------------------------------------------ !
202 ! Reset the scalar field to the initial condition
203 ! ------------------------------------------------------------------------ !
204
205 ! check for a single scalar
206 call json_get_or_default(neko_case%params, &
207 'case.scalar.enabled', has_scalar, .false.)
208
209 if (has_scalar) then
210 ! check for multiple scalars
211 if (size(neko_case%scalars%scalar_fields) .gt. 1) then
212 call neko_error('Multiple scalars not supported')
213 end if
214 ! zero out RHS
215 call field_rzero(neko_case%scalars%scalar_fields(1)%scalar%f_Xh)
216 ! reset the forward scalar
217 call json_get(neko_case%params, &
218 'case.scalar.initial_condition.type', string_val)
219 call json_get(neko_case%params, &
220 'case.scalar.initial_condition', json_subdict)
221 if (trim(string_val) .ne. 'user') then
222 if (trim(neko_case%scalars%scalar_fields(1)%scalar%name) .eq. &
223 'temperature') then
224 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%s, &
225 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, string_val, &
226 json_subdict, 0)
227 else
228 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%s, &
229 neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, string_val, &
230 json_subdict, 1)
231 end if
232 else
233 call set_scalar_ic(neko_case%scalars%scalar_fields(1)%scalar%name, &
234 neko_case%scalars%scalar_fields(1)%scalar%s, &
235 neko_case%scalars%scalar_fields(1)%scalar%c_Xh, &
236 neko_case%scalars%scalar_fields(1)%scalar%gs_Xh, &
237 neko_case%user%initial_conditions)
238 end if
239 ! set lags to IC
240 call neko_case%scalars%scalar_fields(1)%scalar%slag%set(&
241 neko_case%scalars%scalar_fields(1)%scalar%s)
242 end if
243
244 ! ------------------------------------------------------------------------ !
245 ! Reset the "freeze" parameter of the flow
246 ! ------------------------------------------------------------------------ !
247
248 call json_get_or_default(neko_case%params, &
249 'case.fluid.freeze_flow', freezeflow, .false.)
250
251 neko_case%fluid%freeze = freezeflow
252
253 end subroutine reset
254
271 subroutine reset_adjoint(adjoint_case, neko_case, design_iteration, &
272 output_base_fname)
273 type(adjoint_case_t), intent(inout) :: adjoint_case
274 type(case_t), intent(inout) :: neko_case
275 integer, intent(in) :: design_iteration
276 character(len=*), intent(in) :: output_base_fname
277 real(kind=rp) :: t
278 integer :: i
279 character(len=:), allocatable :: string_val
280 logical :: has_scalar, freezeflow
281 type(field_t), pointer :: u_adj, v_adj, w_adj, p_adj, s_adj
282 type(json_file) :: json_subdict
283
284 ! ------------------------------------------------------------------------ !
285 ! Setup shorthand notation
286 ! ------------------------------------------------------------------------ !
287
288 u_adj => adjoint_case%fluid_adj%u_adj
289 v_adj => adjoint_case%fluid_adj%v_adj
290 w_adj => adjoint_case%fluid_adj%w_adj
291 p_adj => adjoint_case%fluid_adj%p_adj
292 if (allocated(adjoint_case%adjoint_scalars)) then
293 s_adj => adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj
294 else
295 nullify(s_adj)
296 end if
297
298 ! ------------------------------------------------------------------------ !
299 ! Reset the timing parameters
300 ! ------------------------------------------------------------------------ !
301
302 call adjoint_case%time%reset()
303 t = adjoint_case%time%start_time
304 do i = 1, size(adjoint_case%time%tlag)
305 adjoint_case%time%tlag(i) = t - i*adjoint_case%time%dtlag(i)
306 end do
307
308 ! Tag the field output filename with the design iteration, so this
309 ! iteration's adjoint field output does not overwrite the previous one.
310 ! See the equivalent call in `reset` for why the base
311 ! `generic_file_t%init` is called directly here.
312 call adjoint_case%f_out%file_%file_type%init( &
313 trim(design_iteration_fname(output_base_fname, design_iteration)))
314
315 ! Reset the time step counter
316 call adjoint_case%output_controller%set_counter(adjoint_case%time)
317 if (adjoint_case%norm_output_enabled) then
318 call adjoint_case%norm_output_ctrl%set_counter(adjoint_case%time)
319 end if
320
321 ! Keep per-design-iteration output numbering anchored at 0.
322 call adjoint_case%f_out%set_start_counter(0)
323 call adjoint_case%f_out%set_counter(-1)
324
325 ! Reset the external BDF coefficients
326 do i = 1, size(adjoint_case%time%dtlag)
327 call adjoint_case%fluid_adj%ext_bdf%set_coeffs(adjoint_case%time%dtlag)
328 end do
329
330 ! ------------------------------------------------------------------------ !
331 ! Reset the adjoint fluid to the initial (final) condition
332 ! ------------------------------------------------------------------------ !
333
334 ! don't fallback to the fluid here
335 call json_get(neko_case%params, &
336 'case.adjoint_fluid.initial_condition.type', string_val)
337 call json_get(neko_case%params, 'case.adjoint_fluid.initial_condition', &
338 json_subdict)
339
340 if (trim(string_val) .ne. 'user') then
341 call set_flow_ic(u_adj, v_adj, w_adj, p_adj, &
342 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
343 string_val, json_subdict)
344 else
345 call neko_error("adjoint user initial conditions not supported")
346 end if
347
348 ! set lags to IC
349 call adjoint_case%fluid_adj%ulag%set(u_adj)
350 call adjoint_case%fluid_adj%vlag%set(v_adj)
351 call adjoint_case%fluid_adj%wlag%set(w_adj)
352 ! zero out RHS etc
353 select type (f => adjoint_case%fluid_adj)
354 type is (adjoint_fluid_pnpn_t)
355 call field_rzero(f%abx1)
356 call field_rzero(f%aby1)
357 call field_rzero(f%abz1)
358 call field_rzero(f%abx2)
359 call field_rzero(f%aby2)
360 call field_rzero(f%abz2)
361 end select
362 ! zero out all lags etc
363 ! (not sure what to do with the abx's_adj)
364 call field_rzero(adjoint_case%fluid_adj%f_adj_x)
365 call field_rzero(adjoint_case%fluid_adj%f_adj_y)
366 call field_rzero(adjoint_case%fluid_adj%f_adj_z)
367 ! ------------------------------------------------------------------------ !
368 ! Reset the scalar field to the initial condition
369 ! ------------------------------------------------------------------------ !
370
371 ! check for a single scalar
372 call json_get_or_default(neko_case%params, 'case.scalar.enabled', &
373 has_scalar, .false.)
374
375 if (has_scalar) then
376 ! check for multiple adjoint_scalars
377 if (size(adjoint_case%adjoint_scalars%adjoint_scalar_fields) .gt. 1) then
378 call neko_error('Multiple adjoint scalars not supported')
379 end if
380 ! zero out lag terms
381 call field_rzero( &
382 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%f_Xh)
383 ! reset the forward scalar
384 call json_get(neko_case%params, &
385 'case.adjoint_scalar.initial_condition.type', string_val)
386 call json_get(neko_case%params, &
387 'case.adjoint_scalar.initial_condition', json_subdict)
388 if (trim(string_val) .ne. 'user') then
389 if (trim(neko_case%scalars%scalar_fields(1)%scalar%name) .eq. &
390 'temperature') then
391 call set_scalar_ic( &
392 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
393 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
394 string_val, json_subdict, 0)
395 else
396 call set_scalar_ic( &
397 adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
398 adjoint_case%fluid_adj%c_Xh, adjoint_case%fluid_adj%gs_Xh, &
399 string_val, json_subdict, 1)
400 end if
401 else
402 call neko_error("adjoint scalar user IC not supported")
403 end if
404 ! set lags to IC
405 call adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj_lag% &
406 set(adjoint_case%adjoint_scalars%adjoint_scalar_fields(1)%s_adj)
407 end if
408
409 ! ------------------------------------------------------------------------ !
410 ! Reset the "freeze" parameter of the flow
411 ! ------------------------------------------------------------------------ !
412
413 call json_get_or_default(neko_case%params, &
414 'case.adjoint_fluid.freeze_flow', freezeflow, .false.)
415
416 adjoint_case%fluid_adj%freeze = freezeflow
417
418 end subroutine reset_adjoint
419
427 subroutine vector_to_field(field, vector)
428 type(field_t), intent(inout) :: field
429 type(vector_t), intent(in) :: vector
430
431 ! first check they're the same size
432 if (field%size() .ne. vector%size()) then
433 call neko_error("vector and field are not the same size")
434 end if
435
436 if (neko_bcknd_device .eq. 1) then
437 call device_copy(field%x_d, vector%x_d, field%size())
438 else
439 call copy(field%x, vector%x, field%size())
440 end if
441
442 end subroutine vector_to_field
443
451 subroutine field_to_vector(vector, field)
452 type(vector_t), intent(inout) :: vector
453 type(field_t), intent(in) :: field
454
455 ! first check they're the same size
456 if (field%size() .ne. vector%size()) then
457 call neko_error("vector and field are not the same size")
458 end if
459
460 if (neko_bcknd_device .eq. 1) then
461 call device_copy(vector%x_d, field%x_d, field%size())
462 else
463 call copy(vector%x, field%x, field%size())
464 end if
465
466 end subroutine field_to_vector
467
476 subroutine get_scalar_indicies(i_primal, i_adjoint, scalars, &
477 adjoint_scalars, primal_name)
478 integer, intent(out) :: i_primal
479 integer, intent(out) :: i_adjoint
480 type(scalars_t), intent(inout) :: scalars
481 type(adjoint_scalars_t), intent(inout) :: adjoint_scalars
482 character(len=*), intent(in) :: primal_name
483 integer :: i, n_primal_scalars, n_adjoint_scalars
484
485 i_primal = -1
486 i_adjoint = -1
487 n_adjoint_scalars = size(adjoint_scalars%adjoint_scalar_fields)
488 n_primal_scalars = size(scalars%scalar_fields)
489
490 if ((n_adjoint_scalars .eq. 1) .and. (n_primal_scalars .eq. 1)) then
491 i_primal = 1
492 i_adjoint = 1
493 return
494 end if
495
496 do i = 1, n_adjoint_scalars
497 if (adjoint_scalars%adjoint_scalar_fields(i)%primal_name &
498 .eq. primal_name) then
499 i_adjoint = i
500 exit
501 end if
502 end do
503
504 do i = 1, n_primal_scalars
505 if (scalars%scalar_fields(i)%scalar%name .eq. primal_name) then
506 i_primal = i
507 exit
508 end if
509 end do
510
511 if (i_primal .le. 0 .or. i_adjoint .le. 0) then
512 call neko_error('could not find matching primal and adjoint' // &
513 ' scalar fields')
514 end if
515
516 end subroutine get_scalar_indicies
517
518 ! ========================================================================= !
519 ! Private routines
520 ! ========================================================================= !
521
546 function design_iteration_fname(base_fname, design_iteration) result(fname)
547 character(len=*), intent(in) :: base_fname
548 integer, intent(in) :: design_iteration
549 character(len=1024) :: fname
550 character(len=80) :: suffix
551 integer :: suffix_pos
552 character(len=32) :: tag
553
554 call filename_suffix(base_fname, suffix)
555 suffix_pos = filename_suffix_pos(base_fname)
556 write(tag, '(a,i5.5)') '_iter', design_iteration
557
558 ! Add extra underscore to the tag if the suffix is `fld` or `nek5000`, so that
559 ! the file's own per-write numeric identifier is visually separated from the
560 ! design-iteration tag.
561 if (trim(suffix) .eq. 'fld' .or. trim(suffix) .eq. 'nek5000') then
562 tag = trim(tag) // '_'
563 end if
564
565 if (suffix_pos .eq. 0) then
566 fname = trim(base_fname) // trim(tag)
567 else
568 fname = base_fname(1:suffix_pos - 1) // trim(tag) // &
569 base_fname(suffix_pos:len_trim(base_fname))
570 end if
571
572 end function design_iteration_fname
573
574end module neko_ext
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 field_to_vector(vector, field)
Field to vector.
Definition neko_ext.f90:452
subroutine, public reset_adjoint(adjoint_case, neko_case, design_iteration, output_base_fname)
Reset the adjoint case data structure.
Definition neko_ext.f90:273
subroutine, public vector_to_field(field, vector)
Vector to field.
Definition neko_ext.f90:428
subroutine, public get_scalar_indicies(i_primal, i_adjoint, scalars, adjoint_scalars, primal_name)
get scalar indices
Definition neko_ext.f90:478
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.