Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_case.f90
Go to the documentation of this file.
1
34
35! Implements the `adjoint_case_t` type.
36module adjoint_case
37 use num_types, only: rp, dp, sp
38 use case, only: case_t
39 use adjoint_fluid_scheme, only: adjoint_fluid_scheme_t
43 use scalar_ic, only: set_scalar_ic
44 use checkpoint, only: chkp_t
45 use chkp_output, only: chkp_output_t
46 use flow_ic, only: set_flow_ic
47 use output_controller, only: output_controller_t
48 use time_based_controller, only: time_based_controller_t
49 use file, only: file_t
50 use json_module, only: json_file
51 use json_utils, only: json_get, json_get_or_default, json_extract_item, &
52 json_get_or_lookup
55 use logger, only : neko_log
56 use time_state, only : time_state_t
57 use utils, only: neko_error
60 use json_utils_ext, only: json_key_fallback
62 implicit none
63 private
64 public :: adjoint_case_t
65
71 class(adjoint_fluid_scheme_t), allocatable :: fluid_adj
73 type(adjoint_scalars_t), allocatable :: adjoint_scalars
76 adjoint_convection_term
77 type(case_t), pointer :: case
78 type(time_state_t) :: time
79 type(chkp_t) :: chkp
80 type(chkp_output_t) :: chkp_out
81
82 ! Fields
83 type(adjoint_output_t) :: f_out
84 type(output_controller_t) :: output_controller
85 type(time_based_controller_t) :: norm_output_ctrl
86 type(file_t) :: norm_output_file
87 logical :: norm_output_enabled = .false.
88
89 logical :: have_scalar = .false.
90
91 contains
92 procedure, pass(this) :: init => adjoint_init_from_json
93 procedure, pass(this) :: free => adjoint_free
94 end type adjoint_case_t
95
96contains
97
98 ! Constructor from json.
99 subroutine adjoint_init_from_json(this, neko_case)
100 class(adjoint_case_t), intent(inout) :: this
101 type(case_t), target, intent(inout) :: neko_case
102
103 this%case => neko_case
104 call adjoint_case_init_common(this, neko_case)
105
106 end subroutine adjoint_init_from_json
107
109 subroutine adjoint_case_init_common(this, neko_case)
110 class(adjoint_case_t), target, intent(inout) :: this
111 type(case_t), intent(inout) :: neko_case
112 integer :: lx = 0
113 real(kind=rp) :: real_val = 0.0_rp
114 character(len=:), allocatable :: string_val, file_format, name
115 character(len=:), allocatable :: norm_control, norm_file
116 integer :: precision, integer_val, layout
117 integer :: n_scalars_primal, n_scalars_adjoint, i
118 logical :: scalar = .false.
119 logical :: temperature_found = .false.
120 logical :: logical_val
121
122 ! extra things for json
123 type(json_file) :: ic_json, numerics_params
124 type(json_file) :: scalar_params_primal, scalar_params_adjoint, json_subdict
125 character(len=:), allocatable :: json_key
126 logical :: dealias_adjoint_scalar_convection
127
128 !
129 ! Setup adjoint fluid
130 !
131 call json_get(neko_case%params, 'case.fluid.scheme', string_val)
132 call adjoint_fluid_scheme_factory(this%fluid_adj, trim(string_val))
133
134 call json_get(neko_case%params, 'case.numerics.polynomial_order', lx)
135 lx = lx + 1 ! add 1 to get number of gll points
136
137 call this%chkp%init()
138 call this%chkp%add_time_state(this%time)
139
140 select type (f => this%fluid_adj)
141 type is (adjoint_fluid_pnpn_t)
142 call f%init(neko_case%msh, lx, neko_case%params, &
143 neko_case%user, this%chkp)
144 end select
145 !
146 ! Setup adjoint scalar
147 !
148 ! @todo no adjoint_scalars factory for now, probably not needed
149
150 ! check how many adjoint scalars
151 scalar = .false.
152 n_scalars_adjoint = 0
153 if (neko_case%params%valid_path('case.adjoint_scalar')) then
154 call json_get_or_default(neko_case%params, &
155 'case.adjoint_scalar.enabled', scalar, .true.)
156 n_scalars_adjoint = 1
157 n_scalars_primal = 1
158 else if (neko_case%params%valid_path('case.adjoint_scalars')) then
159 call neko_case%params%info('case.adjoint_scalars', &
160 n_children = n_scalars_adjoint)
161 call neko_case%params%info('case.scalars', n_children = n_scalars_primal)
162 if (n_scalars_adjoint > 0) then
163 scalar = .true.
164 end if
165 end if
166
167 this%have_scalar = scalar
168
169
170
171
172
173
174 if (this%have_scalar) then
175 allocate(this%adjoint_scalars)
176 call json_get(neko_case%params, 'case.numerics', &
177 numerics_params)
178 if (neko_case%params%valid_path('case.adjoint_scalar')) then
179 ! For backward compatibility
180 call json_get(neko_case%params, 'case.adjoint_scalar', &
181 scalar_params_adjoint)
182 call json_get(neko_case%params, 'case.scalar', &
183 scalar_params_primal)
184 call this%adjoint_scalars%init(neko_case%msh, neko_case%fluid%c_Xh, &
185 neko_case%fluid%gs_Xh, scalar_params_adjoint, &
186 scalar_params_primal, numerics_params, neko_case%user, &
187 this%chkp, neko_case%fluid%ulag, neko_case%fluid%vlag, &
188 neko_case%fluid%wlag, neko_case%fluid%ext_bdf, &
189 neko_case%fluid%rho)
190 ! allocate the coupling term
191 allocate(this%adjoint_convection_term)
192 ! initialize the coupling term
193 call json_get_or_default(neko_case%params, &
194 'case.adjoint_scalar.dealias_coupling_term', &
195 dealias_adjoint_scalar_convection, .true.)
196 call this%adjoint_convection_term%init_from_components( &
197 this%fluid_adj%f_adj_x, this%fluid_adj%f_adj_y, &
198 this%fluid_adj%f_adj_z, this%case%scalars%scalar_fields(1)%scalar%s, &
199 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
200 this%fluid_adj%c_Xh, this%fluid_adj%c_Xh_GL, &
201 this%fluid_adj%GLL_to_GL, &
202 dealias_adjoint_scalar_convection, this%fluid_adj%scratch_GL)
203
204 select type (f => this%fluid_adj)
205 type is (adjoint_fluid_pnpn_t)
206 ! append the coupling term to the adjoint velocity equation
207 call f%source_term%add(this%adjoint_convection_term)
208 end select
209 else
210 ! Multiple scalars
211
212 call json_get(this%case%params, &
213 'case.adjoint_scalars', scalar_params_adjoint)
214 call json_get(this%case%params, &
215 'case.scalars', scalar_params_primal)
216 call this%adjoint_scalars%init(n_scalars_adjoint, n_scalars_primal, &
217 neko_case%msh, neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
218 scalar_params_adjoint, scalar_params_primal, numerics_params, &
219 neko_case%user, this%chkp, neko_case%fluid%ulag, &
220 neko_case%fluid%vlag, neko_case%fluid%wlag, &
221 neko_case%fluid%ext_bdf, neko_case%fluid%rho)
222 call neko_error('The adjoint scaling coupling term have not yet' // &
223 'been implemented for multiple scalars')
224 end if
225 end if
226
227 !
228 ! Time control
229 !
230 call json_get(this%case%params, 'case.time', json_subdict)
231 call this%time%init(json_subdict)
232
233 !
234 ! Setup user defined conditions
235 !
236 ! if (neko_case%params%valid_path('case.fluid.inflow_condition')) then
237 ! call json_get(neko_case%params, 'case.fluid.inflow_condition.type', &
238 ! string_val)
239 ! if (trim(string_val) .eq. 'user') then
240 ! call neko_case%fluid%set_usr_inflow(neko_case%user%fluid_user_if)
241 ! end if
242 ! end if
243
244 ! Setup user boundary conditions for the scalar.
245 ! if (adjoint_scalars) then
246 ! call neko_case%adjoint_scalars%set_user_bc(&
247 ! neko_case%user%scalar_user_bc)
248 ! end if
249
250 !
251 ! Setup initial conditions
252 !
253
254 call neko_log%section("Adjoint initial condition")
255 json_key = json_key_fallback(neko_case%params, &
256 'case.adjoint_fluid.initial_condition', 'case.fluid.initial_condition')
257
258 call json_get(neko_case%params, json_key, ic_json)
259 call json_get(ic_json, 'type', string_val)
260
261 if (trim(string_val) .ne. 'user') then
262 call set_flow_ic( &
263 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
264 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
265 string_val, ic_json)
266 else
267 call set_flow_ic( &
268 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
269 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
270 neko_case%user%initial_conditions, neko_case%fluid%name)
271 end if
272
273 call neko_log%end_section()
274
275 if (this%have_scalar) then
276
277 if (neko_case%params%valid_path('case.adjoint_scalar')) then
278 ! we shouldn't fallback to the primal here.
279 call json_get(neko_case%params, &
280 'case.adjoint_scalar.initial_condition.type', string_val)
281 call json_get(neko_case%params, &
282 'case.adjoint_scalar.initial_condition', ic_json)
283
284 !call neko_log%section("Adjoint scalar initial condition ")
285
286 if (trim(string_val) .ne. 'user') then
287 if (trim(neko_case%scalars%scalar_fields(1)%scalar%name) .eq. &
288 'temperature') then
289 call set_scalar_ic(&
290 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
291 this%adjoint_scalars%adjoint_scalar_fields(1)%c_Xh, &
292 this%adjoint_scalars%adjoint_scalar_fields(1)%gs_Xh, &
293 string_val, ic_json, 0)
294 else
295 call set_scalar_ic(&
296 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
297 this%adjoint_scalars%adjoint_scalar_fields(1)%c_Xh, &
298 this%adjoint_scalars%adjoint_scalar_fields(1)%gs_Xh, &
299 string_val, ic_json, 1)
300 end if
301 else
302 call neko_error("user ICs not implemented for adjoint scalar")
303 ! call set_scalar_ic(this%adjoint_scalars%s_adj, &
304 ! this%adjoint_scalars%c_Xh, this%adjoint_scalars%gs_Xh, &
305 ! this%usr%scalar_user_ic, neko_case%params)
306 end if
307
308 ! call neko_log%end_section()
309 else
310
311 ! Handle multiple scalars
312 do i = 1, n_scalars_adjoint
313 call json_extract_item(neko_case%params, 'case.adjoint_scalars', &
314 i, scalar_params_adjoint)
315 call json_get(scalar_params_adjoint, &
316 'initial_condition.type', string_val)
317 call json_get(scalar_params_adjoint, &
318 'initial_condition', json_subdict)
319
320 if (trim(string_val) .ne. 'user') then
321 if (trim(neko_case%scalars%scalar_fields(i)%scalar%name) .eq. &
322 'temperature') then
323 call set_scalar_ic(&
324 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
325 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
326 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
327 string_val, json_subdict, 0)
328 temperature_found = .true.
329 else
330 if (temperature_found) then
331 ! if temperature is found, scalars start from index 1
332 call set_scalar_ic(&
333 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
334 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
335 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
336 string_val, json_subdict, i - 1)
337 else
338 ! if temperature is not found, scalars start from index 0
339 call set_scalar_ic(&
340 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
341 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
342 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
343 string_val, json_subdict, i)
344 end if
345 end if
346 else
347 call neko_error("user ICs not implemented for adjoint scalar")
348 end if
349 end do
350 end if
351 end if
352
353 ! Add initial conditions to BDF fluid_adj (if present)
354 select type (f => this%fluid_adj)
355 type is (adjoint_fluid_pnpn_t)
356 call f%ulag%set(f%u_adj)
357 call f%vlag%set(f%v_adj)
358 call f%wlag%set(f%w_adj)
359 end select
360
361 !
362 ! Validate that the neko_case is properly setup for time-stepping
363 !
364 call this%fluid_adj%validate
365
366 if (this%have_scalar) then
367 call this%adjoint_scalars%validate()
368 end if
369
370 !
371 ! Setup output precision of the field files
372 !
373 call json_get_or_default(neko_case%params, 'case.output_precision', &
374 string_val, 'single')
375
376 if (trim(string_val) .eq. 'double') then
377 precision = dp
378 else
379 precision = sp
380 end if
381
382 !
383 ! Setup output_controller
384 !
385 call json_get_or_default(neko_case%params, &
386 'case.adjoint_fluid.output_filename', name, "adjoint")
387 call json_get_or_default(neko_case%params, &
388 'case.adjoint_fluid.output_format', file_format, 'fld')
389 call json_get_or_default(neko_case%params, &
390 'case.adjoint_fluid.output_mesh_in_all_files', &
391 logical_val, .false.)
392 call this%output_controller%init(this%time%end_time)
393 if (scalar) then
394 call this%f_out%init(precision, this%fluid_adj, &
395 this%adjoint_scalars, name = name, &
396 path = trim(neko_case%output_directory), &
397 fmt = trim(file_format), layout = layout, &
398 always_write_mesh = logical_val)
399 else
400 call this%f_out%init(precision, this%fluid_adj, name = name, &
401 path = trim(neko_case%output_directory), &
402 fmt = trim(file_format), layout = layout, &
403 always_write_mesh = logical_val)
404 end if
405
406 call json_get_or_default(neko_case%params, &
407 'case.adjoint_fluid.output_subdivide', logical_val, .false.)
408 call this%f_out%file_%set_subdivide(logical_val)
409
410 call json_get_or_default(neko_case%params, &
411 'case.adjoint_fluid.output_control', string_val, 'never')
412
413 if (trim(string_val) .eq. 'org') then
414 ! yes, it should be real_val below for type compatibility
415 call json_get_or_lookup(neko_case%params, 'case.nsamples', integer_val)
416 real_val = real(integer_val, kind=rp)
417 call this%output_controller%add(this%f_out, real_val, 'nsamples')
418 else if (trim(string_val) .eq. 'never') then
419 call this%output_controller%add(this%f_out, 0.0_rp, 'never')
420 else if (trim(string_val) .eq. 'tsteps' .or. &
421 trim(string_val) .eq. 'nsamples') then
422 call json_get_or_lookup(neko_case%params, &
423 'case.adjoint_fluid.output_value', integer_val)
424 real_val = real(integer_val, kind=rp)
425 call this%output_controller%add(this%f_out, real_val, string_val)
426 else if (trim(string_val) .eq. 'simulationtime') then
427 call json_get_or_lookup(neko_case%params, &
428 'case.adjoint_fluid.output_value', real_val)
429 call this%output_controller%add(this%f_out, real_val, string_val)
430 else
431 call neko_log%error('Unknown output control type for the fluid: ' // &
432 trim(string_val))
433 end if
434
435 !
436 ! Setup adjoint norm output
437 !
438 call json_get_or_default(neko_case%params, &
439 'case.adjoint_fluid.norm_output_control', norm_control, 'never')
440 if (trim(norm_control) .ne. 'never') then
441 call json_get_or_default(neko_case%params, &
442 'case.adjoint_fluid.norm_output_value', real_val, 1.0_rp)
443 call json_get_or_default(neko_case%params, &
444 'case.adjoint_fluid.norm_output_file', norm_file, &
445 'adjoint_norm.csv')
446 call this%norm_output_file%init(trim(neko_case%output_directory) // &
447 trim(norm_file))
448 call this%norm_output_file%set_header('Time, Norm')
449 call this%norm_output_file%set_overwrite(.true.)
450 call this%norm_output_ctrl%init(this%time%start_time, &
451 this%time%end_time, trim(norm_control), real_val)
452 this%norm_output_enabled = .true.
453 end if
454
455 ! !
456 ! ! Save checkpoints (if nothing specified, default to saving at end of sim)
457 ! !
458 ! call json_get_or_default(neko_case%params, 'case.output_checkpoints',&
459 ! logical_val, .true.)
460 ! if (logical_val) then
461 ! call json_get_or_default(neko_case%params, 'case.checkpoint_format', &
462 ! string_val, "chkp")
463 ! neko_case%f_chkp = chkp_output_t(this%fluid_adj%chkp, &
464 ! path = output_directory, &
465 ! ! fmt = trim(string_val))
466 ! call json_get_or_default(neko_case%params, 'case.checkpoint_control', &
467 ! string_val, "simulationtime")
468 ! call json_get_or_default(neko_case%params, 'case.checkpoint_value', &
469 ! real_val,&
470 ! 1e10_rp)
471 ! call this%output_controller%add(this%f_chkp, real_val, string_val)
472 ! end if
473
474 !
475 ! Initialize time and step
476 !
477 this%time%t = 0d0
478 this%time%tstep = 0
479
480 end subroutine adjoint_case_init_common
481
482 ! Destructor.
483 subroutine adjoint_free(this)
484 class(adjoint_case_t), intent(inout) :: this
485
486 if (allocated(this%fluid_adj)) then
487 call this%fluid_adj%free()
488 deallocate(this%fluid_adj)
489 end if
490
491 if (allocated(this%adjoint_scalars)) then
492 call this%adjoint_scalars%free()
493 deallocate(this%adjoint_scalars)
494 end if
495
496 if (allocated(this%adjoint_convection_term)) then
497 call this%adjoint_convection_term%free()
498 deallocate(this%adjoint_convection_term)
499 end if
500
501 nullify(this%case)
502
503 ! call this%time%free()
504 call this%chkp%free()
505 call this%chkp_out%free()
506
507 ! Fields
508 call this%f_out%free()
509 call this%output_controller%free()
510 call this%norm_output_ctrl%free()
511 call this%norm_output_file%free()
512
513 this%have_scalar = .false.
514
515 end subroutine adjoint_free
516
517end module adjoint_case
Factory for all adjoint fluid schemes.
subroutine, public adjoint_fluid_scheme_factory(object, type_name)
Initialise a adjoint fluid scheme.
Adjoint Pn/Pn formulation.
Defines an output for a adjoint.
Implements the adjoint_scalar_convection_source_term type.
Contains the adjoint_scalar_pnpn_t type.
Contains the adjoint_scalar_scheme_t type.
Contains the adjoint_scalars_t type that manages multiple scalar fields.
Adjoint case type. Todo: This should Ideally be a subclass of case_t, however, that is not yet suppor...
Base type for a scalar advection-diffusion solver.
Type to manage multiple adjoint scalar transport equations.