39 use case,
only: case_t
40 use global_interpolation,
only: global_interpolation_t
41 use json_utils,
only: json_get_or_default
42 use logger,
only: neko_log, log_size
43 use num_types,
only: rp
44 use tuple,
only: tuple4_i4_t
45 use utils,
only: neko_error
49 integer,
public,
parameter :: facet_type_interior = 0
50 integer,
public,
parameter :: facet_type_outlet = 1
51 integer,
public,
parameter :: facet_type_inlet = 2
52 integer,
public,
parameter :: facet_type_wall = 3
53 integer,
public,
parameter :: facet_type_sympln = 4
61 pure function cross(a, b)
result(c)
62 real(kind=rp),
dimension(3),
intent(in) :: a
63 real(kind=rp),
dimension(3),
intent(in) :: b
64 real(kind=rp),
dimension(3) :: c
66 c(1) = a(2) * b(3) - a(3) * b(2)
67 c(2) = a(3) * b(1) - a(1) * b(3)
68 c(3) = a(1) * b(2) - a(2) * b(1)
76 pure function dot(a, b)
result(d)
77 real(kind=rp),
dimension(3),
intent(in) :: a(3)
78 real(kind=rp),
dimension(3),
intent(in) :: b(3)
81 d = a(1) * b(1) + a(2) * b(2) + a(3) * b(3)
91 pure function area(nv, vertices)
result(a)
92 integer,
intent(in) :: nv
93 real(kind=rp),
dimension(3, nv),
intent(in) :: vertices
97 real(kind=rp),
dimension(3) :: v1, e1, e2, tmp
98 real(kind=rp) :: cp(3)
107 e1 = (vertices(:, v) - v1)
108 e2 = (vertices(:, v + 1) - v1)
113 a = sqrt(dot(cp, cp))
123 subroutine get_facets(C, out, facet_type)
124 type(case_t),
intent(in) :: C
125 integer,
dimension(:, :),
allocatable,
intent(out) :: out
126 integer,
intent(in),
optional :: facet_type
129 integer :: e, f, facet_id
130 integer :: N_elem, N_facets
131 integer :: facet_type_
133 if (
present(facet_type))
then
134 facet_type_ = facet_type
146 if (c%msh%facet_type(f, e) .eq. facet_type_)
then
147 n_facets = n_facets + 1
153 allocate (out(2, n_facets))
159 if (c%msh%facet_type(f, e) .eq. facet_type_)
then
162 facet_id = facet_id + 1
167 end subroutine get_facets
173 subroutine get_facets_outlet(C, out)
174 type(case_t),
intent(in) :: C
175 integer,
dimension(:, :),
allocatable,
intent(out) :: out
177 call get_facets(c, out, facet_type_outlet)
178 end subroutine get_facets_outlet
187 pure function sum_weighted(a, w)
result(s)
188 real(kind=rp),
dimension(:),
intent(in) :: a
189 real(kind=rp),
dimension(:),
intent(in),
optional :: w
198 end function sum_weighted
206 pure function average_weighted(a, w)
result(m)
207 real(kind=rp),
dimension(:),
intent(in) :: a
208 real(kind=rp),
dimension(:),
intent(in),
optional :: w
212 m = sum_weighted(a, w) / sum(w)
217 end function average_weighted
224 subroutine get_facet_nodes(C, element_id, facet_id, nodes)
225 type(case_t),
intent(in) :: c
226 integer,
intent(in) :: element_id
227 integer,
intent(in) :: facet_id
228 real(kind=rp),
dimension(:, :),
allocatable,
intent(out) :: nodes
233 type(tuple4_i4_t) :: t_hex
237 select type (ele => c%msh%elements(element_id)%e)
242 if (n_nodes .eq. 0)
then
243 call neko_error(
"Error: the facet shape is not supported.")
247 if (
allocated(nodes) .and.
size(nodes, 2) .eq. n_nodes)
then
249 else if (.not.
allocated(nodes))
then
250 allocate (nodes(3, n_nodes))
252 call neko_error(
"Error: the nodes array is not the correct size.")
256 select type (ele => c%msh%elements(element_id)%e)
258 call ele%facet_order(t_hex, facet_id)
261 nodes(:, n) = real(c%msh%points(v)%x, kind=rp)
265 end subroutine get_facet_nodes
267 subroutine estimate_temperature(neko_case)
268 type(case_t),
intent(inout) :: neko_case
269 type(global_interpolation_t) :: interpolator
271 real(kind=rp) :: target_temperature
272 real(kind=rp) :: temperature_mean
273 real(kind=rp),
dimension(:),
allocatable :: temperature_local
275 integer,
allocatable :: facet_list(:, :)
277 real(kind=rp),
dimension(:, :),
allocatable :: facet_nodes
278 real(kind=rp),
dimension(:, :),
allocatable :: facet_centers
279 real(kind=rp),
dimension(:),
allocatable :: facet_area
281 integer :: element_id, facet_id
285 character(len=LOG_SIZE) :: log_buf
288 call json_get_or_default(neko_case%params,
'topopt.target_temperature', &
289 target_temperature, 0.5_rp)
292 call interpolator%init(neko_case%scalars%scalar_fields(1)%dm_xh)
295 call get_facets(neko_case, facet_list)
298 n_facets =
size(facet_list, 2)
299 allocate (facet_centers(3, n_facets))
300 allocate (facet_area(n_facets))
301 allocate (temperature_local(n_facets))
305 element_id = facet_list(1, f)
306 facet_id = facet_list(2, f)
309 call get_facet_nodes(neko_case, element_id, facet_id, facet_nodes)
312 facet_centers(:, f) = 0.0
313 do n = 1,
size(facet_nodes, 2)
314 facet_centers(:, f) = facet_centers(:, f) + facet_nodes(:, n)
316 facet_centers(:, f) = facet_centers(:, f) /
size(facet_nodes, 2)
319 facet_area(f) = area(
size(facet_nodes, 2), facet_nodes)
323 call interpolator%find_points_xyz(facet_centers, n_facets)
324 call interpolator%evaluate(temperature_local, &
325 neko_case%scalars%scalar_fields(1)%s%x, on_host=.false.)
327 temperature_local = temperature_local - target_temperature
328 temperature_mean = average_weighted(temperature_local, facet_area)
330 write (log_buf,
'(a,f15.7)') &
331 "Outlet area-weighted average temperature deviation: ", &
333 call neko_log%message(log_buf)
335 call interpolator%free()
337 end subroutine estimate_temperature