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
69 use scratch_registry, only: neko_scratch_registry
72 use objective, only: objective_t
73 use simulation_m, only: simulation_t
75 use coefs, only: coef_t
76 use field_registry, only: neko_field_registry
77 use neko_config, only: neko_bcknd_device
78 use math, only: glsc2, copy
79 use device_math, only: device_copy, device_glsc2
80 use design, only: design_t
81 use brinkman_design, only: brinkman_design_t
82 use point_zone, only: point_zone_t
84 use math_ext, only: glsc2_mask
85 use utils, only: neko_error
86 use json_module, only: json_file
87 use json_utils, only: json_get_or_default
88 implicit none
89 private
90
95 private
96
98 type(field_t), pointer :: u => null()
100 type(field_t), pointer :: v => null()
102 type(field_t), pointer :: w => null()
104 type(coef_t), pointer :: c_xh => null()
105
107 type(field_t), pointer :: adjoint_u => null()
109 type(field_t), pointer :: adjoint_v => null()
111 type(field_t), pointer :: adjoint_w => null()
112
113 contains
115 procedure, public, pass(this) :: init_json_sim => &
116 minimum_dissipation_init_json_sim
118 procedure, public, pass(this) :: init_from_attributes => &
119 minimum_dissipation_init_attributes
121 procedure, public, pass(this) :: free => minimum_dissipation_free
123 procedure, public, pass(this) :: update_value => &
124 minimum_dissipation_update_value
126 procedure, public, pass(this) :: update_sensitivity => &
127 minimum_dissipation_update_sensitivity
128
130
131contains
132
138 subroutine minimum_dissipation_init_json_sim(this, json, design, simulation)
139 class(minimum_dissipation_objective_t), intent(inout) :: this
140 type(json_file), intent(inout) :: json
141 class(design_t), intent(in) :: design
142 type(simulation_t), target, intent(inout) :: simulation
143
144 character(len=:), allocatable :: name
145 character(len=:), allocatable :: mask_name
146 real(kind=rp) :: weight
147
148 call json_get_or_default(json, "weight", weight, 1.0_rp)
149 call json_get_or_default(json, "mask_name", mask_name, "")
150 call json_get_or_default(json, "name", name, "Dissipation")
151
152 call this%init_from_attributes(design, simulation, weight, name, mask_name)
153 end subroutine minimum_dissipation_init_json_sim
154
162 subroutine minimum_dissipation_init_attributes(this, design, simulation, &
163 weight, name, mask_name)
164 class(minimum_dissipation_objective_t), intent(inout) :: this
165 class(design_t), intent(in) :: design
166 type(simulation_t), target, intent(inout) :: simulation
167 real(kind=rp), intent(in) :: weight
168 character(len=*), intent(in) :: name
169 character(len=*), intent(in) :: mask_name
170
171 type(adjoint_minimum_dissipation_source_term_t) :: adjoint_forcing
172
173 call this%init_base(name, design%size(), weight, mask_name)
174
175 ! Save the simulation and design
176 this%u => neko_field_registry%get_field('u')
177 this%v => neko_field_registry%get_field('v')
178 this%w => neko_field_registry%get_field('w')
179 this%c_Xh => simulation%fluid%c_Xh
180 this%adjoint_u => neko_field_registry%get_field('u_adj')
181 this%adjoint_v => neko_field_registry%get_field('v_adj')
182 this%adjoint_w => neko_field_registry%get_field('w_adj')
183
184 ! you will need to init this!
185 ! append a source term based on the minimum dissipation
186 ! init the adjoint forcing term for the adjoint
187 call adjoint_forcing%init_from_components( &
188 simulation%adjoint_fluid%f_adj_x, &
189 simulation%adjoint_fluid%f_adj_y, &
190 simulation%adjoint_fluid%f_adj_z, &
191 this%u, this%v, this%w, this%weight, &
192 this%mask, this%has_mask, &
193 this%c_Xh)
194
195 ! append adjoint forcing term based on objective function
196 call simulation%adjoint_fluid%source_term%add_source_term(adjoint_forcing)
197
198 end subroutine minimum_dissipation_init_attributes
199
201 subroutine minimum_dissipation_free(this)
202 class(minimum_dissipation_objective_t), intent(inout) :: this
203 call this%free_base()
204
205 if (associated(this%u)) nullify(this%u)
206 if (associated(this%v)) nullify(this%v)
207 if (associated(this%w)) nullify(this%w)
208 if (associated(this%c_Xh)) nullify(this%c_Xh)
209
210 if (associated(this%adjoint_u)) nullify(this%adjoint_u)
211 if (associated(this%adjoint_v)) nullify(this%adjoint_v)
212 if (associated(this%adjoint_w)) nullify(this%adjoint_w)
213
214 end subroutine minimum_dissipation_free
215
219 subroutine minimum_dissipation_update_value(this, design)
220 class(minimum_dissipation_objective_t), intent(inout) :: this
221 class(design_t), intent(in) :: design
222 type(field_t), pointer :: wo1, wo2, wo3, work
223 type(field_t), pointer :: objective_field
224 integer :: temp_indices(5)
225 integer n
226
227 call neko_scratch_registry%request_field(wo1, temp_indices(1))
228 call neko_scratch_registry%request_field(wo2, temp_indices(2))
229 call neko_scratch_registry%request_field(wo3, temp_indices(3))
230 call neko_scratch_registry%request_field(objective_field, temp_indices(4))
231 call neko_scratch_registry%request_field(work, temp_indices(5))
232
233 ! update_value the objective function.
234 call grad(wo1%x, wo2%x, wo3%x, this%u%x, this%c_Xh)
235 call field_col3(objective_field, wo1, wo1)
236 call field_addcol3(objective_field, wo2, wo2)
237 call field_addcol3(objective_field, wo3, wo3)
238
239 call grad(wo1%x, wo2%x, wo3%x, this%v%x, this%c_Xh)
240 call field_addcol3(objective_field, wo1, wo1)
241 call field_addcol3(objective_field, wo2, wo2)
242 call field_addcol3(objective_field, wo3, wo3)
243
244 call grad(wo1%x, wo2%x, wo3%x, this%w%x, this%c_Xh)
245 call field_addcol3(objective_field, wo1, wo1)
246 call field_addcol3(objective_field, wo2, wo2)
247 call field_addcol3(objective_field, wo3, wo3)
248
249 ! integrate the field
250 n = wo1%size()
251 if (this%has_mask) then
252 if (neko_bcknd_device .eq. 1) then
253 ! note, this could be done more elagantly by writing
254 ! device_glsc2_mask
255 call field_copy(work, objective_field)
256 call mask_exterior_const(work, this%mask, 0.0_rp)
257 this%value = device_glsc2(work%x_d, this%c_xh%B_d, n)
258 else
259 this%value = glsc2_mask(objective_field%x, this%C_Xh%b, &
260 n, this%mask%mask, this%mask%size)
261 end if
262 else
263 if (neko_bcknd_device .eq. 1) then
264 this%value = device_glsc2(objective_field%x_d, &
265 this%C_Xh%b_d, n)
266 else
267 this%value = glsc2(objective_field%x, this%C_Xh%b, n)
268 end if
269 end if
270
271 call neko_scratch_registry%relinquish_field(temp_indices)
272
273 end subroutine minimum_dissipation_update_value
274
278 subroutine minimum_dissipation_update_sensitivity(this, design)
279 class(minimum_dissipation_objective_t), intent(inout) :: this
280 class(design_t), intent(in) :: design
281 type(field_t), pointer :: work
282 integer :: temp_indices(1)
283
284 call neko_scratch_registry%request_field(work, temp_indices(1))
285
286 ! here it should just be an inner product between the forward and adjoint
287 call field_col3(work, this%u, this%adjoint_u)
288 call field_addcol3(work, this%v, this%adjoint_v)
289 call field_addcol3(work, this%w, this%adjoint_w)
290 ! but negative
291 call field_cmult(work, -1.0_rp)
292
293 if (neko_bcknd_device .eq. 1) then
294 call device_copy(this%sensitivity%x_d, work%x_d, this%sensitivity%size())
295 else
296 call copy(this%sensitivity%x, work%x, this%sensitivity%size())
297 end if
298
299 call neko_scratch_registry%relinquish_field(temp_indices)
300
301 end subroutine minimum_dissipation_update_sensitivity
302
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