Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
volume_constraint.f90
1! Copyright (c) 2023, 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! $V = \frac{1}{|\Omega_O|}\int_{\Omega_O} \tilde{\rho} d\Omega$
35! Either
36! $V < V_\text{max}$
37! $V > V_\text{min}$
39 use constraint, only: constraint_t
40
41 use design, only: design_t
42 use brinkman_design, only: brinkman_design_t
43 use simulation_m, only: simulation_t
44
45 use num_types, only: rp
46 use coefs, only: coef_t
47 use json_module, only: json_file
48 use json_utils, only: json_get, json_get_or_default
49 use field, only: field_t
50 use field_registry, only: neko_field_registry
51 use scratch_registry, only: neko_scratch_registry
52 use neko_config, only: neko_bcknd_device
54 use math, only: glsc2
55 use device_math, only: device_glsc2
56 use vector_math, only: vector_cmult
57 use math_ext, only: glsc2_mask
58 use field_math, only: field_rone, field_copy
59 use utils, only: neko_error
60 implicit none
61 private
62
64 type, public, extends(constraint_t) :: volume_constraint_t
65 private
66
70 logical :: is_max
72 real(kind=rp) :: limit
74 real(kind=rp) :: volume_domain
75
77 class(coef_t), pointer :: c_xh => null()
78
79 contains
80
82 procedure, public, pass(this) :: init_json_sim => &
83 volume_constraint_init_json_sim
85 procedure, public, pass(this) :: init_from_attributes => &
86 volume_constraint_init_attributes
88 procedure, public, pass(this) :: free => volume_constraint_free
90 procedure, public, pass(this) :: update_value => &
91 volume_constraint_update_value
93 procedure, public, pass(this) :: update_sensitivity => &
94 volume_constraint_update_sensitivity
95
97 procedure, private, pass(this) :: compute_volume
98
99 end type volume_constraint_t
100
101contains
102
108 subroutine volume_constraint_init_json_sim(this, json, design, simulation)
109 class(volume_constraint_t), intent(inout) :: this
110 type(json_file), intent(inout) :: json
111 class(design_t), intent(in) :: design
112 type(simulation_t), target, intent(inout) :: simulation
113
114 character(len=:), allocatable :: mask_name
115 character(len=:), allocatable :: name
116 logical :: is_max
117 real(kind=rp) :: limit
118
119 call json_get_or_default(json, "mask_name", mask_name, "")
120 call json_get_or_default(json, "name", name, "Volume constraint")
121 call json_get_or_default(json, "is_max", is_max, .false.)
122 call json_get(json, "limit", limit)
123
124 call this%init_from_attributes(design, simulation, name, mask_name, &
125 is_max, limit)
126 end subroutine volume_constraint_init_json_sim
127
136 subroutine volume_constraint_init_attributes(this, design, simulation, &
137 name, mask_name, is_max, limit)
138 class(volume_constraint_t), intent(inout) :: this
139 class(design_t), intent(in) :: design
140 type(simulation_t), target, intent(inout) :: simulation
141 character(len=*), intent(in) :: mask_name
142 character(len=*), intent(in) :: name
143 logical, intent(in) :: is_max
144 real(kind=rp), intent(in) :: limit
145
146 real(kind=rp) :: volume
147 type(field_t), pointer :: work
148 integer :: temp_indices(1)
149
150 ! Initialize the base class
151 call this%init_base(name, design%size(), mask_name)
152
153 ! Store the attributes
154 this%is_max = is_max
155 this%limit = limit
156 this%c_Xh => simulation%neko_case%fluid%c_Xh
157
158 ! Now we can extract the mask/has_mask from the design
159 if (this%has_mask) then
160
161 ! calculate the volume of the optimization domain
162 call neko_scratch_registry%request_field(work, temp_indices(1))
163 call field_rone(work)
164
165 if (neko_bcknd_device .eq. 1) then
166 call mask_exterior_const(work, this%mask, 0.0_rp)
167 this%volume_domain = device_glsc2(work%x_d, this%c_xh%B_d, &
168 work%size())
169 else
170 this%volume_domain = glsc2_mask(work%x, this%c_Xh%B, &
171 design%size(), this%mask%mask%get(), this%mask%size)
172 end if
173
174 call neko_scratch_registry%relinquish_field(temp_indices)
175 else
176 this%volume_domain = this%c_Xh%volume
177 end if
178
179 ! ------------------------------------------------------------------------ !
180 ! Initialize the value of constraint
181
182 ! Compute the volume of the design
183 volume = this%compute_volume(design)
184
185 ! Compute the distance to the target volume
186 this%value = this%limit - volume / this%volume_domain
187
188 ! Invert the sign if it is a maximum constraint
189 if (this%is_max) this%value = - ( this%value )
190
191 ! ------------------------------------------------------------------------ !
192 ! Initialize the sensitivity value
193
194 this%sensitivity = 1.0_rp / this%volume_domain
195
196 ! Invert the sign if it is a maximum constraint
197 call vector_cmult(this%sensitivity, -1.0_rp)
198
199 if (this%has_mask) then
200 call mask_exterior_const(this%sensitivity, this%mask, 0.0_rp)
201 end if
202
203 end subroutine volume_constraint_init_attributes
204
206 subroutine volume_constraint_free(this)
207 class(volume_constraint_t), intent(inout) :: this
208
209 call this%free_base()
210 end subroutine volume_constraint_free
211
215 subroutine volume_constraint_update_value(this, design)
216 class(volume_constraint_t), intent(inout) :: this
217 class(design_t), intent(in) :: design
218 real(kind=rp) :: volume
219
220 volume = this%compute_volume(design)
221
222 ! Compute the distance to the target volume
223 this%value = this%limit - volume / this%volume_domain
224
225 ! Invert the sign if it is a maximum constraint
226 if (this%is_max) this%value = - ( this%value )
227
228 end subroutine volume_constraint_update_value
229
233 subroutine volume_constraint_update_sensitivity(this, design)
234 class(volume_constraint_t), intent(inout) :: this
235 class(design_t), intent(in) :: design
236
237 ! Sensitivity is just a constant so it should not be updated
238
239 end subroutine volume_constraint_update_sensitivity
240
241
242 ! ========================================================================== !
243 ! The actual volume computations for different types of designs
244
245
251 function compute_volume(this, design) result(volume)
252 class(volume_constraint_t), intent(inout) :: this
253 class(design_t), intent(in) :: design
254 real(kind=rp) :: volume
255
256 volume = 0.0_rp
257 select type (design)
258 type is (brinkman_design_t)
259 volume = volume_brinkman_design(this, design)
260
261 class default
262 call neko_error('Volume constraint only works with brinkman_design')
263 end select
264
265 end function compute_volume
266
270 function volume_brinkman_design(this, design) result(volume)
271 class(volume_constraint_t), intent(inout) :: this
272 type(brinkman_design_t), intent(in) :: design
273 real(kind=rp) :: volume
274 type(field_t), pointer :: work, design_indicator
275 integer :: temp_indices(1)
276
277 volume = 0.0_rp
278 design_indicator => neko_field_registry%get_field("design_indicator")
279
280 ! in the future we should be using the mapped design variable
281 ! corresponding to this constraint!!!
282 if (this%has_mask) then
283
284 if (neko_bcknd_device .eq. 1) then
285 call neko_scratch_registry%request_field(work, temp_indices(1))
286 call field_copy(work, design_indicator)
287 call mask_exterior_const(work, this%mask, 0.0_rp)
288 volume = device_glsc2(work%x_d, this%c_xh%B_d, design%size())
289 call neko_scratch_registry%relinquish_field(temp_indices)
290 else
291 volume = glsc2_mask(design_indicator%x, &
292 this%c_Xh%B, design%size(), this%mask%mask%get(), this%mask%size)
293 end if
294
295 else
296
297 if (neko_bcknd_device .eq. 1) then
298 volume = device_glsc2(design_indicator%x_d, &
299 this%c_xh%B_d, design%size())
300 else
301 volume = glsc2(design_indicator%x, &
302 this%c_Xh%B, design%size())
303 end if
304
305 end if
306
307 end function volume_brinkman_design
308
309end module volume_constraint
Implements the constraint_t type.
Implements the design_t.
Definition design.f90:34
Some common Masking operations we may need.
Definition mask_ops.f90:34
Implements the steady_problem_t type.
Implements the volume_constraint_t type.
A topology optimization design variable.
The abstract constraint type.
An abstract design type.
Definition design.f90:52
A constraint on the volume of the design.