Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
volume_constraint.f90
Go to the documentation of this file.
1
34!
41 use constraint, only: constraint_t
42
43 use design, only: design_t
44 use brinkman_design, only: brinkman_design_t
45 use simulation_m, only: simulation_t
47 use num_types, only: rp
48 use coefs, only: coef_t
49 use json_module, only: json_file
50 use json_utils, only: json_get, json_get_or_default
51 use field, only: field_t
52 use scratch_registry, only: neko_scratch_registry
53 use neko_config, only: neko_bcknd_device
55 use math, only: glsc2, copy, cmult
56 use device_math, only: device_glsc2, device_copy, device_cmult
57 use vector_math, only: vector_cmult, vector_cfill
58 use math_ext, only: glsc2_mask
59 use field_math, only: field_rone, field_copy, field_cmult, field_cfill
60 use utils, only: neko_error
61 use vector, only: vector_t
62 use neko_ext, only: field_to_vector
63 implicit none
64 private
65
67 type, public, extends(constraint_t) :: volume_constraint_t
68 private
69
73 logical :: is_max
75 real(kind=rp) :: limit
77 real(kind=rp) :: volume_domain
79 class(coef_t), pointer :: c_xh => null()
83 logical :: if_mapping = .false.
84
85 contains
86
88 procedure, public, pass(this) :: init_json_sim => &
91 procedure, public, pass(this) :: init_from_components => &
92 volume_constraint_init_from_components
94 procedure, public, pass(this) :: free => volume_constraint_free
96 procedure, public, pass(this) :: update_value => &
97 volume_constraint_update_value
99 procedure, public, pass(this) :: update_sensitivity => &
100 volume_constraint_update_sensitivity
102 procedure, public, pass(this) :: get_log_size => &
103 volume_constraint_get_log_size
105 procedure, public, pass(this) :: get_log_headers => &
106 volume_constraint_get_log_headers
108 procedure, public, pass(this) :: get_log_values => &
109 volume_constraint_get_log_values
110
112 procedure, private, pass(this) :: compute_volume
113
114 end type volume_constraint_t
115
116contains
117
123 subroutine volume_constraint_init_json_sim(this, json, design, simulation)
124 class(volume_constraint_t), intent(inout) :: this
125 type(json_file), intent(inout) :: json
126 class(design_t), intent(in) :: design
127 type(simulation_t), target, intent(inout) :: simulation
128
129 character(len=:), allocatable :: mask_name
130 character(len=:), allocatable :: name
131 logical :: is_max
132 real(kind=rp) :: limit
133
134 call json_get_or_default(json, "name", name, "Volume constraint")
135 call json_get_or_default(json, "mask_name", mask_name, "")
136 call json_get_or_default(json, "is_max", is_max, .false.)
137 call json_get(json, "limit", limit)
138
139 call this%init_from_components(design, simulation, name, mask_name, &
140 is_max, limit)
141
142 ! check if we have a mapping
143 if ('mapping' .in. json) then
144 ! Initialize the mapper
145 call this%mapping%init_base(this%c_Xh)
146 call this%mapping%add(json, 'mapping')
147 this%if_mapping = .true.
148 ! recompute value after mapping
149 call this%update_value(design)
150 end if
151
153
162 subroutine volume_constraint_init_from_components(this, design, simulation, &
163 name, mask_name, is_max, limit)
164 class(volume_constraint_t), intent(inout) :: this
165 class(design_t), intent(in) :: design
166 type(simulation_t), target, intent(inout) :: simulation
167 character(len=*), intent(in) :: mask_name
168 character(len=*), intent(in) :: name
169 logical, intent(in) :: is_max
170 real(kind=rp), intent(in) :: limit
171
172 type(field_t), pointer :: work
173 integer :: temp_indices(1)
174
175 ! Initialize the base class
176 call this%init_base(name, design%size(), mask_name)
177
178 ! Store the attributes
179 this%is_max = is_max
180 this%limit = limit
181 this%c_Xh => simulation%neko_case%fluid%c_Xh
182
183 ! Now we can extract the mask/has_mask from the design
184 if (this%has_mask) then
185
186 ! calculate the volume of the optimization domain
187 call neko_scratch_registry%request(work, temp_indices(1), .false.)
188 call field_rone(work)
189 call mask_exterior_const(work, this%mask, 0.0_rp)
190
191 if (neko_bcknd_device .eq. 1) then
192 this%volume_domain = device_glsc2(work%x_d, this%c_xh%B_d, &
193 work%size())
194 else
195 this%volume_domain = glsc2_mask(work%x, this%c_Xh%B, &
196 design%size(), this%mask%mask%get(), this%mask%size)
197 end if
198
199 call neko_scratch_registry%relinquish(temp_indices)
200 else
201 this%volume_domain = this%c_Xh%volume
202 end if
203
204 ! ------------------------------------------------------------------------ !
205 ! Initialize the value of constraint
206
207 call this%update_value(design)
208
209 ! ------------------------------------------------------------------------ !
210 ! Initialize the sensitivity value
211 call vector_cfill(this%sensitivity, -1.0_rp / this%volume_domain)
212 if (this%is_max) then
213 call vector_cmult(this%sensitivity, -1.0_rp)
214 end if
215
216 if (this%has_mask) then
217 call mask_exterior_const(this%sensitivity, this%mask, 0.0_rp)
218 end if
219
220 end subroutine volume_constraint_init_from_components
221
223 subroutine volume_constraint_free(this)
224 class(volume_constraint_t), intent(inout) :: this
225
226 call this%free_base()
227 end subroutine volume_constraint_free
228
232 subroutine volume_constraint_update_value(this, design)
233 class(volume_constraint_t), intent(inout) :: this
234 class(design_t), intent(in) :: design
235 real(kind=rp) :: volume
236
237 volume = this%compute_volume(design)
238
239 ! Compute the distance to the target volume
240 this%value = this%limit - volume / this%volume_domain
241
242 ! Invert the sign if it is a maximum constraint
243 if (this%is_max) this%value = -this%value
244
245 end subroutine volume_constraint_update_value
246
250 subroutine volume_constraint_update_sensitivity(this, design)
251 class(volume_constraint_t), intent(inout) :: this
252 class(design_t), intent(in) :: design
254 type(field_t), pointer :: unmapped, mapped
255 integer :: temp_indices(2)
256
257 if (this%if_mapping) then
258 ! Recompute and map backward
259 call neko_scratch_registry%request(unmapped, temp_indices(1), &
260 .false.)
261 call neko_scratch_registry%request(mapped, temp_indices(2), &
262 .false.)
263 call field_cfill(unmapped, -1.0_rp / this%volume_domain)
264 if (this%is_max) then
265 call field_cmult(unmapped, -1.0_rp)
266 end if
267 ! mask
268 if (this%has_mask) then
269 call mask_exterior_const(unmapped, this%mask, 0.0_rp)
270 end if
271 ! map backwards
272 call this%mapping%apply_backward(mapped, unmapped)
273 call field_to_vector(this%sensitivity, mapped)
274
275 call neko_scratch_registry%relinquish(temp_indices)
276
277 else
278 ! Sensitivity is just a constant so it should not be updated
279 end if
280
281 end subroutine volume_constraint_update_sensitivity
282
283 ! ========================================================================== !
284 ! The actual volume computations for different types of designs
285
291 function compute_volume(this, design) result(volume)
292 class(volume_constraint_t), intent(inout) :: this
293 class(design_t), intent(in) :: design
294 real(kind=rp) :: volume
295
296 volume = 0.0_rp
297 select type (design)
298 type is (brinkman_design_t)
299 volume = volume_brinkman_design(this, design)
300
301 class default
302 call neko_error('Volume constraint only works with brinkman_design')
303 end select
304
305 end function compute_volume
306
310 function volume_brinkman_design(this, design) result(volume)
311 class(volume_constraint_t), intent(inout) :: this
312 type(brinkman_design_t), intent(in) :: design
313 real(kind=rp) :: volume
314 type(field_t), pointer :: work
315 type(vector_t), pointer :: values, unmapped_values
316 integer :: temp_indices, ind_value, ind_um_value
317
318 call neko_scratch_registry%request(values, ind_value, design%size(), &
319 .false.)
320
321 volume = 0.0_rp
322 if (this%if_mapping) then
323 call neko_scratch_registry%request(unmapped_values, ind_um_value, &
324 design%size(), .false.)
325 call design%get_values(unmapped_values)
326 call this%mapping%apply_forward(values, unmapped_values)
327 call neko_scratch_registry%relinquish(ind_um_value)
328 else
329 call design%get_values(values)
330 end if
331
332 if (this%has_mask) then
333
334 if (neko_bcknd_device .eq. 1) then
335 call neko_scratch_registry%request(work, temp_indices, .false.)
336 call device_copy(work%x_d, values%x_d, design%size())
337 call mask_exterior_const(work, this%mask, 0.0_rp)
338
339 volume = device_glsc2(work%x_d, this%c_xh%B_d, design%size())
340
341 call neko_scratch_registry%relinquish(temp_indices)
342 else
343 volume = glsc2_mask(values%x, this%c_Xh%B, design%size(), &
344 this%mask%mask%get(), this%mask%size)
345 end if
346
347 else
348
349 if (neko_bcknd_device .eq. 1) then
350 volume = device_glsc2(values%x_d, this%c_xh%B_d, design%size())
351 else
352 volume = glsc2(values%x, this%c_Xh%B, design%size())
353 end if
354
355 end if
356
357 call neko_scratch_registry%relinquish(ind_value)
358
359 end function volume_brinkman_design
360
364 function volume_constraint_get_log_size(this) result(n)
365 class(volume_constraint_t), intent(in) :: this
366 integer :: n
367
368 n = 2
369 end function volume_constraint_get_log_size
370
374 subroutine volume_constraint_get_log_headers(this, headers)
375 class(volume_constraint_t), intent(in) :: this
376 character(len=*), intent(out) :: headers(:)
377 character(len=64) :: prefix
378
379 if (size(headers) .lt. 1) return
380 prefix = trim(this%name)
381 headers(1) = prefix
382 if (size(headers) .lt. 2) return
383 headers(2) = trim(prefix) // '.volume'
384
385 end subroutine volume_constraint_get_log_headers
386
390 subroutine volume_constraint_get_log_values(this, values)
391 class(volume_constraint_t), intent(in) :: this
392 real(kind=rp), intent(out) :: values(:)
393 real(kind=rp) :: volume_ratio
394
395 if (size(values) .lt. 1) return
396 if (this%is_max) then
397 volume_ratio = this%limit + this%value
398 else
399 volume_ratio = this%limit - this%value
400 end if
401
402 values(1) = this%value
403 if (size(values) .lt. 2) return
404 values(2) = volume_ratio
405
406 end subroutine volume_constraint_get_log_values
407
408end module volume_constraint
Implements the constraint_t type.
Implements the design_t.
Definition design.f90:36
Implements the mapping_handler_t type.
Mappings to be applied to a scalar field.
Definition mapping.f90:36
Some common Masking operations we may need.
Definition mask_ops.f90:36
Contains extensions to the neko library required to run the topology optimization code.
Definition neko_ext.f90:42
subroutine, public field_to_vector(vector, field)
Field to vector.
Definition neko_ext.f90:409
Implements the steady_problem_t type.
Implements the volume_constraint_t type. Either .
subroutine volume_constraint_init_json_sim(this, json, design, simulation)
The common constructor using a JSON object.
A topology optimization design variable.
The abstract constraint type.
An abstract design type.
Definition design.f90:53
Abstract class for handling mapping_cascade.
A constraint on the volume of the design.