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