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_object, &
49 json_extract_item
52 use logger, only : neko_log
53 use time_state, only : time_state_t
54 use utils, only: neko_error
57 use json_utils_ext, only: json_key_fallback
59 implicit none
60 private
61 public :: adjoint_case_t, adjoint_init, adjoint_free
62
68 class(adjoint_fluid_scheme_t), allocatable :: fluid_adj
70 type(adjoint_scalars_t), allocatable :: adjoint_scalars
73 adjoint_convection_term
74 type(case_t), pointer :: case
75 type(time_state_t) :: time
76 type(chkp_t) :: chkp
77 type(chkp_output_t) :: chkp_out
78
79 ! Fields
80 real(kind=rp) :: tol
81 type(adjoint_output_t) :: f_out
82 type(output_controller_t) :: output_controller
83
84 logical :: have_scalar = .false.
85
86 end type adjoint_case_t
87
88 interface adjoint_init
89 module procedure adjoint_init_from_json ! todo, init from file
90 end interface adjoint_init
91
92contains
93
94 ! Constructor from json.
95 subroutine adjoint_init_from_json(this, neko_case)
96 class(adjoint_case_t), intent(inout) :: this
97 type(case_t), target, intent(inout) :: neko_case
98
99 this%case => neko_case
100 call adjoint_case_init_common(this, neko_case)
101
102 end subroutine adjoint_init_from_json
103
105 subroutine adjoint_case_init_common(this, neko_case)
106 class(adjoint_case_t), target, intent(inout) :: this
107 type(case_t), intent(inout) :: neko_case
108 integer :: lx = 0
109 real(kind=rp) :: real_val = 0.0_rp
110 character(len=:), allocatable :: string_val
111 integer :: precision
112 integer :: n_scalars_primal, n_scalars_adjoint, i
113 logical :: scalar = .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_extract_object(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_extract_object(neko_case%params, 'case.adjoint_scalar', &
173 scalar_params_adjoint)
174 call json_extract_object(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_extract_object(this%case%params, &
200 'case.adjoint_scalars', scalar_params_adjoint)
201 call json_extract_object(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_extract_object(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_extract_object(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_extract_object(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 call set_scalar_ic(&
275 this%adjoint_scalars%adjoint_scalar_fields(1)%s_adj, &
276 this%adjoint_scalars%adjoint_scalar_fields(1)%c_Xh, &
277 this%adjoint_scalars%adjoint_scalar_fields(1)%gs_Xh, &
278 string_val, ic_json)
279 else
280 call neko_error("user ICs not implemented for adjoint scalar")
281 ! call set_scalar_ic(this%adjoint_scalars%s_adj, &
282 ! this%adjoint_scalars%c_Xh, this%adjoint_scalars%gs_Xh, &
283 ! this%usr%scalar_user_ic, neko_case%params)
284 end if
285
286 ! call neko_log%end_section()
287 else
288
289 ! Handle multiple scalars
290 do i = 1, n_scalars_adjoint
291 call json_extract_item(neko_case%params, 'case.adjoint_scalars', &
292 i, scalar_params_adjoint)
293 call json_get(scalar_params_adjoint, &
294 'initial_condition.type', string_val)
295 call json_extract_object(scalar_params_adjoint, &
296 'initial_condition', json_subdict)
297
298 if (trim(string_val) .ne. 'user') then
299 call set_scalar_ic(&
300 this%adjoint_scalars%adjoint_scalar_fields(i)%s_adj, &
301 this%adjoint_scalars%adjoint_scalar_fields(i)%c_Xh, &
302 this%adjoint_scalars%adjoint_scalar_fields(i)%gs_Xh, &
303 string_val, json_subdict)
304 else
305 call neko_error("user ICs not implemented for adjoint scalar")
306 end if
307 end do
308 end if
309 end if
310
311 ! Add initial conditions to BDF fluid_adj (if present)
312 select type (f => this%fluid_adj)
313 type is (adjoint_fluid_pnpn_t)
314 call f%ulag%set(f%u_adj)
315 call f%vlag%set(f%v_adj)
316 call f%wlag%set(f%w_adj)
317 end select
318
319 !
320 ! Validate that the neko_case is properly setup for time-stepping
321 !
322 call this%fluid_adj%validate
323
324 if (this%have_scalar) then
325 call this%adjoint_scalars%validate()
326 end if
327
328 !
329 ! Setup output precision of the field files
330 !
331 call json_get_or_default(neko_case%params, 'case.output_precision', &
332 string_val, 'single')
333
334 if (trim(string_val) .eq. 'double') then
335 precision = dp
336 else
337 precision = sp
338 end if
339
340 !
341 ! Setup output_controller
342 !
343 call this%output_controller%init(this%time%end_time)
344 if (this%have_scalar) then
345 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
346 this%adjoint_scalars, path = trim(neko_case%output_directory))
347 else
348 this%f_out = adjoint_output_t(precision, this%fluid_adj, &
349 path = trim(neko_case%output_directory))
350 end if
351
352 call json_get_or_default(neko_case%params, 'case.fluid.output_control',&
353 string_val, 'org')
354
355 if (trim(string_val) .eq. 'org') then
356 ! yes, it should be real_val below for type compatibility
357 call json_get(neko_case%params, 'case.nsamples', real_val)
358 call this%output_controller%add(this%f_out, real_val, 'nsamples')
359 else if (trim(string_val) .eq. 'never') then
360 ! Fix a dummy 0.0 output_value
361 call json_get_or_default(neko_case%params, 'case.fluid.output_value', &
362 real_val, 0.0_rp)
363 call this%output_controller%add(this%f_out, 0.0_rp, string_val)
364 else
365 call json_get(neko_case%params, 'case.fluid.output_value', real_val)
366 call this%output_controller%add(this%f_out, real_val, string_val)
367 end if
368
369 ! !
370 ! ! Save checkpoints (if nothing specified, default to saving at end of sim)
371 ! !
372 ! call json_get_or_default(neko_case%params, 'case.output_checkpoints',&
373 ! logical_val, .true.)
374 ! if (logical_val) then
375 ! call json_get_or_default(neko_case%params, 'case.checkpoint_format', &
376 ! string_val, "chkp")
377 ! neko_case%f_chkp = chkp_output_t(this%fluid_adj%chkp, &
378 ! path = output_directory, &
379 ! ! fmt = trim(string_val))
380 ! call json_get_or_default(neko_case%params, 'case.checkpoint_control', &
381 ! string_val, "simulationtime")
382 ! call json_get_or_default(neko_case%params, 'case.checkpoint_value', &
383 ! real_val,&
384 ! 1e10_rp)
385 ! call this%output_controller%add(this%f_chkp, real_val, string_val)
386 ! end if
387
388 !
389 ! Initialize time and step
390 !
391 this%time%t = 0d0
392 this%time%tstep = 0
393
394 end subroutine adjoint_case_init_common
395
396 ! Destructor.
397 subroutine adjoint_free(this)
398 class(adjoint_case_t), intent(inout) :: this
399
400 nullify(this%case)
401 if (allocated(this%adjoint_scalars)) then
402 call this%adjoint_scalars%free()
403 deallocate(this%adjoint_scalars)
404 end if
405
406 if (allocated(this%fluid_adj)) then
407 call this%fluid_adj%free()
408 deallocate(this%fluid_adj)
409 end if
410 call this%output_controller%free()
411
412 end subroutine adjoint_free
413
414end module adjoint_case
415
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.