Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
minimum_dissipation_objective.f90
1! Copyright (c) 2024-25, 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!
34!
35! I promise I'll write this document properly in the future...
36!
37! But the Borval Peterson (I think) paper had an objective function
38! that had 2 terms, dissipation and this term they claimed represented
39! out of plane stresses.
40! I never really understood that extra term, I also don't think it
41! applies to 3D cases, but everyone includes it anyway.
42!
43! It appears to me to be basically a heuristic penality that targets
44! non-binary designs
45!
46! so let's call
47!
48! F = \int |\nabla u|^2 + K \int \chi \u^2
49!
50! | dissipation | |"lube term"|
51!
52! I say "lube term" because they said it came from lubrication theory...
53! Anyway, we can change all this later (especially the names!)
54
55! If the objective function \int |\nabla u|^2,
56! the corresponding adjoint forcing is \int \nabla v \cdot \nabla u
57!
58! for the lube term, the adjoint forcing is \chi u
59!
60! This has always annoyed me...
61! because now I see one objective and one constraint
62!
64 use num_types, only: rp
65 use field, only: field_t
66 use field_math, only: field_col3, field_addcol3, field_cmult, field_add2s2, &
67 field_copy
68 use operators, only: grad
70 use scratch_registry, only: neko_scratch_registry
73 use objective, only: objective_t
74 use simulation_m, only: simulation_t
75 use adjoint_fluid_scheme, only: adjoint_fluid_scheme_t
76 use coefs, only: coef_t
77 use field_registry, only: neko_field_registry
78 use neko_config, only: neko_bcknd_device
79 use math, only: glsc2, copy
80 use device_math, only: device_copy, device_glsc2
81 use design, only: design_t
82 use brinkman_design, only: brinkman_design_t
83 use point_zone, only: point_zone_t
85 use math_ext, only: glsc2_mask
86 use utils, only: neko_error
87 use json_module, only: json_file
88 use json_utils, only: json_get_or_default
89 implicit none
90 private
91
96 private
97
99 type(field_t), pointer :: u => null()
101 type(field_t), pointer :: v => null()
103 type(field_t), pointer :: w => null()
105 type(coef_t), pointer :: c_xh => null()
106
108 type(field_t), pointer :: adjoint_u => null()
110 type(field_t), pointer :: adjoint_v => null()
112 type(field_t), pointer :: adjoint_w => null()
113
114 contains
116 procedure, public, pass(this) :: init_json_sim => &
117 minimum_dissipation_init_json_sim
119 procedure, public, pass(this) :: init_from_attributes => &
120 minimum_dissipation_init_attributes
122 procedure, public, pass(this) :: free => minimum_dissipation_free
124 procedure, public, pass(this) :: update_value => &
125 minimum_dissipation_update_value
127 procedure, public, pass(this) :: update_sensitivity => &
128 minimum_dissipation_update_sensitivity
129
131
132contains
133
139 subroutine minimum_dissipation_init_json_sim(this, json, design, simulation)
140 class(minimum_dissipation_objective_t), intent(inout) :: this
141 type(json_file), intent(inout) :: json
142 class(design_t), intent(in) :: design
143 type(simulation_t), target, intent(inout) :: simulation
144
145 character(len=:), allocatable :: name
146 character(len=:), allocatable :: mask_name
147 real(kind=rp) :: weight
148
149 call json_get_or_default(json, "weight", weight, 1.0_rp)
150 call json_get_or_default(json, "mask_name", mask_name, "")
151 call json_get_or_default(json, "name", name, "Dissipation")
152
153 call this%init_from_attributes(design, simulation, weight, name, mask_name)
154 end subroutine minimum_dissipation_init_json_sim
155
163 subroutine minimum_dissipation_init_attributes(this, design, simulation, &
164 weight, name, mask_name)
165 class(minimum_dissipation_objective_t), intent(inout) :: this
166 class(design_t), intent(in) :: design
167 type(simulation_t), target, intent(inout) :: simulation
168 real(kind=rp), intent(in) :: weight
169 character(len=*), intent(in) :: name
170 character(len=*), intent(in) :: mask_name
171
172 type(adjoint_minimum_dissipation_source_term_t) :: adjoint_forcing
173
174 call this%init_base(name, design%size(), weight, mask_name)
175
176 ! Save the simulation and design
177 this%u => neko_field_registry%get_field('u')
178 this%v => neko_field_registry%get_field('v')
179 this%w => neko_field_registry%get_field('w')
180 this%c_Xh => simulation%fluid%c_Xh
181 this%adjoint_u => neko_field_registry%get_field('u_adj')
182 this%adjoint_v => neko_field_registry%get_field('v_adj')
183 this%adjoint_w => neko_field_registry%get_field('w_adj')
184
185 ! you will need to init this!
186 ! append a source term based on the minimum dissipation
187 ! init the adjoint forcing term for the adjoint
188 call adjoint_forcing%init_from_components( &
189 simulation%adjoint_fluid%f_adj_x, &
190 simulation%adjoint_fluid%f_adj_y, &
191 simulation%adjoint_fluid%f_adj_z, &
192 this%u, this%v, this%w, this%weight, &
193 this%mask, this%has_mask, &
194 this%c_Xh)
195
196 ! append adjoint forcing term based on objective function
197 select type (f => simulation%adjoint_fluid)
198 type is (adjoint_fluid_pnpn_t)
199 call f%source_term%add_source_term(adjoint_forcing)
200 end select
201
202 end subroutine minimum_dissipation_init_attributes
203
205 subroutine minimum_dissipation_free(this)
206 class(minimum_dissipation_objective_t), intent(inout) :: this
207 call this%free_base()
208
209 if (associated(this%u)) nullify(this%u)
210 if (associated(this%v)) nullify(this%v)
211 if (associated(this%w)) nullify(this%w)
212 if (associated(this%c_Xh)) nullify(this%c_Xh)
213
214 if (associated(this%adjoint_u)) nullify(this%adjoint_u)
215 if (associated(this%adjoint_v)) nullify(this%adjoint_v)
216 if (associated(this%adjoint_w)) nullify(this%adjoint_w)
217
218 end subroutine minimum_dissipation_free
219
223 subroutine minimum_dissipation_update_value(this, design)
224 class(minimum_dissipation_objective_t), intent(inout) :: this
225 class(design_t), intent(in) :: design
226 type(field_t), pointer :: wo1, wo2, wo3, work
227 type(field_t), pointer :: objective_field
228 integer :: temp_indices(5)
229 integer n
230
231 call neko_scratch_registry%request_field(wo1, temp_indices(1))
232 call neko_scratch_registry%request_field(wo2, temp_indices(2))
233 call neko_scratch_registry%request_field(wo3, temp_indices(3))
234 call neko_scratch_registry%request_field(objective_field, temp_indices(4))
235 call neko_scratch_registry%request_field(work, temp_indices(5))
236
237 ! update_value the objective function.
238 call grad(wo1%x, wo2%x, wo3%x, this%u%x, this%c_Xh)
239 call field_col3(objective_field, wo1, wo1)
240 call field_addcol3(objective_field, wo2, wo2)
241 call field_addcol3(objective_field, wo3, wo3)
242
243 call grad(wo1%x, wo2%x, wo3%x, this%v%x, this%c_Xh)
244 call field_addcol3(objective_field, wo1, wo1)
245 call field_addcol3(objective_field, wo2, wo2)
246 call field_addcol3(objective_field, wo3, wo3)
247
248 call grad(wo1%x, wo2%x, wo3%x, this%w%x, this%c_Xh)
249 call field_addcol3(objective_field, wo1, wo1)
250 call field_addcol3(objective_field, wo2, wo2)
251 call field_addcol3(objective_field, wo3, wo3)
252
253 ! integrate the field
254 n = wo1%size()
255 if (this%has_mask) then
256 if (neko_bcknd_device .eq. 1) then
257 ! note, this could be done more elagantly by writing
258 ! device_glsc2_mask
259 call field_copy(work, objective_field)
260 call mask_exterior_const(work, this%mask, 0.0_rp)
261 this%value = device_glsc2(work%x_d, this%c_xh%B_d, n)
262 else
263 this%value = glsc2_mask(objective_field%x, this%C_Xh%b, &
264 n, this%mask%mask, this%mask%size)
265 end if
266 else
267 if (neko_bcknd_device .eq. 1) then
268 this%value = device_glsc2(objective_field%x_d, &
269 this%C_Xh%b_d, n)
270 else
271 this%value = glsc2(objective_field%x, this%C_Xh%b, n)
272 end if
273 end if
274
275 call neko_scratch_registry%relinquish_field(temp_indices)
276
277 end subroutine minimum_dissipation_update_value
278
282 subroutine minimum_dissipation_update_sensitivity(this, design)
283 class(minimum_dissipation_objective_t), intent(inout) :: this
284 class(design_t), intent(in) :: design
285 type(field_t), pointer :: work
286 integer :: temp_indices(1)
287
288 call neko_scratch_registry%request_field(work, temp_indices(1))
289
290 ! here it should just be an inner product between the forward and adjoint
291 call field_col3(work, this%u, this%adjoint_u)
292 call field_addcol3(work, this%v, this%adjoint_v)
293 call field_addcol3(work, this%w, this%adjoint_w)
294 ! but negative
295 call field_cmult(work, -1.0_rp)
296
297 if (neko_bcknd_device .eq. 1) then
298 call device_copy(this%sensitivity%x_d, work%x_d, this%sensitivity%size())
299 else
300 call copy(this%sensitivity%x, work%x, this%sensitivity%size())
301 end if
302
303 call neko_scratch_registry%relinquish_field(temp_indices)
304
305 end subroutine minimum_dissipation_update_sensitivity
306
Adjoint Pn/Pn formulation.
Implements the adjoint_minimum_dissipation_source_term_t type.
Implements the design_t.
Definition design.f90:34
Some common Masking operations we may need.
Definition mask_ops.f90:34
Implements the minimum_dissipation_objective_t type.
Implements the objective_t type.
Definition objective.f90:35
Implements the steady_problem_t type.
A topology optimization design variable.
An abstract design type.
Definition design.f90:50
An objective function corresponding to minimum dissipation .
The abstract objective type.
Definition objective.f90:51