50 use mpi_f08,
only : mpi_allreduce, mpi_integer, mpi_sum
58 type(
coef_t),
pointer :: coef => null()
62 integer,
allocatable :: zone_indices(:)
64 integer :: n_local = 0
66 integer :: n_global = 0
77 logical :: outward_normals = .true.
84 procedure, pass(this) :: update_geometry => &
87 generic :: get => get_vector_by_name, get_vector_by_field
88 procedure,
private, pass(this) :: get_vector_by_name => &
90 procedure,
private, pass(this) :: get_vector_by_field => &
93 generic :: scatter => scatter_to_field_by_vector, &
94 scatter_to_field_by_name
95 procedure,
private, pass(this) :: scatter_to_field_by_vector => &
97 procedure,
private, pass(this) :: scatter_to_field_by_name => &
102 generic :: integrate => integrate_by_name, integrate_by_field
103 procedure,
private, pass(this) :: integrate_by_name => &
105 procedure,
private, pass(this) :: integrate_by_field => &
108 generic :: average => average_by_name, average_by_field
109 procedure,
private, pass(this) :: average_by_name => &
111 procedure,
private, pass(this) :: average_by_field => &
120 generic :: integrate_vector => integrate_vector_by_name, &
121 integrate_vector_by_field
122 procedure,
private, pass(this) :: integrate_vector_by_name => &
124 procedure,
private, pass(this) :: integrate_vector_by_field => &
127 generic :: integrate_normal => integrate_normal_by_name, &
128 integrate_normal_by_field
129 procedure,
private, pass(this) :: integrate_normal_by_name => &
131 procedure,
private, pass(this) :: integrate_normal_by_field => &
134 generic :: flux => flux_by_name, flux_by_field
135 procedure,
private, pass(this) :: flux_by_name => &
137 procedure,
private, pass(this) :: flux_by_field => &
140 generic :: tangential => tangential_inplace, tangential_split
141 procedure,
private, pass(this) :: tangential_inplace => &
143 procedure,
private, pass(this) :: tangential_split => &
146 generic :: normal => normal_inplace, normal_split
147 procedure,
private, pass(this) :: normal_inplace => &
149 procedure,
private, pass(this) :: normal_split => &
163 type(
coef_t),
intent(inout),
target :: coef
164 integer,
intent(in) :: zone_indices(:)
165 logical,
intent(in),
optional :: outward_normals
171 this%outward_normals = .true.
172 if (
present(outward_normals)) this%outward_normals = outward_normals
174 if (
size(zone_indices) .eq. 0)
then
175 call neko_error(
"boundary_data: at least one zone index is required")
177 do i = 1,
size(zone_indices)
178 if (zone_indices(i) .lt. 1 .or. &
180 call neko_error(
"boundary_data: zone index out of range")
184 allocate(this%zone_indices(
size(zone_indices)))
185 this%zone_indices = zone_indices
188 call this%bc%init_base(this%coef)
189 this%bc%zone_indices = this%zone_indices
190 do i = 1,
size(this%zone_indices)
191 call this%bc%mark_zone( &
192 this%coef%dof%msh%labeled_zones(this%zone_indices(i)))
194 call this%bc%finalize(only_facets = .true.)
196 this%n_local = this%bc%msk(0)
198 call mpi_allreduce(this%n_local, this%n_global, 1, mpi_integer, &
201 if (this%n_global .eq. 0)
then
202 call neko_error(
"boundary_data: the requested zones contain no " // &
206 call this%x%init(this%n_local)
207 call this%y%init(this%n_local)
208 call this%z%init(this%n_local)
209 call this%n_x%init(this%n_local)
210 call this%n_y%init(this%n_local)
211 call this%n_z%init(this%n_local)
212 call this%area%init(this%n_local)
213 call this%work%init(this%n_local)
216 call this%update_geometry()
232 call this%area%free()
233 call this%work%free()
235 if (
allocated(this%zone_indices))
deallocate(this%zone_indices)
248 if (this%n_local .le. 0)
return
250 n = this%coef%dof%size()
260 this%bc%msk, this%bc%facet, this%coef%Xh%lx, this%coef%Xh%ly, &
261 this%coef%Xh%lz, this%n_local)
263 this%bc%msk, this%bc%facet, this%coef%Xh%lx, this%coef%Xh%ly, &
264 this%coef%Xh%lz, this%n_local)
266 this%bc%msk, this%bc%facet, this%coef%Xh%lx, this%coef%Xh%ly, &
267 this%coef%Xh%lz, this%n_local)
270 this%bc%msk, this%bc%facet, this%coef%Xh%lx, this%coef%Xh%ly, &
271 this%coef%Xh%lz, this%n_local)
273 if (this%outward_normals)
then
285 character(len=*),
intent(in) :: name
288 select case (trim(name))
289 case (
"x",
"y",
"z",
"n_x",
"n_y",
"n_z",
"area")
304 character(len=*),
intent(in) :: name
308 if (v%size() .ne. this%n_local)
then
310 call v%init(this%n_local)
312 if (this%n_local .le. 0)
return
314 select case (trim(name))
331 call neko_error(
"boundary_data: '" // trim(name) // &
332 "' is neither a geometry attribute (x, y, z, n_x, n_y, " // &
333 "n_z, area) nor a field in the registry")
336 call this%get_vector_by_field(f, v)
349 if (.not.
associated(f%dof, this%coef%dof))
then
350 call neko_error(
"boundary_data: the field '" // trim(f%name) // &
351 "' is on a different dofmap than the boundary mask, so the " // &
352 "masked indices do not apply to it")
355 if (v%size() .ne. this%n_local)
then
357 call v%init(this%n_local)
359 if (this%n_local .le. 0)
return
362 this%coef%dof%size(), this%n_local)
374 type(
field_t),
intent(inout) :: f
375 logical,
intent(in),
optional :: clear
379 if (.not.
associated(f%dof, this%coef%dof))
then
380 call neko_error(
"boundary_data: the destination field is on a " // &
381 "different dofmap than the boundary mask")
385 if (
present(clear)) clear_ = clear
387 n = this%coef%dof%size()
402 character(len=*),
intent(in) :: name
403 type(
field_t),
intent(inout) :: f
404 logical,
intent(in),
optional :: clear
408 if (
present(clear)) clear_ = clear
410 call this%get(trim(name), this%work)
411 call this%scatter_to_field_by_vector(this%work, f, clear_)
425 type(
vector_t),
intent(inout) :: vx, vy, vz
427 if (vx%size() .lt. this%n_local .or. vy%size() .lt. this%n_local .or. &
428 vz%size() .lt. this%n_local)
then
429 call neko_error(
"boundary_data: the vectors passed to tangential " // &
430 "are shorter than the number of boundary points")
433 call vector_vdot3(this%work, vx, vy, vz, this%n_x, this%n_y, this%n_z)
454 type(
vector_t),
intent(in) :: vx, vy, vz
455 type(
vector_t),
intent(inout) :: tx, ty, tz
457 if (vx%size() .lt. this%n_local .or. vy%size() .lt. this%n_local .or. &
458 vz%size() .lt. this%n_local .or. tx%size() .lt. this%n_local .or. &
459 ty%size() .lt. this%n_local .or. tz%size() .lt. this%n_local)
then
460 call neko_error(
"boundary_data: the vectors passed to tangential " // &
461 "are shorter than the number of boundary points")
464 call vector_vdot3(this%work, vx, vy, vz, this%n_x, this%n_y, this%n_z)
484 type(
vector_t),
intent(inout) :: vx, vy, vz
486 if (vx%size() .lt. this%n_local .or. vy%size() .lt. this%n_local .or. &
487 vz%size() .lt. this%n_local)
then
488 call neko_error(
"boundary_data: the vectors passed to normal " // &
489 "are shorter than the number of boundary points")
492 call vector_vdot3(this%work, vx, vy, vz, this%n_x, this%n_y, this%n_z)
513 type(
vector_t),
intent(in) :: vx, vy, vz
514 type(
vector_t),
intent(inout) :: nx, ny, nz
516 if (vx%size() .lt. this%n_local .or. vy%size() .lt. this%n_local .or. &
517 vz%size() .lt. this%n_local .or. nx%size() .lt. this%n_local .or. &
518 ny%size() .lt. this%n_local .or. nz%size() .lt. this%n_local)
then
519 call neko_error(
"boundary_data: the vectors passed to normal " // &
520 "are shorter than the number of boundary points")
523 call vector_vdot3(this%work, vx, vy, vz, this%n_x, this%n_y, this%n_z)
534 character(len=*),
intent(in) :: name
537 call this%get(trim(name), this%work)
549 call this%get(f, this%work)
567 character(len=*),
intent(in) :: name
569 real(kind=
rp) :: total
571 total = this%surface_area()
572 if (total .le. 0.0_rp)
then
573 call neko_error(
"boundary_data: the total surface area is not " // &
574 "positive, cannot form an area weighted average")
576 val = this%integrate(trim(name)) / total
586 real(kind=
rp) :: total
588 total = this%surface_area()
589 if (total .le. 0.0_rp)
then
590 call neko_error(
"boundary_data: the total surface area is not " // &
591 "positive, cannot form an area weighted average")
593 val = this%integrate(f) / total
600 real(kind=
rp) :: c(3)
601 real(kind=
rp) :: total
604 if (total .le. 0.0_rp)
then
605 call neko_error(
"boundary_data: the total surface area is not " // &
606 "positive, cannot form a centroid")
618 real(kind=
rp) :: c(3)
633 type(
field_t),
intent(in) :: fx, fy, fz
634 real(kind=
rp) :: f(3)
636 f(1) = this%integrate(fx)
637 f(2) = this%integrate(fy)
638 f(3) = this%integrate(fz)
648 character(len=*),
intent(in) :: fx, fy, fz
649 real(kind=
rp) :: f(3)
651 f(1) = this%integrate(trim(fx))
652 f(2) = this%integrate(trim(fy))
653 f(3) = this%integrate(trim(fz))
665 type(
field_t),
intent(in) :: u, v, w
668 call this%get(u, this%work)
670 call this%get(v, this%work)
672 call this%get(w, this%work)
683 character(len=*),
intent(in) :: u, v, w
686 call this%get(trim(u), this%work)
688 call this%get(trim(v), this%work)
690 call this%get(trim(w), this%work)
702 real(kind=
rp) :: fn(3)
704 call this%get(f, this%work)
715 character(len=*),
intent(in) :: name
716 real(kind=
rp) :: fn(3)
718 call this%get(trim(name), this%work)
Defines a boundary condition.
Implements the boundary_data_t type.
real(kind=rp) function, dimension(3) boundary_data_point_average(this)
Unweighted mean of the boundary point coordinates.
subroutine boundary_data_get_vector_by_field(this, f, v)
Sample a field at the boundary points into a vector.
real(kind=rp) function boundary_data_flux_by_name(this, u, v, w)
Flux of a named vector quantity through the zones.
subroutine boundary_data_normal_inplace(this, vx, vy, vz)
Keep only the wall normal part of a vector at the boundary points, in place. Each component is overwr...
subroutine boundary_data_update_geometry(this)
Re-gather the coordinates, normals and surface weights.
real(kind=rp) function boundary_data_average_by_field(this, f)
Area weighted average of a field over the zones.
subroutine boundary_data_scatter_to_field_by_vector(this, v, f, clear)
Scatter a boundary vector back into a full field.
subroutine boundary_data_get_vector_by_name(this, name, v)
Sample a named quantity at the boundary points into a vector.
real(kind=rp) function, dimension(3) boundary_data_integrate_vector_by_field(this, fx, fy, fz)
Surface integral of a vector quantity, component by component.
real(kind=rp) function boundary_data_flux_by_field(this, u, v, w)
Flux of a vector quantity through the zones.
subroutine boundary_data_tangential_split(this, vx, vy, vz, tx, ty, tz)
Wall tangential part of a vector at the boundary points, out of place. The input (vx,...
real(kind=rp) function, dimension(3) boundary_data_centroid(this)
Area weighted geometric centre of the zones.
real(kind=rp) function, dimension(3) boundary_data_integrate_normal_by_field(this, f)
Surface integral of a scalar quantity times the normal.
subroutine boundary_data_tangential_inplace(this, vx, vy, vz)
Keep only the wall tangential part of a vector at the boundary points, in place. Each component is ov...
subroutine boundary_data_init(this, coef, zone_indices, outward_normals)
Build the boundary point mask and gather the geometry.
subroutine boundary_data_scatter_to_field_by_name(this, name, f, clear)
Scatter a named boundary quantity into a full field.
real(kind=rp) function boundary_data_surface_area(this)
Total surface area of the zones.
real(kind=rp) function boundary_data_average_by_name(this, name)
Area weighted average of a named quantity over the zones.
subroutine boundary_data_normal_split(this, vx, vy, vz, nx, ny, nz)
Wall normal part of a vector at the boundary points, out of place. The input (vx, vy,...
real(kind=rp) function boundary_data_integrate_by_field(this, f)
Surface integral of a field over the zones.
real(kind=rp) function, dimension(3) boundary_data_integrate_vector_by_name(this, fx, fy, fz)
Surface integral of a named vector quantity, component by component.
real(kind=rp) function boundary_data_integrate_by_name(this, name)
Surface integral of a named quantity over the zones.
real(kind=rp) function, dimension(3) boundary_data_integrate_normal_by_name(this, name)
Surface integral of a named scalar quantity times the normal.
subroutine boundary_data_free(this)
Destructor.
pure logical function boundary_data_is_geometry(name)
Whether name refers to one of the geometry attributes.
type(mpi_comm), public neko_comm
MPI communicator.
Defines a dirichlet boundary condition.
subroutine, public field_rzero(a, n)
Zero a real vector.
integer, parameter, public neko_msh_max_zlbls
Max num. zone labels.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Defines a registry for storing solution fields.
type(registry_t), target, public neko_registry
Global field registry.
subroutine, public vector_masked_gather_copy_0(a, b, mask, n, n_mask)
Gather a vector to reduced contigous array .
real(kind=rp) function, public vector_glsc3(a, b, c, n)
subroutine, public vector_vdot3(dot, u1, u2, u3, v1, v2, v3, n)
Compute a dot product (3-d version) assuming vector components etc.
subroutine, public vector_copy(a, b, n)
Copy a vector .
subroutine, public vector_cmult(a, c, n)
Multiplication by constant c .
subroutine, public vector_face_masked_gather_copy_0(a, b, mask, facet, lx, ly, lz, n_mask)
Gather a face-local SEM field to a reduced contiguous vector.
real(kind=rp) function, public vector_glsum(a, n)
real(kind=rp) function, public vector_glsc2(a, b, n)
subroutine, public vector_subcol3(a, b, c, n)
Returns .
subroutine, public vector_col3(a, b, c, n)
Vector multiplication with 3 vectors .
subroutine, public vector_masked_scatter_copy_0(a, b, mask, n, n_mask)
Scatter a contiguous vector into an array .
Collects data on the boundary points of one or more labelled zones and perform some bounary operation...
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Generic Dirichlet boundary condition on .