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