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
120 !
121 ! Setup adjoint fluid
122 !
123 call json_get(neko_case%params, 'case.fluid.scheme', string_val)
124 call adjoint_fluid_scheme_factory(this%fluid_adj, trim(string_val))
125
126 call json_get(neko_case%params, 'case.numerics.polynomial_order', lx)
127 lx = lx + 1 ! add 1 to get number of gll points
128
129 this%chkp%tlag => this%time%tlag
130 this%chkp%dtlag => this%time%dtlag
131
132 select type (f => this%fluid_adj)
133 type is (adjoint_fluid_pnpn_t)
134 call f%init(neko_case%msh, lx, neko_case%params, &
135 neko_case%user, this%chkp)
136 end select
137 !
138 ! Setup adjoint scalar
139 !
140 ! @todo no adjoint_scalars factory for now, probably not needed
141
142 ! check how many adjoint scalars
143 scalar = .false.
144 n_scalars_adjoint = 0
145 if (neko_case%params%valid_path('case.adjoint_scalar')) then
146 call json_get_or_default(neko_case%params, &
147 'case.adjoint_scalar.enabled', scalar, .true.)
148 n_scalars_adjoint = 1
149 n_scalars_primal = 1
150 else if (neko_case%params%valid_path('case.adjoint_scalars')) then
151 call neko_case%params%info('case.adjoint_scalars', &
152 n_children = n_scalars_adjoint)
153 call neko_case%params%info('case.scalars', n_children = n_scalars_primal)
154 if (n_scalars_adjoint > 0) then
155 scalar = .true.
156 end if
157 end if
158
159 this%have_scalar = scalar
160
161
162
163
164
165
166 if (this%have_scalar) then
167 allocate(this%adjoint_scalars)
168 call json_get(neko_case%params, 'case.numerics', &
169 numerics_params)
170 if (neko_case%params%valid_path('case.adjoint_scalar')) then
171 ! For backward compatibility
172 call json_get(neko_case%params, 'case.adjoint_scalar', &
173 scalar_params_adjoint)
174 call json_get(neko_case%params, 'case.scalar', &
175 scalar_params_primal)
176 call this%adjoint_scalars%init(neko_case%msh, neko_case%fluid%c_Xh, &
177 neko_case%fluid%gs_Xh, scalar_params_adjoint, &
178 scalar_params_primal, numerics_params, neko_case%user, &
179 neko_case%chkp, neko_case%fluid%ulag, neko_case%fluid%vlag, &
180 neko_case%fluid%wlag, neko_case%fluid%ext_bdf, &
181 neko_case%fluid%rho)
182 ! allocate the coupling term
183 allocate(this%adjoint_convection_term)
184 ! initialize the coupling term
185 call this%adjoint_convection_term%init_from_components( &
186 this%fluid_adj%f_adj_x, this%fluid_adj%f_adj_y, &
187 this%fluid_adj%f_adj_z, this%case%scalars%scalar_fields(1)%s, &
188 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
189 this%fluid_adj%c_Xh)
190
191 select type (f => this%fluid_adj)
192 type is (adjoint_fluid_pnpn_t)
193 ! append the coupling term to the adjoint velocity equation
194 call f%source_term%add(this%adjoint_convection_term)
195 end select
196 else
197 ! Multiple scalars
198
199 call json_get(this%case%params, &
200 'case.adjoint_scalars', scalar_params_adjoint)
201 call json_get(this%case%params, &
202 'case.scalars', scalar_params_primal)
203 call this%adjoint_scalars%init(n_scalars_adjoint, n_scalars_primal, &
204 neko_case%msh, neko_case%fluid%c_Xh, neko_case%fluid%gs_Xh, &
205 scalar_params_adjoint, scalar_params_primal, numerics_params, &
206 neko_case%user, neko_case%chkp, neko_case%fluid%ulag, &
207 neko_case%fluid%vlag, neko_case%fluid%wlag, &
208 neko_case%fluid%ext_bdf, neko_case%fluid%rho)
209 call neko_error('The adjoint scaling coupling term have not yet' // &
210 'been implemented for multiple scalars')
211 end if
212 end if
213
214 !
215 ! Time control
216 !
217 call json_get(this%case%params, 'case.time', json_subdict)
218 call this%time%init(json_subdict)
219
220 !
221 ! Setup user defined conditions
222 !
223 ! if (neko_case%params%valid_path('case.fluid.inflow_condition')) then
224 ! call json_get(neko_case%params, 'case.fluid.inflow_condition.type', &
225 ! string_val)
226 ! if (trim(string_val) .eq. 'user') then
227 ! call neko_case%fluid%set_usr_inflow(neko_case%user%fluid_user_if)
228 ! end if
229 ! end if
230
231 ! Setup user boundary conditions for the scalar.
232 ! if (adjoint_scalars) then
233 ! call neko_case%adjoint_scalars%set_user_bc(&
234 ! neko_case%user%scalar_user_bc)
235 ! end if
236
237 !
238 ! Setup initial conditions
239 !
240
241 call neko_log%section("Adjoint initial condition")
242 json_key = json_key_fallback(neko_case%params, &
243 'case.adjoint_fluid.initial_condition', 'case.fluid.initial_condition')
244
245 call json_get(neko_case%params, json_key, ic_json)
246 call json_get(ic_json, 'type', string_val)
247
248 if (trim(string_val) .ne. 'user') then
249 call set_flow_ic( &
250 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
251 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
252 string_val, ic_json)
253 else
254 call set_flow_ic( &
255 this%fluid_adj%u_adj, this%fluid_adj%v_adj, this%fluid_adj%w_adj, &
256 this%fluid_adj%p_adj, this%fluid_adj%c_Xh, this%fluid_adj%gs_Xh, &
257 neko_case%user%initial_conditions, neko_case%fluid%name)
258 end if
259
260 call neko_log%end_section()
261
262 if (this%have_scalar) then
263
264 if (neko_case%params%valid_path('case.adjoint_scalar')) then
265 ! we shouldn't fallback to the primal here.
266 call json_get(neko_case%params, &
267 'case.adjoint_scalar.initial_condition.type', string_val)
268 call json_get(neko_case%params, &
269 'case.adjoint_scalar.initial_condition', ic_json)
270
271 !call neko_log%section("Adjoint scalar initial condition ")
272
273 if (trim(string_val) .ne. 'user') then
274 if (trim(neko_case%scalars%scalar_fields(1)%name) .eq. &
275 'temperature') then
276 call set_scalar_ic(&
277 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
278 this%adjoint_scalars%adjoint_scalar_fields(1)%c_Xh, &
279 this%adjoint_scalars%adjoint_scalar_fields(1)%gs_Xh, &
280 string_val, ic_json, 0)
281 else
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, 1)
287 end if
288 else
289 call neko_error("user ICs not implemented for adjoint scalar")
290 ! call set_scalar_ic(this%adjoint_scalars%s_adj, &
291 ! this%adjoint_scalars%c_Xh, this%adjoint_scalars%gs_Xh, &
292 ! this%usr%scalar_user_ic, neko_case%params)
293 end if
294
295 ! call neko_log%end_section()
296 else
297
298 ! Handle multiple scalars
299 do i = 1, n_scalars_adjoint
300 call json_extract_item(neko_case%params, 'case.adjoint_scalars', &
301 i, scalar_params_adjoint)
302 call json_get(scalar_params_adjoint, &
303 'initial_condition.type', string_val)
304 call json_get(scalar_params_adjoint, &
305 'initial_condition', json_subdict)
306
307 if (trim(string_val) .ne. 'user') then
308 if (trim(neko_case%scalars%scalar_fields(i)%name) .eq. &
309 'temperature') then
310 call set_scalar_ic(&
311 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
312 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
313 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
314 string_val, json_subdict, 0)
315 temperature_found = .true.
316 else
317 if (temperature_found) then
318 ! if temperature is found, scalars start from index 1
319 call set_scalar_ic(&
320 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
321 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
322 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
323 string_val, json_subdict, i - 1)
324 else
325 ! if temperature is not found, scalars start from index 0
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)
331 end if
332 end if
333 else
334 call neko_error("user ICs not implemented for adjoint scalar")
335 end if
336 end do
337 end if
338 end if
339
340 ! Add initial conditions to BDF fluid_adj (if present)
341 select type (f => this%fluid_adj)
342 type is (adjoint_fluid_pnpn_t)
343 call f%ulag%set(f%u_adj)
344 call f%vlag%set(f%v_adj)
345 call f%wlag%set(f%w_adj)
346 end select
347
348 !
349 ! Validate that the neko_case is properly setup for time-stepping
350 !
351 call this%fluid_adj%validate
352
353 if (this%have_scalar) then
354 call this%adjoint_scalars%validate()
355 end if
356
357 !
358 ! Setup output precision of the field files
359 !
360 call json_get_or_default(neko_case%params, 'case.output_precision', &
361 string_val, 'single')
362
363 if (trim(string_val) .eq. 'double') then
364 precision = dp
365 else
366 precision = sp
367 end if
368
369 !
370 ! Setup output_controller
371 !
372 call this%output_controller%init(this%time%end_time)
373 if (this%have_scalar) then
374 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
375 this%adjoint_scalars, path = trim(neko_case%output_directory))
376 else
377 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
378 path = trim(neko_case%output_directory))
379 end if
380
381 call json_get_or_default(neko_case%params, 'case.fluid.output_control',&
382 string_val, 'org')
383
384 if (trim(string_val) .eq. 'org') then
385 ! yes, it should be real_val below for type compatibility
386 call json_get(neko_case%params, 'case.nsamples', real_val)
387 call this%output_controller%add(this%f_out, real_val, 'nsamples')
388 else if (trim(string_val) .eq. 'never') then
389 ! Fix a dummy 0.0 output_value
390 call json_get_or_default(neko_case%params, 'case.fluid.output_value', &
391 real_val, 0.0_rp)
392 call this%output_controller%add(this%f_out, 0.0_rp, string_val)
393 else
394 call json_get(neko_case%params, 'case.fluid.output_value', real_val)
395 call this%output_controller%add(this%f_out, real_val, string_val)
396 end if
397
398 ! !
399 ! ! Save checkpoints (if nothing specified, default to saving at end of sim)
400 ! !
401 ! call json_get_or_default(neko_case%params, 'case.output_checkpoints',&
402 ! logical_val, .true.)
403 ! if (logical_val) then
404 ! call json_get_or_default(neko_case%params, 'case.checkpoint_format', &
405 ! string_val, "chkp")
406 ! neko_case%f_chkp = chkp_output_t(this%fluid_adj%chkp, &
407 ! path = output_directory, &
408 ! ! fmt = trim(string_val))
409 ! call json_get_or_default(neko_case%params, 'case.checkpoint_control', &
410 ! string_val, "simulationtime")
411 ! call json_get_or_default(neko_case%params, 'case.checkpoint_value', &
412 ! real_val,&
413 ! 1e10_rp)
414 ! call this%output_controller%add(this%f_chkp, real_val, string_val)
415 ! end if
416
417 !
418 ! Initialize time and step
419 !
420 this%time%t = 0d0
421 this%time%tstep = 0
422
423 end subroutine adjoint_case_init_common
424
425 ! Destructor.
426 subroutine adjoint_free(this)
427 class(adjoint_case_t), intent(inout) :: this
428
429 nullify(this%case)
430 if (allocated(this%adjoint_scalars)) then
431 call this%adjoint_scalars%free()
432 deallocate(this%adjoint_scalars)
433 end if
434
435 if (allocated(this%fluid_adj)) then
436 call this%fluid_adj%free()
437 deallocate(this%fluid_adj)
438 end if
439 call this%output_controller%free()
440
441 end subroutine adjoint_free
442
443end module adjoint_case
444
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.