Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_scalars.f90
Go to the documentation of this file.
1
34!
36
38 use num_types, only: rp
41 use mesh, only: mesh_t
42 use space, only: space_t
43 use gather_scatter, only: gs_t
44 use time_scheme_controller, only: time_scheme_controller_t
45 use time_step_controller, only: time_step_controller_t
46 use json_module, only: json_file
47 use json_utils, only: json_get, json_get_or_default, json_extract_item
48 use field, only: field_t
49 use field_series, only: field_series_t
50 use scalar_aux, only : scalar_step_info
51 use krylov, only : ksp_monitor_t
52 use registry, only: neko_registry
53 use checkpoint, only: chkp_t
54 use krylov, only: ksp_t
55 use logger, only: neko_log, log_size, neko_log_verbose
56 use user_intf, only: user_t
57 use utils, only: neko_error
58 use coefs, only : coef_t
59 use time_state, only : time_state_t
60 implicit none
61 private
62
64 type, public :: adjoint_scalars_t
66 class(adjoint_scalar_scheme_t), allocatable :: adjoint_scalar_fields(:)
68 class(ksp_t), allocatable :: shared_ksp
69 contains
71 generic :: init => adjoint_scalars_init, adjoint_scalars_init_single
72 procedure, private :: adjoint_scalars_init
73 procedure, private :: adjoint_scalars_init_single
75 procedure :: step => adjoint_scalars_step
77 procedure :: restart => adjoint_scalars_restart
79 procedure :: validate => adjoint_scalars_validate
81 procedure :: free => adjoint_scalars_free
82 end type adjoint_scalars_t
83
84contains
85
104 subroutine adjoint_scalars_init(this, n_adjoint_scalars, n_primal_scalars, &
105 msh, coef, gs, params_adjoint, params_primal, &
106 numerics_params, user, chkp, ulag, vlag, wlag, time_scheme, rho)
107 class(adjoint_scalars_t), intent(inout) :: this
108 integer, intent(in) :: n_adjoint_scalars, n_primal_scalars
109 type(mesh_t), target, intent(in) :: msh
110 type(coef_t), target, intent(in) :: coef
111 type(gs_t), target, intent(inout) :: gs
112 type(json_file), target, intent(inout) :: params_adjoint, params_primal
113 type(json_file), target, intent(inout) :: numerics_params
114 type(user_t), target, intent(in) :: user
115 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
116 type(time_scheme_controller_t), target, intent(in) :: time_scheme
117 TYPE(field_t), TARGET, INTENT(IN) :: rho
118 type(chkp_t), target, intent(inout) :: chkp
119 type(json_file) :: json_subdict_adjoint, json_subdict_primal
120 integer :: i, j
121 character(len=:), allocatable :: field_name
122 character(len=256), allocatable :: field_names(:)
123 character(len=:), allocatable :: primal_name, trial_primal_name
124 logical :: found_primal
125
126 if (n_adjoint_scalars .gt. n_primal_scalars) then
127 call neko_error("More adjoint scalars than forward scalars")
128 ! Note. This assumes every adjoint scalar must have a corresponding
129 ! primal scalar, but not the other way around.
130 end if
131
132 ! Allocate the scalar fields
133 ! If there are more adjoint_scalar_scheme_t types, add a factory function
134 ! here
135 allocate( &
136 adjoint_scalar_pnpn_t::this%adjoint_scalar_fields(n_adjoint_scalars))
137
138 allocate(field_names(n_adjoint_scalars))
139
140 ! For multiple adjoint_scalars, collect and validate field names
141 if (n_adjoint_scalars > 1) then
142 do i = 1, n_adjoint_scalars
143 ! Extract element i from the "adjoint_scalars" array
144 call json_extract_item(params_adjoint, "", i, json_subdict_adjoint)
145
146 ! Try to get name from JSON, generate one if not found or empty
147 if (json_subdict_adjoint%valid_path('name')) then
148 call json_get(json_subdict_adjoint, 'name', field_name)
149 else
150 field_name = ''
151 end if
152
153 ! If name is empty or not provided, generate a default one
154 if (len_trim(field_name) == 0) then
155 write(field_name, '(A,I0,A)') 's_', i, '_adj'
156 end if
157
158 field_names(i) = trim(field_name)
159
160 ! If there's a duplicate, append a number until unique
161 j = 1
162 do while (j < i)
163 if (trim(field_names(i)) == trim(field_names(j))) then
164 write(field_name, '(A,I0)') trim(field_names(i))//'_', j
165 field_names(i) = trim(field_name)
166 j = 1 ! Start over to check if new name is unique
167 else
168 j = j + 1
169 end if
170 end do
171 end do
172 end if
173
174 do i = 1, n_adjoint_scalars
175 call json_extract_item(params_adjoint, "", i, json_subdict_adjoint)
176
177 ! Use the processed field names for multiple adjoint_scalars
178 if (n_adjoint_scalars > 1) then
179 call json_subdict_adjoint%add('name', trim(field_names(i)))
180 else
181 call json_subdict_adjoint%add('name', 's_adj')
182 end if
183
184 ! Before initializing, find the corresponding primal scalar, and find
185 ! its subdict
186 ! note: the default primal name is s.
187 ! So we search for it if not specified
188 call json_get_or_default(params_adjoint, 'primal_name', primal_name, 's')
189
190 found_primal = .false.
191 do j = 1, n_primal_scalars
192 ! Extract element i from the "adjoint_scalars" array
193 call json_extract_item(params_primal, "", j, json_subdict_primal)
194
195 ! Try to get name from JSON
196 if (json_subdict_primal%valid_path('name')) then
197 call json_get(json_subdict_primal, 'name', trial_primal_name)
198 if (trim(trial_primal_name) == trim(primal_name)) then
199 found_primal = .true.
200 exit
201 end if
202 end if
203 end do
204
205 if (.not. found_primal) then
206 call neko_error('Could not find corresponding primal scalar name')
207 else
208 ! now we modify the json in case a name wasn't specified
209 call json_subdict_adjoint%add('primal_name', primal_name)
210 end if
211
212 call this%adjoint_scalar_fields(i)%init(msh, coef, gs, &
213 json_subdict_adjoint, json_subdict_primal, numerics_params, &
214 user, chkp, ulag, vlag, wlag, time_scheme, rho)
215 end do
216 end subroutine adjoint_scalars_init
217
234 subroutine adjoint_scalars_init_single(this, msh, coef, gs, params_adjoint, &
235 params_primal, numerics_params, user, chkp, ulag, vlag, wlag, &
236 time_scheme, rho)
237 class(adjoint_scalars_t), intent(inout) :: this
238 type(mesh_t), target, intent(in) :: msh
239 type(coef_t), target, intent(in) :: coef
240 type(gs_t), target, intent(inout) :: gs
241 type(json_file), target, intent(inout) :: params_adjoint
242 type(json_file), target, intent(inout) :: params_primal
243 type(json_file), target, intent(inout) :: numerics_params
244 type(user_t), target, intent(in) :: user
245 type(chkp_t), target, intent(inout) :: chkp
246 type(field_series_t), target, intent(in) :: ulag, vlag, wlag
247 type(time_scheme_controller_t), target, intent(in) :: time_scheme
248 TYPE(field_t), TARGET, INTENT(IN) :: rho
249
250 ! Allocate a single scalar field
251 allocate(adjoint_scalar_pnpn_t::this%adjoint_scalar_fields(1))
252
253 ! The default for primal scalar name will be s, so we force these two
254 call params_adjoint%add('name', 's_adj')
255 call params_adjoint%add('primal_name', 's')
256
257 ! TODO, there may be a corner case with multiple primal and a single adjoint
258 ! we'll need to catch that before entering this subroutine.
259
260 ! Initialize it directly with the params
261 call this%adjoint_scalar_fields(1)%init(msh, coef, gs, params_adjoint, &
262 params_primal, numerics_params, user, chkp, ulag, vlag, wlag, &
263 time_scheme, rho)
264 end subroutine adjoint_scalars_init_single
265
267 subroutine adjoint_scalars_step(this, time, ext_bdf, dt_controller)
268 class(adjoint_scalars_t), intent(inout) :: this
269 type(time_state_t), intent(in) :: time
270 type(time_scheme_controller_t), intent(inout) :: ext_bdf
271 type(time_step_controller_t), intent(inout) :: dt_controller
272 type(ksp_monitor_t), dimension(size(this%adjoint_scalar_fields)) :: ksp_results
273 integer :: i
274 logical :: all_frozen
275
276 all_frozen = .true.
277
278 ! Iterate through all scalar fields
279 do i = 1, size(this%adjoint_scalar_fields)
280 all_frozen = all_frozen .and. this%adjoint_scalar_fields(i)%freeze
281 call this%adjoint_scalar_fields(i)%step(time, ext_bdf, dt_controller, &
282 ksp_results(i))
283 end do
284
285 if (.not. all_frozen) then
286 call ksp_results(i)%print_header()
287 end if
288
289 do i = 1, size(this%adjoint_scalar_fields)
290 if (this%adjoint_scalar_fields(i)%freeze) cycle
291 call scalar_step_info(time, ksp_results(i))
292 end do
293 end subroutine adjoint_scalars_step
294
296 subroutine adjoint_scalars_restart(this, chkp)
297 class(adjoint_scalars_t), intent(inout) :: this
298 type(chkp_t), intent(inout) :: chkp
299 integer :: i
300 ! Iterate through all scalar fields
301 do i = 1, size(this%adjoint_scalar_fields)
302 call this%adjoint_scalar_fields(i)%restart(chkp)
303 end do
304 end subroutine adjoint_scalars_restart
305
307 subroutine adjoint_scalars_validate(this)
308 class(adjoint_scalars_t), intent(inout) :: this
309 integer :: i
310 ! Iterate through all scalar fields
311 do i = 1, size(this%adjoint_scalar_fields)
312 call this%adjoint_scalar_fields(i)%s_adj_lag%set(&
313 this%adjoint_scalar_fields(i)%s_adj)
314 call this%adjoint_scalar_fields(i)%validate()
315 end do
316 end subroutine adjoint_scalars_validate
317
319 subroutine adjoint_scalars_free(this)
320 class(adjoint_scalars_t), intent(inout) :: this
321 integer :: i
322
323 ! Iterate through all scalar fields
324 if (allocated(this%adjoint_scalar_fields)) then
325 do i = 1, size(this%adjoint_scalar_fields)
326 call this%adjoint_scalar_fields(i)%free()
327 end do
328 deallocate(this%adjoint_scalar_fields)
329 end if
330 end subroutine adjoint_scalars_free
331
332end module adjoint_scalars
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.
subroutine adjoint_scalars_init(this, n_adjoint_scalars, n_primal_scalars, msh, coef, gs, params_adjoint, params_primal, numerics_params, user, chkp, ulag, vlag, wlag, time_scheme, rho)
Constructor.
Base type for a scalar advection-diffusion solver.
Type to manage multiple adjoint scalar transport equations.