Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
adjoint_minimum_dissipation_source_term.f90
Go to the documentation of this file.
1
34!
36!
37!
38! If the objective function $\int |\nabla u|^2$,
39! the corresponding adjoint forcing is $ \int \nabla v \cdot \nabla u $ in weak
40! form.
42 use num_types, only: rp
43 use field_list, only: field_list_t
44 use json_module, only: json_file
45 use json_utils, only: json_get, json_get_or_default
46 use source_term, only: source_term_t
47 use coefs, only: coef_t
48 use neko_config, only: neko_bcknd_device
49 use utils, only: neko_error
50 use field, only: field_t
51 use field_math, only: field_subcol3, field_add2, field_add2s2, field_rzero
52 use json_module, only: json_file
53 use time_state, only: time_state_t
55 use simcomp_executor, only: neko_simcomps
56 use user_source_term, only: user_source_term_t
57 use num_types, only: rp
58 use field, only: field_t
59 use registry, only: neko_registry
60 use math, only: rzero, copy, chsign, cfill, invcol2
61 use device_math, only: device_copy, device_cmult, device_cfill, device_invcol2
62 use neko_config, only: neko_bcknd_device
63 use scratch_registry, only: neko_scratch_registry
65 use point_zone, only: point_zone_t
66 use ax_product, only : ax_t, ax_helm_factory
67
68 implicit none
69 private
71
73 ! $\int \nabla v \cdot \nabla u $
74 type, public, extends(source_term_t) :: &
77 type(field_t), pointer :: u => null()
79 type(field_t), pointer :: v => null()
81 type(field_t), pointer :: w => null()
83 real(kind=rp) :: obj_scale
85 class(point_zone_t), pointer :: mask => null()
87 logical :: if_mask
89 class(ax_t), allocatable :: ax
91 real(kind=rp) :: volume
92
93 contains
95 procedure, pass(this) :: init => &
96 adjoint_minimum_dissipation_source_term_init_from_json
98 procedure, pass(this) :: init_from_components => &
99 adjoint_minimum_dissipation_source_term_init_from_components
101 procedure, pass(this) :: free => &
102 adjoint_minimum_dissipation_source_term_free
104 procedure, pass(this) :: compute_ => &
105 adjoint_minimum_dissipation_source_term_compute
107
108contains
109
112 class(source_term_t), allocatable, intent(inout) :: obj
115
122 subroutine adjoint_minimum_dissipation_source_term_init_from_json(this, &
123 json, fields, coef, variable_name)
124 class(adjoint_minimum_dissipation_source_term_t), intent(inout) :: this
125 type(json_file), intent(inout) :: json
126 type(field_list_t), intent(in), target :: fields
127 type(coef_t), intent(in), target :: coef
128 character(len=*), intent(in) :: variable_name
129
130 ! we shouldn't be initializing this from JSON
131 ! maybe throw an error?
132
133
134 end subroutine adjoint_minimum_dissipation_source_term_init_from_json
135
145 subroutine adjoint_minimum_dissipation_source_term_init_from_components(this,&
146 f_x, f_y, f_z, &
147 u, v, w, obj_scale, &
148 mask, if_mask, &
149 coef, volume)
150 class(adjoint_minimum_dissipation_source_term_t), intent(inout) :: this
151 type(field_t), pointer, intent(in) :: f_x, f_y, f_z
152 type(field_list_t) :: fields
153 type(coef_t) :: coef
154 real(kind=rp) :: start_time
155 real(kind=rp) :: end_time
156 real(kind=rp) :: obj_scale
157 type(field_t), intent(in), target :: u, v, w
158 class(point_zone_t), intent(in), target :: mask
159 real(kind=rp), intent(in) :: volume
160 logical :: if_mask
161
162 ! I wish you didn't need a start time and end time...
163 ! but I'm just going to set a super big number...
164 start_time = 0.0_rp
165 end_time = 100000000.0_rp
166
167 call this%free()
168
169 ! this is copying the fluid source term init
170 ! We package the fields for the source term to operate on in a field list.
171 call fields%init(3)
172 call fields%assign(1, f_x)
173 call fields%assign(2, f_y)
174 call fields%assign(3, f_z)
175
176 call this%init_base(fields, coef, start_time, end_time)
177
178 ! point everything in the correct places
179 this%u => u
180 this%v => v
181 this%w => w
182
183 this%obj_scale = obj_scale
184 this%volume = volume
185
186 this%if_mask = if_mask
187 if (this%if_mask) then
188 this%mask => mask
189 end if
190
191 ! Initialize the ax_helm object
192 call ax_helm_factory(this%Ax, full_formulation = .false.)
193
194 end subroutine adjoint_minimum_dissipation_source_term_init_from_components
195
197 subroutine adjoint_minimum_dissipation_source_term_free(this)
198 class(adjoint_minimum_dissipation_source_term_t), intent(inout) :: this
199
200 call this%free_base()
201 nullify(this%u)
202 nullify(this%v)
203 nullify(this%w)
204 nullify(this%mask)
205 if (allocated(this%Ax)) then
206 deallocate(this%Ax)
207 end if
208
209 end subroutine adjoint_minimum_dissipation_source_term_free
210
214 subroutine adjoint_minimum_dissipation_source_term_compute(this, time)
215 class(adjoint_minimum_dissipation_source_term_t), intent(inout) :: this
216 type(time_state_t), intent(in) :: time
217 type(field_t), pointer :: u, v, w
218 type(field_t), pointer :: fu, fv, fw
219 type(field_t), pointer :: work
220 integer :: temp_indices(1)
221 integer n
222
223 fu => this%fields%get_by_index(1)
224 fv => this%fields%get_by_index(2)
225 fw => this%fields%get_by_index(3)
226
227 n = fu%size()
228
229 u => this%u
230 v => this%v
231 w => this%w
232
233 call neko_scratch_registry%request_field(work, temp_indices(1), .false.)
234
235 associate(coef => this%coef)
236
237 ! Note that axhelm computes h1 * lap u + h2 * u
238 ! we set h1 = 1 and h2 = 0 to compute the weak laplacian.
239 if (neko_bcknd_device .eq. 1) then
240 call device_cfill(coef%h1_d, 1.0_rp, n)
241 call device_cfill(coef%h2_d, 0.0_rp, n)
242 else
243 call cfill(coef%h1, 1.0_rp, n)
244 call cfill(coef%h2, 0.0_rp, n)
245 end if
246 coef%ifh2 = .false.
247
248 ! ------------------------------------------------------------------------
249 ! u
250
251 call this%Ax%compute(work%x, u%x, coef, coef%msh, coef%xh)
252
253 ! pre-divide out the mass matrix to counteract it's multiplication
254 if (neko_bcknd_device .eq. 1) then
255 call device_invcol2(work%x_d, coef%B_d, work%size())
256 else
257 call invcol2(work%x, coef%B, work%size())
258 end if
259
260 ! mask
261 if (this%if_mask) then
262 call mask_exterior_const(work, this%mask, 0.0_rp)
263 end if
264
265 ! add to RHS
266 call field_add2s2(fu, work, this%obj_scale / this%volume)
267
268 ! ------------------------------------------------------------------------
269 ! v
270
271 call this%Ax%compute(work%x, v%x, coef, coef%msh, coef%xh)
272
273 ! pre-divide out the mass matrix to counteract it's multiplication
274 if (neko_bcknd_device .eq. 1) then
275 call device_invcol2(work%x_d, coef%B_d, work%size())
276 else
277 call invcol2(work%x, coef%B, work%size())
278 end if
279
280 ! mask
281 if (this%if_mask) then
282 call mask_exterior_const(work, this%mask, 0.0_rp)
283 end if
284
285 ! add to RHS
286 call field_add2s2(fv, work, this%obj_scale / this%volume)
287
288 ! ------------------------------------------------------------------------
289 ! w
290
291 call this%Ax%compute(work%x, w%x, coef, coef%msh, coef%xh)
292
293 ! pre-divide out the mass matrix to counteract it's multiplication
294 if (neko_bcknd_device .eq. 1) then
295 call device_invcol2(work%x_d, coef%B_d, work%size())
296 else
297 call invcol2(work%x, coef%B, work%size())
298 end if
299
300 ! mask
301 if (this%if_mask) then
302 call mask_exterior_const(work, this%mask, 0.0_rp)
303 end if
304
305 ! add to RHS
306 call field_add2s2(fw, work, this%obj_scale / this%volume)
307
308 call neko_scratch_registry%relinquish_field(temp_indices)
309
310 end associate
311
312 end subroutine adjoint_minimum_dissipation_source_term_compute
313
Implements the adjoint_minimum_dissipation_source_term_t type.
subroutine, public adjoint_minimum_dissipation_source_term_allocate(obj)
Allocator for the adjoint minimum dissipation source term.
Some common Masking operations we may need.
Definition mask_ops.f90:36
Implements the steady_simcomp_t type.
The steady_simcomp_t type is a simulation component that terminates a simulation when the normed diff...