Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
design.f90
Go to the documentation of this file.
1
5
7
8 use case, only: case_t
9 use fluid_user_source_term, only: fluid_user_source_term_t
10 ! use fluid_source_term, only: fluid_source_term_t
11 use field, only: field_t
12 use field_registry, only: neko_field_registry
13 use num_types, only: rp
14 use point_zone, only: point_zone_t
15 use device, only: device_map, device_memcpy, host_to_device
16 use logger, only: neko_log
17 use point_zone_registry, only: neko_point_zone_registry
18 use json_utils, only: json_get, json_get_or_default
19 use neko_config, only: neko_bcknd_device
20 use math, only: col3, rzero, col2, cmult, invcol1, cadd, add2, cfill
21 use device_math, only: device_col3, device_rzero, device_col2, device_cmult, &
22 device_invcol1, device_cadd, device_add2, device_cfill
23 use math_ext, only: cadd_mask, col3_mask
25 use simulation_component, only: simulation_component_t
26 use json_module, only: json_file
27 use utils, only: neko_error
28 use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr
29 ! use topopt_brinkman_source_term, only: topopt_brinkman_source_term_t
30 implicit none
31
32
33 ! ========================================================================= !
34 ! Module interface
35 ! ========================================================================= !
36 private
37
39
40 ! ========================================================================= !
41 ! Global variables
42 ! ========================================================================= !
43
45 real(kind=rp), dimension(:), allocatable :: resistance
47 type(c_ptr) :: resistance_d = c_null_ptr
49 integer, dimension(:), pointer :: design_domain_mask
51 type(c_ptr) :: design_domain_mask_d = c_null_ptr
52
53 ! ========================================================================= !
54 ! Topology type
55 ! ========================================================================= !
56
59 type, extends(simulation_component_t) :: design_t
60
61 ! the design field, and brinkman amplitude stay public
63 class(field_t), public, pointer :: chi
65 class(field_t), public, pointer :: design_field
67 class(point_zone_t), private, pointer :: design_domain => null()
68
69 ! Limits of the permeability.
70 real(kind=rp), private :: perm_0, perm_1, perm_penalty
71
73 integer :: total_size, design_size
74
76 logical :: converged = .false.
78 logical :: design_changed = .false.
79
80 contains
81
83 procedure, pass(this) :: init => init_design
84
86 procedure, pass(this) :: free => free_design
87
89 procedure, pass(this) :: preprocess_ => update_permeability
90
92 procedure, pass(this) :: compute_ => update_design
93
95 procedure, pass(this) :: update => update_design
96 end type design_t
97
98contains
99
100 ! ========================================================================= !
101 ! Public routines
102 ! ========================================================================= !
103
109 subroutine init_design(this, json, case)
110 class(design_t), intent(inout) :: this
111 type(json_file), intent(inout) :: json
112 class(case_t), intent(inout), target :: case
113
114 ! type(fluid_source_term_t), allocatable :: brinkman_source_term
115
116 ! Base initialization
117 call this%free()
118 call this%init_base(json, case)
119
120 ! ---------------------------------------------------------------------- !
121 ! Assign local variables
122 ! ---------------------------------------------------------------------- !
123
124 call json_get_or_default(json, "topopt.perm_penalty", &
125 this%perm_penalty, 1.0_rp)
126 call json_get_or_default(json, "topopt.perm_0", &
127 this%perm_0, 1000.0_rp)
128 call json_get_or_default(json, "topopt.perm_1", &
129 this%perm_1, 0.0_rp)
130
131 ! ---------------------------------------------------------------------- !
132 ! Set the design domain
133 ! ---------------------------------------------------------------------- !
134
135 if (neko_point_zone_registry%point_zone_exists("design_domain") ) then
136 this%design_domain => &
137 neko_point_zone_registry%get_point_zone("design_domain")
138 else
139 call neko_log%error("design_domain point zone does not exist")
140 end if
141
142 design_domain_mask => this%design_domain%mask
143 design_domain_mask_d = this%design_domain%mask_d
144
145 if (neko_bcknd_device .eq. 1) then
146 call neko_log%warning("We assume that NEKO is using the old design " // &
147 "domain masks. Please check the status of PR " // &
148 "on masks if results seem wonky.")
149
151 call device_memcpy(design_domain_mask, design_domain_mask_d, &
152 this%design_domain%size, host_to_device, &
153 .true. &
154 )
156
157 end if
158 ! ---------------------------------------------------------------------- !
159 ! Initialize the design field
160 ! ---------------------------------------------------------------------- !
161
162 if (.not. neko_field_registry%field_exists("design")) then
163 call neko_field_registry%add_field(case%fluid%dm_Xh, "design")
164 end if
165
166 this%design_field => neko_field_registry%get_field_by_name("design")
167
168 call case%f_out%fluid%append(this%design_field)
169
170 ! Initialize the design
171 call rzero(this%design_field%x, this%design_field%dof%size())
172 if (neko_bcknd_device .eq. 1) then
173 call device_rzero(this%design_field%x_d, this%design_field%dof%size())
174 end if
175
176 ! ---------------------------------------------------------------------- !
177 ! Initialize the resistance array
178 ! ---------------------------------------------------------------------- !
179
180 ! allocate(brinkman_source_term)
181
182
183 this%total_size = this%design_field%dof%size()
184 this%design_size = this%design_domain%size
185
186 allocate (resistance(this%total_size))
187 call rzero(resistance, this%total_size)
188
189 if (neko_bcknd_device .eq. 1) then
190 call device_map(resistance, resistance_d, this%total_size)
191 end if
192
193
194
195 ! ---------------------------------------------------------------------- !
196 ! Assign the resistance function to be the source term
197 ! ---------------------------------------------------------------------- !
198
199 if (associated(this%case%usr%fluid_user_f_vector)) then
200 nullify(this%case%usr%fluid_user_f_vector)
201 end if
202 this%case%usr%fluid_user_f_vector => topopt_permeability_force
203
204 end subroutine init_design
205
207 subroutine free_design(this)
208 use device, only: device_free
209 implicit none
210
211 class(design_t), intent(inout) :: this
212
213 if (allocated(resistance)) deallocate(resistance)
214 call device_free(resistance_d)
215 nullify(this%design_field)
216 nullify(this%design_domain)
217
218 end subroutine free_design
219
224 subroutine update_design(this, t, tstep)
225 class(design_t), intent(inout) :: this
226 real(kind=rp), intent(in) :: t
227 integer, intent(in) :: tstep
228 real(kind=rp) :: max_norm
229
230 ! ---------------------------------------------------------------------- !
231 ! Update the design
232 ! ---------------------------------------------------------------------- !
233
234 associate(x => this%design_field%x, &
235 x_d => this%design_field%x_d, &
236 mask => this%design_domain%mask, &
237 mask_d => this%design_domain%mask_d &
238 )
239
240 if (.not. neko_bcknd_device .eq. 1) then
241 call cadd_mask(x, 0.3_rp, this%total_size, mask, this%design_size)
242 else
243 call device_cadd_mask(x_d, 0.3_rp, this%total_size, &
244 mask_d, this%design_size)
245 end if
246 end associate
247
248 ! ---------------------------------------------------------------------- !
249 ! Compute the maximum norm of the change in the design and check if we
250 ! have converged.
251 ! ---------------------------------------------------------------------- !
252
253 max_norm = 1.0_rp
254 this%converged = max_norm < 0.01_rp
255
256 end subroutine update_design
257
267 class(fluid_user_source_term_t), intent(inout) :: f
268 real(kind=rp), intent(in) :: t
269 type(field_t), pointer :: u, v, w
270 integer :: total_size, design_size
271
272 u => neko_field_registry%get_field('u')
273 v => neko_field_registry%get_field('v')
274 w => neko_field_registry%get_field('w')
275
276 design_size = size(design_domain_mask)
277 total_size = f%dm%size()
278
279 if (neko_bcknd_device .eq. 1) then
280 call device_col3_mask(f%u_d, u%x_d, resistance_d, total_size, &
281 design_domain_mask_d, design_size)
282 call device_col3_mask(f%v_d, v%x_d, resistance_d, total_size, &
283 design_domain_mask_d, design_size)
284 call device_col3_mask(f%w_d, w%x_d, resistance_d, total_size, &
285 design_domain_mask_d, design_size)
286 else
287 call col3_mask(f%u, u%x, resistance, total_size, &
288 design_domain_mask, design_size)
289 call col3_mask(f%v, v%x, resistance, total_size, &
290 design_domain_mask, design_size)
291 call col3_mask(f%w, w%x, resistance, total_size, &
292 design_domain_mask, design_size)
293 end if
294 end subroutine topopt_permeability_force
295
296 ! ========================================================================= !
297 ! Private routines
298 ! ========================================================================= !
299
316 subroutine update_permeability(this, t, tstep)
317 class(design_t), intent(inout) :: this
318 real(kind=rp), intent(in) :: t
319 integer, intent(in) :: tstep
320
321 ! Local variables
322 real(kind=rp) :: constant
323
324 constant = (this%perm_0 - this%perm_1) * (this%perm_penalty + 1.0_rp)
325
326 if (neko_bcknd_device .eq. 1) then
327 call device_cfill(resistance_d, this%perm_penalty, this%total_size)
328 call device_add2(resistance_d, this%design_field%x_d, this%total_size)
329 call device_invcol1(resistance_d, this%total_size)
330 call device_col2(resistance_d, this%design_field%x_d, this%total_size)
331 call device_cmult(resistance_d, constant, this%total_size)
332 call device_cadd(resistance_d, this%perm_1, this%total_size)
333
334 ! Multiply by -1, since we wish to affect the velocity negatively.
335 call device_cmult(resistance_d, -1.0_rp, this%total_size)
336 else
337 call cfill(resistance, this%perm_penalty, this%total_size)
338 call add2(resistance, this%design_field%x, this%total_size)
339 call invcol1(resistance, this%total_size)
340 call col2(resistance, this%design_field%x, this%total_size)
341 call cmult(resistance, constant, this%total_size)
342 call cadd(resistance, this%perm_1, this%total_size)
343
344 ! Multiply by -1, since we wish to affect the velocity negatively.
345 call cmult(resistance, -1.0_rp, this%total_size)
346 end if
347
348 end subroutine update_permeability
349
350end module design_module
type(c_ptr) design_domain_mask_d
Pointer to the design domain mask on the device.
Definition design.f90:51
subroutine update_permeability(this, t, tstep)
Update the permeability.
Definition design.f90:317
integer, dimension(:), pointer design_domain_mask
Pointer to the design domain mask.
Definition design.f90:49
subroutine free_design(this)
Free the topology.
Definition design.f90:208
subroutine init_design(this, json, case)
Initialize the topology.
Definition design.f90:110
subroutine, public topopt_permeability_force(f, t)
Compute the permeability force term.
Definition design.f90:267
real(kind=rp), dimension(:), allocatable resistance
The resistance array.
Definition design.f90:45
type(c_ptr) resistance_d
Pointer to the resistance array on the device.
Definition design.f90:47
subroutine update_design(this, t, tstep)
Update the topology.
Definition design.f90:225
subroutine device_cadd_mask(a_d, c, size, mask_d, mask_size)
subroutine device_col3_mask(a_d, b_d, c_d, size, mask_d, mask_size)
subroutine col3_mask(a, b, c, size, mask, mask_size)
Multiply 2 masked vectors. Save the result in a new vector. .
Definition math_ext.f90:87
subroutine cadd_mask(a, c, size, mask, mask_size)
Add a constant to a masked vector. .
Definition math_ext.f90:28
The topology type, which is used to describe the designs in topology optimization.
Definition design.f90:59