Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
minimum_dissipation_objective.f90
Go to the documentation of this file.
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, 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
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
92 ! $ F = \int_\Omega |\nabla u|^2 d \Omega + K \int_Omega \frac{1}{2} \chi
93 ! |\mathbf{u}|^2 d \Omega $
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 => minimum_dissipation_init_json
117 procedure, public, pass(this) :: init_from_attributes => &
120 procedure, public, pass(this) :: free => minimum_dissipation_free
122 procedure, public, pass(this) :: update_value => &
125 procedure, public, pass(this) :: update_sensitivity => &
127
129
130contains
131
136 subroutine minimum_dissipation_init_json(this, json, design, simulation)
137 class(minimum_dissipation_objective_t), intent(inout) :: this
138 type(json_file), intent(inout) :: json
139 class(design_t), intent(in) :: design
140 type(simulation_t), target, intent(inout) :: simulation
141 character(len=:), allocatable :: name
142 character(len=:), allocatable :: mask_name
143 real(kind=rp) :: weight
144
145 call json_get_or_default(json, "weight", weight, 1.0_rp)
146 call json_get_or_default(json, "mask_name", mask_name, "")
147 call json_get_or_default(json, "name", name, "Dissipation")
148
149 call this%init_from_attributes(design, simulation, weight, name, mask_name)
150 end subroutine minimum_dissipation_init_json
151
157 subroutine minimum_dissipation_init_attributes(this, design, simulation, &
158 weight, name, mask_name)
159 class(minimum_dissipation_objective_t), intent(inout) :: this
160 class(design_t), intent(in) :: design
161 type(simulation_t), target, intent(inout) :: simulation
162 real(kind=rp), intent(in) :: weight
163 character(len=*), intent(in) :: name
164 character(len=*), intent(in) :: mask_name
165
166 type(adjoint_minimum_dissipation_source_term_t) :: adjoint_forcing
167
168 call this%init_base(name, design%size(), weight, mask_name)
169
170 ! Save the simulation and design
171 this%u => neko_field_registry%get_field('u')
172 this%v => neko_field_registry%get_field('v')
173 this%w => neko_field_registry%get_field('w')
174 this%c_Xh => simulation%fluid_scheme%c_Xh
175 this%adjoint_u => neko_field_registry%get_field('u_adj')
176 this%adjoint_v => neko_field_registry%get_field('v_adj')
177 this%adjoint_w => neko_field_registry%get_field('w_adj')
178
179 ! you will need to init this!
180 ! append a source term based on the minimum dissipation
181 ! init the adjoint forcing term for the adjoint
182 call adjoint_forcing%init_from_components( &
183 simulation%adjoint_case%scheme%f_adj_x, &
184 simulation%adjoint_case%scheme%f_adj_y, &
185 simulation%adjoint_case%scheme%f_adj_z, &
186 this%u, this%v, this%w, this%weight, &
187 this%mask, this%has_mask, &
188 this%c_Xh)
189
190 ! append adjoint forcing term based on objective function
191 call simulation%adjoint_case%scheme%source_term%add_source_term( &
192 adjoint_forcing)
193
195
198 class(minimum_dissipation_objective_t), intent(inout) :: this
199 call this%free_base()
200
201 if (associated(this%u)) nullify(this%u)
202 if (associated(this%v)) nullify(this%v)
203 if (associated(this%w)) nullify(this%w)
204 if (associated(this%c_Xh)) nullify(this%c_Xh)
205
206 if (associated(this%adjoint_u)) nullify(this%adjoint_u)
207 if (associated(this%adjoint_v)) nullify(this%adjoint_v)
208 if (associated(this%adjoint_w)) nullify(this%adjoint_w)
209
210 end subroutine minimum_dissipation_free
211
216 subroutine minimum_dissipation_update_value(this, design)
217 class(minimum_dissipation_objective_t), intent(inout) :: this
218 class(design_t), intent(in) :: design
219 type(field_t), pointer :: wo1, wo2, wo3, work
220 type(field_t), pointer :: objective_field
221 integer :: temp_indices(5)
222 integer n
223
224 call neko_scratch_registry%request_field(wo1, temp_indices(1))
225 call neko_scratch_registry%request_field(wo2, temp_indices(2))
226 call neko_scratch_registry%request_field(wo3, temp_indices(3))
227 call neko_scratch_registry%request_field(objective_field, temp_indices(4))
228 call neko_scratch_registry%request_field(work, temp_indices(5))
229
230 ! update_value the objective function.
231 call grad(wo1%x, wo2%x, wo3%x, this%u%x, this%c_Xh)
232 call field_col3(objective_field, wo1, wo1)
233 call field_addcol3(objective_field, wo2, wo2)
234 call field_addcol3(objective_field, wo3, wo3)
235
236 call grad(wo1%x, wo2%x, wo3%x, this%v%x, this%c_Xh)
237 call field_addcol3(objective_field, wo1, wo1)
238 call field_addcol3(objective_field, wo2, wo2)
239 call field_addcol3(objective_field, wo3, wo3)
240
241 call grad(wo1%x, wo2%x, wo3%x, this%w%x, this%c_Xh)
242 call field_addcol3(objective_field, wo1, wo1)
243 call field_addcol3(objective_field, wo2, wo2)
244 call field_addcol3(objective_field, wo3, wo3)
245
246 ! integrate the field
247 n = wo1%size()
248 if (this%has_mask) then
249 if (neko_bcknd_device .eq. 1) then
250 ! note, this could be done more elagantly by writing
251 ! device_glsc2_mask
252 call field_copy(work, objective_field)
253 call mask_exterior_const(work, this%mask, 0.0_rp)
254 this%value = device_glsc2(work%x_d, this%c_xh%B_d, n)
255 else
256 this%value = glsc2_mask(objective_field%x, this%C_Xh%b, &
257 n, this%mask%mask, this%mask%size)
258 end if
259 else
260 if (neko_bcknd_device .eq. 1) then
261 this%value = device_glsc2(objective_field%x_d, &
262 this%C_Xh%b_d, n)
263 else
264 this%value = glsc2(objective_field%x, this%C_Xh%b, n)
265 end if
266 end if
267
268 call neko_scratch_registry%relinquish_field(temp_indices)
269
271
275 class(minimum_dissipation_objective_t), intent(inout) :: this
276 class(design_t), intent(in) :: design
277 type(field_t), pointer :: work
278 integer :: temp_indices(1)
279
280 call neko_scratch_registry%request_field(work, temp_indices(1))
281
282 ! here it should just be an inner product between the forward and adjoint
283 call field_col3(work, this%u, this%adjoint_u)
284 call field_addcol3(work, this%v, this%adjoint_v)
285 call field_addcol3(work, this%w, this%adjoint_w)
286 ! but negative
287 call field_cmult(work, -1.0_rp)
288
289 if (neko_bcknd_device .eq. 1) then
290 call device_copy(this%sensitivity%x_d, work%x_d, this%sensitivity%size())
291 else
292 call copy(this%sensitivity%x, work%x, this%sensitivity%size())
293 end if
294
295 call neko_scratch_registry%relinquish_field(temp_indices)
296
298
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
real(kind=rp) function glsc2_mask(a, b, size, mask, mask_size)
Weighted inner product for indices in the mask.
Definition math_ext.f90:117
Implements the minimum_dissipation_objective_t type.
subroutine minimum_dissipation_init_attributes(this, design, simulation, weight, name, mask_name)
The actual constructor.
subroutine minimum_dissipation_free(this)
Destructor.
subroutine minimum_dissipation_update_value(this, design)
Compute the objective function.
subroutine minimum_dissipation_update_sensitivity(this, design)
update_value the sensitivity of the objective function with respect to
subroutine minimum_dissipation_init_json(this, json, design, simulation)
The common constructor using a JSON object.
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:48
An objective function corresponding to minimum dissipation.
The abstract objective type.
Definition objective.f90:51