Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_case.f90
1! Copyright (c) 2024, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32
33! Implements the `adjoint_case_t` type.
34module adjoint_case
35 use num_types, only: rp, dp, sp
36 use case, only: case_t
37 use adjoint_fluid_scheme, only: adjoint_fluid_scheme_t
38 use adjoint_fluid_fctry, only: adjoint_fluid_scheme_factory
41 use scalar_ic, only: set_scalar_ic
42 use checkpoint, only: chkp_t
43 use chkp_output, only: chkp_output_t
44 use flow_ic, only: set_flow_ic
45 use output_controller, only: output_controller_t
46 use file, only: file_t
47 use json_module, only: json_file
48 use json_utils, only: json_get, json_get_or_default, json_extract_item
51 use logger, only : neko_log
52 use time_state, only : time_state_t
53 use utils, only: neko_error
56 use json_utils_ext, only: json_key_fallback
58 implicit none
59 private
60 public :: adjoint_case_t, adjoint_init, adjoint_free
61
67 class(adjoint_fluid_scheme_t), allocatable :: fluid_adj
69 type(adjoint_scalars_t), allocatable :: adjoint_scalars
72 adjoint_convection_term
73 type(case_t), pointer :: case
74 type(time_state_t) :: time
75 type(chkp_t) :: chkp
76 type(chkp_output_t) :: chkp_out
77
78 ! Fields
79 real(kind=rp) :: tol
80 type(adjoint_output_t) :: f_out
81 type(output_controller_t) :: output_controller
82
83 logical :: have_scalar = .false.
84
85 end type adjoint_case_t
86
87 interface adjoint_init
88 module procedure adjoint_init_from_json ! todo, init from file
89 end interface adjoint_init
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 this%chkp%tlag => this%time%tlag
131 this%chkp%dtlag => this%time%dtlag
132
133 select type (f => this%fluid_adj)
134 type is (adjoint_fluid_pnpn_t)
135 call f%init(neko_case%msh, lx, neko_case%params, &
136 neko_case%user, this%chkp)
137 end select
138 !
139 ! Setup adjoint scalar
140 !
141 ! @todo no adjoint_scalars factory for now, probably not needed
142
143 ! check how many adjoint scalars
144 scalar = .false.
145 n_scalars_adjoint = 0
146 if (neko_case%params%valid_path('case.adjoint_scalar')) then
147 call json_get_or_default(neko_case%params, &
148 'case.adjoint_scalar.enabled', scalar, .true.)
149 n_scalars_adjoint = 1
150 n_scalars_primal = 1
151 else if (neko_case%params%valid_path('case.adjoint_scalars')) then
152 call neko_case%params%info('case.adjoint_scalars', &
153 n_children = n_scalars_adjoint)
154 call neko_case%params%info('case.scalars', n_children = n_scalars_primal)
155 if (n_scalars_adjoint > 0) then
156 scalar = .true.
157 end if
158 end if
159
160 this%have_scalar = scalar
161
162
163
164
165
166
167 if (this%have_scalar) then
168 allocate(this%adjoint_scalars)
169 call json_get(neko_case%params, 'case.numerics', &
170 numerics_params)
171 if (neko_case%params%valid_path('case.adjoint_scalar')) then
172 ! For backward compatibility
173 call json_get(neko_case%params, 'case.adjoint_scalar', &
174 scalar_params_adjoint)
175 call json_get(neko_case%params, 'case.scalar', &
176 scalar_params_primal)
177 call this%adjoint_scalars%init(neko_case%msh, neko_case%fluid%c_Xh, &
178 neko_case%fluid%gs_Xh, scalar_params_adjoint, &
179 scalar_params_primal, numerics_params, neko_case%user, &
180 neko_case%chkp, neko_case%fluid%ulag, neko_case%fluid%vlag, &
181 neko_case%fluid%wlag, neko_case%fluid%ext_bdf, &
182 neko_case%fluid%rho)
183 ! allocate the coupling term
184 allocate(this%adjoint_convection_term)
185 ! initialize the coupling term
186 call json_get_or_default(neko_case%params, &
187 'case.adjoint_scalar.dealias_coupling_term', &
188 dealias_adjoint_scalar_convection, .true.)
189 call this%adjoint_convection_term%init_from_components( &
190 this%fluid_adj%f_adj_x, this%fluid_adj%f_adj_y, &
191 this%fluid_adj%f_adj_z, this%case%scalars%scalar_fields(1)%s, &
192 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
193 this%fluid_adj%c_Xh, this%fluid_adj%c_Xh_GL, &
194 this%fluid_adj%GLL_to_GL, &
195 dealias_adjoint_scalar_convection, this%fluid_adj%scratch_GL)
196
197 select type (f => this%fluid_adj)
198 type is (adjoint_fluid_pnpn_t)
199 ! append the coupling term to the adjoint velocity equation
200 call f%source_term%add(this%adjoint_convection_term)
201 end select
202 else
203 ! Multiple scalars
204
205 call json_get(this%case%params, &
206 'case.adjoint_scalars', scalar_params_adjoint)
207 call json_get(this%case%params, &
208 'case.scalars', scalar_params_primal)
209 call this%adjoint_scalars%init(n_scalars_adjoint, n_scalars_primal, &
210 neko_case%msh, neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
211 scalar_params_adjoint, scalar_params_primal, numerics_params, &
212 neko_case%user, neko_case%chkp, neko_case%fluid%ulag, &
213 neko_case%fluid%vlag, neko_case%fluid%wlag, &
214 neko_case%fluid%ext_bdf, neko_case%fluid%rho)
215 call neko_error('The adjoint scaling coupling term have not yet' // &
216 'been implemented for multiple scalars')
217 end if
218 end if
219
220 !
221 ! Time control
222 !
223 call json_get(this%case%params, 'case.time', json_subdict)
224 call this%time%init(json_subdict)
225
226 !
227 ! Setup user defined conditions
228 !
229 ! if (neko_case%params%valid_path('case.fluid.inflow_condition')) then
230 ! call json_get(neko_case%params, 'case.fluid.inflow_condition.type', &
231 ! string_val)
232 ! if (trim(string_val) .eq. 'user') then
233 ! call neko_case%fluid%set_usr_inflow(neko_case%user%fluid_user_if)
234 ! end if
235 ! end if
236
237 ! Setup user boundary conditions for the scalar.
238 ! if (adjoint_scalars) then
239 ! call neko_case%adjoint_scalars%set_user_bc(&
240 ! neko_case%user%scalar_user_bc)
241 ! end if
242
243 !
244 ! Setup initial conditions
245 !
246
247 call neko_log%section("Adjoint initial condition")
248 json_key = json_key_fallback(neko_case%params, &
249 'case.adjoint_fluid.initial_condition', 'case.fluid.initial_condition')
250
251 call json_get(neko_case%params, json_key, ic_json)
252 call json_get(ic_json, 'type', string_val)
253
254 if (trim(string_val) .ne. 'user') then
255 call set_flow_ic( &
256 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
257 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
258 string_val, ic_json)
259 else
260 call set_flow_ic( &
261 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
262 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
263 neko_case%user%initial_conditions, neko_case%fluid%name)
264 end if
265
266 call neko_log%end_section()
267
268 if (this%have_scalar) then
269
270 if (neko_case%params%valid_path('case.adjoint_scalar')) then
271 ! we shouldn't fallback to the primal here.
272 call json_get(neko_case%params, &
273 'case.adjoint_scalar.initial_condition.type', string_val)
274 call json_get(neko_case%params, &
275 'case.adjoint_scalar.initial_condition', ic_json)
276
277 !call neko_log%section("Adjoint scalar initial condition ")
278
279 if (trim(string_val) .ne. 'user') then
280 if (trim(neko_case%scalars%scalar_fields(1)%name) .eq. &
281 'temperature') then
282 call set_scalar_ic(&
283 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
284 this%adjoint_scalars%adjoint_scalar_fields(1)%c_Xh, &
285 this%adjoint_scalars%adjoint_scalar_fields(1)%gs_Xh, &
286 string_val, ic_json, 0)
287 else
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, 1)
293 end if
294 else
295 call neko_error("user ICs not implemented for adjoint scalar")
296 ! call set_scalar_ic(this%adjoint_scalars%s_adj, &
297 ! this%adjoint_scalars%c_Xh, this%adjoint_scalars%gs_Xh, &
298 ! this%usr%scalar_user_ic, neko_case%params)
299 end if
300
301 ! call neko_log%end_section()
302 else
303
304 ! Handle multiple scalars
305 do i = 1, n_scalars_adjoint
306 call json_extract_item(neko_case%params, 'case.adjoint_scalars', &
307 i, scalar_params_adjoint)
308 call json_get(scalar_params_adjoint, &
309 'initial_condition.type', string_val)
310 call json_get(scalar_params_adjoint, &
311 'initial_condition', json_subdict)
312
313 if (trim(string_val) .ne. 'user') then
314 if (trim(neko_case%scalars%scalar_fields(i)%name) .eq. &
315 'temperature') then
316 call set_scalar_ic(&
317 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
318 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
319 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
320 string_val, json_subdict, 0)
321 temperature_found = .true.
322 else
323 if (temperature_found) then
324 ! if temperature is found, scalars start from index 1
325 call set_scalar_ic(&
326 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
327 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
328 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
329 string_val, json_subdict, i - 1)
330 else
331 ! if temperature is not found, scalars start from index 0
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)
337 end if
338 end if
339 else
340 call neko_error("user ICs not implemented for adjoint scalar")
341 end if
342 end do
343 end if
344 end if
345
346 ! Add initial conditions to BDF fluid_adj (if present)
347 select type (f => this%fluid_adj)
348 type is (adjoint_fluid_pnpn_t)
349 call f%ulag%set(f%u_adj)
350 call f%vlag%set(f%v_adj)
351 call f%wlag%set(f%w_adj)
352 end select
353
354 !
355 ! Validate that the neko_case is properly setup for time-stepping
356 !
357 call this%fluid_adj%validate
358
359 if (this%have_scalar) then
360 call this%adjoint_scalars%validate()
361 end if
362
363 !
364 ! Setup output precision of the field files
365 !
366 call json_get_or_default(neko_case%params, 'case.output_precision', &
367 string_val, 'single')
368
369 if (trim(string_val) .eq. 'double') then
370 precision = dp
371 else
372 precision = sp
373 end if
374
375 !
376 ! Setup output_controller
377 !
378 call this%output_controller%init(this%time%end_time)
379 if (this%have_scalar) then
380 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
381 this%adjoint_scalars, path = trim(neko_case%output_directory))
382 else
383 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
384 path = trim(neko_case%output_directory))
385 end if
386
387 call json_get_or_default(neko_case%params, 'case.fluid.output_control',&
388 string_val, 'org')
389
390 if (trim(string_val) .eq. 'org') then
391 ! yes, it should be real_val below for type compatibility
392 call json_get(neko_case%params, 'case.nsamples', real_val)
393 call this%output_controller%add(this%f_out, real_val, 'nsamples')
394 else if (trim(string_val) .eq. 'never') then
395 ! Fix a dummy 0.0 output_value
396 call json_get_or_default(neko_case%params, 'case.fluid.output_value', &
397 real_val, 0.0_rp)
398 call this%output_controller%add(this%f_out, 0.0_rp, string_val)
399 else
400 call json_get(neko_case%params, 'case.fluid.output_value', real_val)
401 call this%output_controller%add(this%f_out, real_val, string_val)
402 end if
403
404 ! !
405 ! ! Save checkpoints (if nothing specified, default to saving at end of sim)
406 ! !
407 ! call json_get_or_default(neko_case%params, 'case.output_checkpoints',&
408 ! logical_val, .true.)
409 ! if (logical_val) then
410 ! call json_get_or_default(neko_case%params, 'case.checkpoint_format', &
411 ! string_val, "chkp")
412 ! neko_case%f_chkp = chkp_output_t(this%fluid_adj%chkp, &
413 ! path = output_directory, &
414 ! ! fmt = trim(string_val))
415 ! call json_get_or_default(neko_case%params, 'case.checkpoint_control', &
416 ! string_val, "simulationtime")
417 ! call json_get_or_default(neko_case%params, 'case.checkpoint_value', &
418 ! real_val,&
419 ! 1e10_rp)
420 ! call this%output_controller%add(this%f_chkp, real_val, string_val)
421 ! end if
422
423 !
424 ! Initialize time and step
425 !
426 this%time%t = 0d0
427 this%time%tstep = 0
428
429 end subroutine adjoint_case_init_common
430
431 ! Destructor.
432 subroutine adjoint_free(this)
433 class(adjoint_case_t), intent(inout) :: this
434
435 nullify(this%case)
436 if (allocated(this%adjoint_scalars)) then
437 call this%adjoint_scalars%free()
438 deallocate(this%adjoint_scalars)
439 end if
440
441 if (allocated(this%fluid_adj)) then
442 call this%fluid_adj%free()
443 deallocate(this%fluid_adj)
444 end if
445 call this%output_controller%free()
446
447 end subroutine adjoint_free
448
449end module adjoint_case
450
Factory for all adjoint fluid schemes.
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.