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
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
212 if (neko_bcknd_device .eq. 1) then
213 call device_copy(this%sensitivity%x_d, this%c_xh%B_d, design%size())
214 call device_cmult(this%sensitivity%x_d, -1.0_rp / this%volume_domain, &
215 design%size())
216
217 if (this%is_max) then
218 call device_cmult(this%sensitivity%x_d, -1.0_rp, design%size())
219 end if
220 else
221 call copy(this%sensitivity%x, this%c_Xh%B, design%size())
222 call cmult(this%sensitivity%x, -1.0_rp / this%volume_domain, &
223 design%size())
224
225 if (this%is_max) then
226 call vector_cmult(this%sensitivity, -1.0_rp)
227 end if
228 end if
229
230 if (this%has_mask) then
231 call mask_exterior_const(this%sensitivity, this%mask, 0.0_rp)
232 end if
233
234 end subroutine volume_constraint_init_from_components
235
237 subroutine volume_constraint_free(this)
238 class(volume_constraint_t), intent(inout) :: this
239
240 call this%free_base()
241 end subroutine volume_constraint_free
242
246 subroutine volume_constraint_update_value(this, design)
247 class(volume_constraint_t), intent(inout) :: this
248 class(design_t), intent(in) :: design
249 real(kind=rp) :: volume
250
251 volume = this%compute_volume(design)
252
253 ! Compute the distance to the target volume
254 this%value = this%limit - volume / this%volume_domain
255
256 ! Invert the sign if it is a maximum constraint
257 if (this%is_max) this%value = -this%value
258
259 end subroutine volume_constraint_update_value
260
264 subroutine volume_constraint_update_sensitivity(this, design)
265 class(volume_constraint_t), intent(inout) :: this
266 class(design_t), intent(in) :: design
268 type(field_t), pointer :: unmapped, mapped
269 integer :: temp_indices(2)
270
271 if (this%if_mapping) then
272 ! Recompute and map backward
273 call neko_scratch_registry%request(unmapped, temp_indices(1), &
274 .false.)
275 call neko_scratch_registry%request(mapped, temp_indices(2), &
276 .false.)
277 ! The mapping will handle the mass matrix
278 call field_cfill(unmapped, -1.0_rp / this%volume_domain)
279 if (this%is_max) then
280 call field_cmult(unmapped, -1.0_rp)
281 end if
282 ! mask
283 if (this%has_mask) then
284 call mask_exterior_const(unmapped, this%mask, 0.0_rp)
285 end if
286 ! map backwards
287 call this%mapping%apply_backward(mapped, unmapped)
288 call field_to_vector(this%sensitivity, mapped)
289
290 call neko_scratch_registry%relinquish(temp_indices)
291
292 else
293 ! Sensitivity is just a constant so it should not be updated
294 end if
295
296 end subroutine volume_constraint_update_sensitivity
297
298 ! ========================================================================== !
299 ! The actual volume computations for different types of designs
300
306 function compute_volume(this, design) result(volume)
307 class(volume_constraint_t), intent(inout) :: this
308 class(design_t), intent(in) :: design
309 real(kind=rp) :: volume
310
311 volume = 0.0_rp
312 select type (design)
313 type is (brinkman_design_t)
314 volume = volume_brinkman_design(this, design)
315
316 class default
317 call neko_error('Volume constraint only works with brinkman_design')
318 end select
319
320 end function compute_volume
321
325 function volume_brinkman_design(this, design) result(volume)
326 class(volume_constraint_t), intent(inout) :: this
327 type(brinkman_design_t), intent(in) :: design
328 real(kind=rp) :: volume
329 type(field_t), pointer :: work
330 type(vector_t), pointer :: values, unmapped_values
331 integer :: temp_indices, ind_value, ind_um_value
332
333 call neko_scratch_registry%request(values, ind_value, design%size(), &
334 .false.)
335
336 volume = 0.0_rp
337 if (this%if_mapping) then
338 call neko_scratch_registry%request(unmapped_values, ind_um_value, &
339 design%size(), .false.)
340 call design%get_values(unmapped_values)
341 call this%mapping%apply_forward(values, unmapped_values)
342 call neko_scratch_registry%relinquish(ind_um_value)
343 else
344 call design%get_values(values)
345 end if
346
347 if (this%has_mask) then
348
349 if (neko_bcknd_device .eq. 1) then
350 call neko_scratch_registry%request(work, temp_indices, .false.)
351 call device_copy(work%x_d, values%x_d, design%size())
352 call mask_exterior_const(work, this%mask, 0.0_rp)
353
354 volume = device_glsc2(work%x_d, this%c_xh%B_d, design%size())
355
356 call neko_scratch_registry%relinquish(temp_indices)
357 else
358 volume = glsc2_mask(values%x, this%c_Xh%B, design%size(), &
359 this%mask%mask%get(), this%mask%size)
360 end if
361
362 else
363
364 if (neko_bcknd_device .eq. 1) then
365 volume = device_glsc2(values%x_d, this%c_xh%B_d, design%size())
366 else
367 volume = glsc2(values%x, this%c_Xh%B, design%size())
368 end if
369
370 end if
371
372 call neko_scratch_registry%relinquish(ind_value)
373
374 end function volume_brinkman_design
375
379 function volume_constraint_get_log_size(this) result(n)
380 class(volume_constraint_t), intent(in) :: this
381 integer :: n
382
383 n = 2
384 end function volume_constraint_get_log_size
385
389 subroutine volume_constraint_get_log_headers(this, headers)
390 class(volume_constraint_t), intent(in) :: this
391 character(len=*), intent(out) :: headers(:)
392 character(len=64) :: prefix
393
394 if (size(headers) .lt. 1) return
395 prefix = trim(this%name)
396 headers(1) = prefix
397 if (size(headers) .lt. 2) return
398 headers(2) = trim(prefix) // '.volume'
399
400 end subroutine volume_constraint_get_log_headers
401
405 subroutine volume_constraint_get_log_values(this, values)
406 class(volume_constraint_t), intent(in) :: this
407 real(kind=rp), intent(out) :: values(:)
408 real(kind=rp) :: volume_ratio
409
410 if (size(values) .lt. 1) return
411 if (this%is_max) then
412 volume_ratio = this%limit + this%value
413 else
414 volume_ratio = this%limit - this%value
415 end if
416
417 values(1) = this%value
418 if (size(values) .lt. 2) return
419 values(2) = volume_ratio
420
421 end subroutine volume_constraint_get_log_values
422
423end 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:406
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:54
Abstract class for handling mapping_cascade.
A constraint on the volume of the design.