Neko-TOP
A portable framework for high-order spectral element flow toplogy optimization.
Loading...
Searching...
No Matches
topopt_brinkman_source.f90
Go to the documentation of this file.
1
34!
37 use num_types, only: rp, dp
38 use field, only: field_t
39 use field_list, only: field_list_t
40 use json_utils, only: json_get, json_get_or_default, json_extract_item
41 use field_registry, only: neko_field_registry
42 use source_term, only: source_term_t
43 use coefs, only: coef_t
44 use neko_config, only: neko_bcknd_device
45 use utils, only: neko_error
46 use field_math, only: field_subcol3
47 use file, only: file_t
48 use tri_mesh, only: tri_mesh_t
49 use device, only: device_memcpy, host_to_device
50 use filters, only: smooth_step_field, step_function_field, permeability_field
51 use signed_distance, only: signed_distance_field
52 use profiler, only: profiler_start_region, profiler_end_region
53 use json_module, only: json_core, json_value, json_file
54 use point_zone, only: point_zone_t
55 use point_zone_registry, only: neko_point_zone_registry
56 use aabb, only: aabb_t, get_aabb
57 implicit none
58
59
60 private
61
65 type, public, extends(source_term_t) :: topopt_brinkman_source_term_t
66 private
67
69 type(field_t), pointer :: indicator => null()
71 type(field_t), pointer :: brinkman => null()
72 contains
74 procedure, public, pass(this) :: init => &
77 procedure, public, pass(this) :: free => brinkman_source_term_free
79 procedure, public, pass(this) :: compute_ => brinkman_source_term_compute
81 ! procedure, public, pass(this) :: update_resistance
82
83 ! ----------------------------------------------------------------------- !
84 ! Private methods
85 procedure, pass(this) :: init_boundary_mesh
86 procedure, pass(this) :: init_point_zone
88
89contains
90
91 ! ========================================================================== !
92 ! Public methods
93
99 subroutine brinkman_source_term_init_from_json(this, json, fields, coef)
100 class(topopt_brinkman_source_term_t), intent(inout) :: this
101 type(json_file), intent(inout) :: json
102 type(field_list_t), intent(inout), target :: fields
103 type(coef_t), target, intent(inout) :: coef
104 real(kind=rp) :: start_time, end_time
105
106 character(len=:), allocatable :: filter_type
107 real(kind=rp), dimension(:), allocatable :: brinkman_limits
108 real(kind=rp) :: brinkman_penalty
109
110 type(json_value), pointer :: json_object_list
111 type(json_core) :: core
112
113 character(len=:), allocatable :: object_type
114 type(json_file) :: object_settings
115 integer :: n_regions
116 integer :: i
117
118 ! Mandatory fields for the general source term
119 call json_get_or_default(json, "start_time", start_time, 0.0_rp)
120 call json_get_or_default(json, "end_time", end_time, huge(0.0_rp))
121
122 ! Read the options for the permeability field
123 call json_get(json, 'brinkman.limits', brinkman_limits)
124 call json_get(json, 'brinkman.penalty', brinkman_penalty)
125
126 if (size(brinkman_limits) .ne. 2) then
127 call neko_error('brinkman_limits must be a 2 element array of reals')
128 end if
129
130 call this%free()
131 call this%init_base(fields, coef, start_time, end_time)
132
133 ! ------------------------------------------------------------------------ !
134 ! Allocate the permeability and indicator field
135
136 if (neko_field_registry%field_exists('brinkman_indicator') &
137 .or. neko_field_registry%field_exists('brinkman')) then
138 call neko_error('Brinkman field already exists.')
139 end if
140
141 call neko_field_registry%add_field(coef%dof, 'brinkman_indicator')
142 this%indicator => &
143 neko_field_registry%get_field_by_name('brinkman_indicator')
144
145 call neko_field_registry%add_field(coef%dof, 'brinkman')
146 this%brinkman => neko_field_registry%get_field_by_name('brinkman')
147
148 ! ------------------------------------------------------------------------ !
149 ! Select which constructor should be called
150
151 call json%get('objects', json_object_list)
152 call json%info('objects', n_children = n_regions)
153 call json%get_core(core)
154
155 do i = 1, n_regions
156 call json_extract_item(core, json_object_list, i, object_settings)
157 call json_get_or_default(object_settings, 'type', object_type, 'none')
158
159 select case (object_type)
160 case ('boundary_mesh')
161 call this%init_boundary_mesh(object_settings)
162 case ('point_zone')
163 call this%init_point_zone(object_settings)
164
165 case ('none')
166 call object_settings%print()
167 call neko_error('Brinkman source term objects require a region type')
168 case default
169 call neko_error('Brinkman source term unknown region type')
170 end select
171
172 end do
173
174 ! Run filter on the full indicator field to smooth it out.
175 call json_get_or_default(json, 'filter.type', filter_type, 'none')
176
177 select case (filter_type)
178 case ('none')
179 ! Do nothing
180 case default
181 call neko_error('Brinkman source term unknown filter type')
182 end select
183
184 ! ------------------------------------------------------------------------ !
185 ! Compute the permeability field
186
187 call permeability_field(this%brinkman, this%indicator, &
188 brinkman_limits(1), brinkman_limits(2), brinkman_penalty)
189
190 ! Copy the permeability field to the device
191 if (neko_bcknd_device .eq. 1) then
192 call device_memcpy(this%brinkman%x, this%brinkman%x_d, &
193 this%brinkman%dof%size(), host_to_device, .true.)
194 end if
195
197
200 subroutine brinkman_source_term_free(this)
201 class(topopt_brinkman_source_term_t), intent(inout) :: this
202
203 this%brinkman => null()
204 call this%free_base()
205 end subroutine brinkman_source_term_free
206
211 subroutine brinkman_source_term_compute(this, t, tstep)
212 class(topopt_brinkman_source_term_t), intent(inout) :: this
213 real(kind=rp), intent(in) :: t
214 integer, intent(in) :: tstep
215 type(field_t), pointer :: u, v, w, fu, fv, fw
216 integer :: n
217
218 n = this%fields%item_size(1)
219
220 u => neko_field_registry%get_field('u')
221 v => neko_field_registry%get_field('v')
222 w => neko_field_registry%get_field('w')
223
224 fu => this%fields%get(1)
225 fv => this%fields%get(2)
226 fw => this%fields%get(3)
227
228 call field_subcol3(fu, u, this%brinkman, n)
229 call field_subcol3(fv, v, this%brinkman, n)
230 call field_subcol3(fw, w, this%brinkman, n)
231
232 end subroutine brinkman_source_term_compute
233
234 ! ========================================================================== !
235 ! Private methods
236
240 subroutine init_boundary_mesh(this, json)
241 class(topopt_brinkman_source_term_t), intent(inout) :: this
242 type(json_file), intent(inout) :: json
243
244 ! Options
245 character(len=:), allocatable :: mesh_file_name
246 character(len=:), allocatable :: distance_transform
247 character(len=:), allocatable :: filter_type
248 character(len=:), allocatable :: mesh_transform
249
250 ! Read the options for the boundary mesh
251 type(file_t) :: mesh_file
252 type(tri_mesh_t) :: boundary_mesh
253 real(kind=rp) :: scalar_r
254 real(kind=dp) :: scalar_d
255
256 ! Mesh transform options variables
257 real(kind=dp), dimension(:), allocatable :: box_min, box_max
258 logical :: keep_aspect_ratio
259 real(kind=dp), dimension(3) :: scaling
260 real(kind=dp), dimension(3) :: translation
261 type(field_t) :: temp_field
262 type(aabb_t) :: mesh_box, target_box
263 integer :: idx_p
264
265 ! ------------------------------------------------------------------------ !
266 ! Read the options for the boundary mesh
267
268 call json_get(json, 'name', mesh_file_name)
269
270 ! Settings on how to filter the design field
271 call json_get(json, 'distance_transform.type', distance_transform)
272
273 ! ------------------------------------------------------------------------ !
274 ! Load the immersed boundary mesh
275
276 mesh_file = file_t(mesh_file_name)
277 call mesh_file%read(boundary_mesh)
278
279 if (boundary_mesh%nelv .eq. 0) then
280 call neko_error('No elements in the boundary mesh')
281 end if
282
283 ! ------------------------------------------------------------------------ !
284 ! Transform the mesh if specified.
285
286 call json_get_or_default(json, 'mesh_transform.type', &
287 mesh_transform, 'none')
288
289 select case (mesh_transform)
290 case ('none')
291 ! Do nothing
292 case ('bounding_box')
293 call json_get(json, 'mesh_transform.box_min', box_min)
294 call json_get(json, 'mesh_transform.box_max', box_max)
295 call json_get_or_default(json, 'mesh_transform.keep_aspect_ratio', &
296 keep_aspect_ratio, .true.)
297
298 if (size(box_min) .ne. 3 .or. size(box_max) .ne. 3) then
299 call neko_error('Case file: mesh_transform. &
300 &box_min and box_max must be 3 element arrays of reals')
301 end if
302
303 call target_box%init(box_min, box_max)
304
305 mesh_box = get_aabb(boundary_mesh)
306
307 scaling = target_box%get_diagonal() / mesh_box%get_diagonal()
308 if (keep_aspect_ratio) then
309 scaling = minval(scaling)
310 end if
311
312 translation = - scaling * mesh_box%get_min() + target_box%get_min()
313
314 do idx_p = 1, boundary_mesh%mpts
315 boundary_mesh%points(idx_p)%x = &
316 scaling * boundary_mesh%points(idx_p)%x + translation
317 end do
318
319 case default
320 call neko_error('Unknown mesh transform')
321 end select
322
323 ! ------------------------------------------------------------------------ !
324 ! Compute the permeability field
325
326 ! Assign the signed distance field to all GLL points in the permeability
327 ! field. Initally we just run a brute force loop over all GLL points and
328 ! compute the signed distance function. This should be replaced with a
329 ! more efficient method, such as a tree search.
330
331 call temp_field%init(this%indicator%dof)
332
333 ! Select how to transform the distance field to a design field
334 select case (distance_transform)
335 case ('smooth_step')
336 call json_get(json, 'distance_transform.value', scalar_d)
337 scalar_r = real(scalar_d, kind=rp)
338
339 call signed_distance_field(temp_field, boundary_mesh, scalar_d)
340 call smooth_step_field(temp_field, scalar_r, 0.0_rp)
341
342 case ('step')
343
344 call json_get(json, 'distance_transform.value', scalar_d)
345
346 call signed_distance_field(temp_field, boundary_mesh, scalar_d)
347 call step_function_field(temp_field, scalar_r, 1.0_rp, 0.0_rp)
348
349 case default
350 call neko_error('Unknown distance transform')
351 end select
352
353 ! ------------------------------------------------------------------------ !
354 ! Run filter on the temporary indicator field to smooth it out.
355 call json_get_or_default(json, 'filter.type', filter_type, 'none')
356
357 select case (filter_type)
358 case ('none')
359 ! Do nothing
360 case default
361 call neko_error('Unknown filter type')
362 end select
363
364 ! Update the global indicator field by max operator
365 this%indicator%x = max(this%indicator%x, temp_field%x)
366
367 end subroutine init_boundary_mesh
368
372 subroutine init_point_zone(this, json)
373 class(topopt_brinkman_source_term_t), intent(inout) :: this
374 type(json_file), intent(inout) :: json
375
376 ! Options
377 character(len=:), allocatable :: zone_name
378 character(len=:), allocatable :: filter_type
379
380 type(field_t) :: temp_field
381 class(point_zone_t), pointer :: my_point_zone
382 integer :: i
383
384 ! ------------------------------------------------------------------------ !
385 ! Read the options for the point zone
386
387 call json_get(json, 'name', zone_name)
388 call json_get_or_default(json, 'filter.type', filter_type, 'none')
389
390 ! Compute the indicator field
391
392 call temp_field%init(this%indicator%dof)
393
394 my_point_zone => neko_point_zone_registry%get_point_zone(zone_name)
395
396 do i = 1, my_point_zone%size
397 temp_field%x(my_point_zone%mask(i), 1, 1, 1) = 1.0_rp
398 end do
399
400 ! Run filter on the temporary indicator field to smooth it out.
401
402 select case (filter_type)
403 case ('none')
404 ! Do nothing
405 case default
406 call neko_error('Unknown filter type')
407 end select
408
409 ! Update the global indicator field by max operator
410 this%indicator%x = max(this%indicator%x, temp_field%x)
411
412 end subroutine init_point_zone
413
Implements the brinkman_source_term_t type.
subroutine brinkman_source_term_init_from_json(this, json, fields, coef)
The common constructor using a JSON object.
A Brinkman source term. The region and strength are controlled by assigning regions types and brinkma...