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
84 use mask_ops, only: mask_exterior_const, compute_masked_volume
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
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()
106 type(field_t), pointer :: adjoint_u => null()
108 type(field_t), pointer :: adjoint_v => null()
110 type(field_t), pointer :: adjoint_w => null()
112 real(kind=rp) :: volume
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 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 ! compute the volume of the objective domain
185 if (this%has_mask) then
186 this%volume = compute_masked_volume(this%mask, this%c_Xh)
187 else
188 this%volume = this%c_Xh%volume
189 end if
190
191 ! you will need to init this!
192 ! append a source term based on the minimum dissipation
193 ! init the adjoint forcing term for the adjoint
194 call adjoint_forcing%init_from_components( &
195 simulation%adjoint_fluid%f_adj_x, &
196 simulation%adjoint_fluid%f_adj_y, &
197 simulation%adjoint_fluid%f_adj_z, &
198 this%u, this%v, this%w, this%weight, &
199 this%mask, this%has_mask, &
200 this%c_Xh, this%volume)
201
202 ! append adjoint forcing term based on objective function
203 select type (f => simulation%adjoint_fluid)
204 type is (adjoint_fluid_pnpn_t)
205 call f%source_term%add_source_term(adjoint_forcing)
206 end select
207
208 end subroutine minimum_dissipation_init_attributes
209
211 subroutine minimum_dissipation_free(this)
212 class(minimum_dissipation_objective_t), intent(inout) :: this
213 call this%free_base()
214
215 if (associated(this%u)) nullify(this%u)
216 if (associated(this%v)) nullify(this%v)
217 if (associated(this%w)) nullify(this%w)
218 if (associated(this%c_Xh)) nullify(this%c_Xh)
219
220 if (associated(this%adjoint_u)) nullify(this%adjoint_u)
221 if (associated(this%adjoint_v)) nullify(this%adjoint_v)
222 if (associated(this%adjoint_w)) nullify(this%adjoint_w)
223
224 end subroutine minimum_dissipation_free
225
229 subroutine minimum_dissipation_update_value(this, design)
230 class(minimum_dissipation_objective_t), intent(inout) :: this
231 class(design_t), intent(in) :: design
232 type(field_t), pointer :: wo1, wo2, wo3, work
233 type(field_t), pointer :: objective_field
234 integer :: temp_indices(5)
235 integer n
236
237 call neko_scratch_registry%request_field(wo1, temp_indices(1))
238 call neko_scratch_registry%request_field(wo2, temp_indices(2))
239 call neko_scratch_registry%request_field(wo3, temp_indices(3))
240 call neko_scratch_registry%request_field(objective_field, temp_indices(4))
241 call neko_scratch_registry%request_field(work, temp_indices(5))
242
243 ! update_value the objective function.
244 call grad(wo1%x, wo2%x, wo3%x, this%u%x, this%c_Xh)
245 call field_col3(objective_field, wo1, wo1)
246 call field_addcol3(objective_field, wo2, wo2)
247 call field_addcol3(objective_field, wo3, wo3)
248
249 call grad(wo1%x, wo2%x, wo3%x, this%v%x, this%c_Xh)
250 call field_addcol3(objective_field, wo1, wo1)
251 call field_addcol3(objective_field, wo2, wo2)
252 call field_addcol3(objective_field, wo3, wo3)
253
254 call grad(wo1%x, wo2%x, wo3%x, this%w%x, this%c_Xh)
255 call field_addcol3(objective_field, wo1, wo1)
256 call field_addcol3(objective_field, wo2, wo2)
257 call field_addcol3(objective_field, wo3, wo3)
258
259 ! integrate the field
260 n = wo1%size()
261 if (this%has_mask) then
262 if (neko_bcknd_device .eq. 1) then
263 ! note, this could be done more elagantly by writing
264 ! device_glsc2_mask
265 call field_copy(work, objective_field)
266 call mask_exterior_const(work, this%mask, 0.0_rp)
267 this%value = device_glsc2(work%x_d, this%c_xh%B_d, n)
268 else
269 this%value = glsc2_mask(objective_field%x, this%c_Xh%b, &
270 n, this%mask%mask%get(), this%mask%size)
271 end if
272 else
273 if (neko_bcknd_device .eq. 1) then
274 this%value = device_glsc2(objective_field%x_d, &
275 this%c_Xh%b_d, n)
276 else
277 this%value = glsc2(objective_field%x, this%c_Xh%b, n)
278 end if
279 end if
280
281 this%value = this%value * 0.5_rp / this%volume
282
283 call neko_scratch_registry%relinquish_field(temp_indices)
284
285 end subroutine minimum_dissipation_update_value
286
290 subroutine minimum_dissipation_update_sensitivity(this, design)
291 class(minimum_dissipation_objective_t), intent(inout) :: this
292 class(design_t), intent(in) :: design
293
294 end subroutine minimum_dissipation_update_sensitivity
295
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:52
An objective function corresponding to minimum dissipation .
The abstract objective type.
Definition objective.f90:51