Neko  0.9.99
A portable framework for high-order spectral element flow simulations
map_1d.f90
Go to the documentation of this file.
1 
3 module map_1d
4  use num_types, only: rp
5  use space, only: space_t
6  use dofmap, only: dofmap_t
8  use mesh, only: mesh_t
9  use device
10  use comm
11  use coefs, only: coef_t
12  use field_list, only: field_list_t
13  use matrix, only: matrix_t
14  use vector, only: vector_ptr_t
15  use logger, only: neko_log, log_size
16  use utils, only: neko_error, neko_warning
17  use math, only: glmax, glmin, glimax, glimin, relcmp, cmult, add2s1, col2
18  use neko_mpi_types
19  use, intrinsic :: iso_c_binding
20  implicit none
21  private
26  type, public :: map_1d_t
29  integer, allocatable :: dir_el(:)
31  integer, allocatable :: el_lvl(:)
33  integer, allocatable :: pt_lvl(:,:,:,:)
35  integer :: n_el_lvls
37  integer :: n_gll_lvls
40  type(dofmap_t), pointer :: dof => null()
42  type(coef_t), pointer :: coef => null()
44  type(mesh_t), pointer :: msh => null()
46  integer :: dir
48  real(kind=rp) :: tol = 1e-7
50  real(kind=rp), allocatable :: volume_per_gll_lvl(:)
51  contains
53  procedure, pass(this) :: init_int => map_1d_init
54 
55  procedure, pass(this) :: init_char => map_1d_init_char
56  generic :: init => init_int, init_char
58  procedure, pass(this) :: free => map_1d_free
60  procedure, pass(this) :: average_planes_fld_lst => map_1d_average_field_list
61 
62  procedure, pass(this) :: average_planes_vec_ptr => map_1d_average_vector_ptr
63  generic :: average_planes => average_planes_fld_lst, average_planes_vec_ptr
64  end type map_1d_t
65 
66 
67 contains
68 
69  subroutine map_1d_init(this, coef, dir, tol)
70  class(map_1d_t) :: this
71  type(coef_t), intent(inout), target :: coef
72  integer, intent(in) :: dir
73  real(kind=rp), intent(in) :: tol
74  integer :: nelv, lx, n, i, e, lvl, ierr
75  real(kind=rp), contiguous, pointer :: line(:,:,:,:)
76  real(kind=rp), allocatable :: min_vals(:,:,:,:)
77  real(kind=rp), allocatable :: min_temp(:,:,:,:)
78  type(c_ptr) :: min_vals_d = c_null_ptr
79  real(kind=rp) :: el_dim(3,3), glb_min, glb_max, el_min
80 
81  call this%free()
82 
83  if (neko_bcknd_device .eq. 1) then
84  if (pe_rank .eq. 0) then
85  call neko_warning('map_1d does not copy indices to device,'// &
86  ' but ok if used on cpu and for io')
87  end if
88  end if
89 
90  this%dir = dir
91  this%dof => coef%dof
92  this%coef => coef
93  this%msh => coef%msh
94  nelv = this%msh%nelv
95  lx = this%dof%Xh%lx
96  n = this%dof%size()
97 
98  if (dir .eq. 1) then
99  line => this%dof%x
100  else if (dir .eq. 2) then
101  line => this%dof%y
102  else if(dir .eq. 3) then
103  line => this%dof%z
104  else
105  call neko_error('Invalid dir for geopmetric comm')
106  end if
107  allocate(this%dir_el(nelv))
108  allocate(this%el_lvl(nelv))
109  allocate(this%pt_lvl(lx, lx, lx, nelv))
110  allocate(min_vals(lx, lx, lx, nelv))
111  allocate(min_temp(lx, lx, lx, nelv))
112  call mpi_barrier(neko_comm)
113  if (neko_bcknd_device .eq. 1) then
114 
115  call device_map(min_vals,min_vals_d,n)
116  end if
117  call mpi_barrier(neko_comm)
118 
119  do i = 1, nelv
120  !store which direction r,s,t corresponds to speciifed direction, x,y,z
121  !we assume elements are stacked on each other...
122  ! Check which one of the normalized vectors are closest to dir
123  ! If we want to incorporate other directions, we should look here
124  el_dim(1,:) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
125  this%msh%elements(i)%e%pts(2)%p%x)
126  el_dim(1,:) = el_dim(1,:)/norm2(el_dim(1,:))
127  el_dim(2,:) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
128  this%msh%elements(i)%e%pts(3)%p%x)
129  el_dim(2,:) = el_dim(2,:)/norm2(el_dim(2,:))
130  el_dim(3,:) = abs(this%msh%elements(i)%e%pts(1)%p%x - &
131  this%msh%elements(i)%e%pts(5)%p%x)
132  el_dim(3,:) = el_dim(3,:)/norm2(el_dim(3,:))
133  ! Checks which directions in rst the xyz corresponds to
134  ! 1 corresponds to r, 2 to s, 3 to t and are stored in dir_el
135  this%dir_el(i) = maxloc(el_dim(:,this%dir),dim=1)
136  end do
137  glb_min = glmin(line,n)
138  glb_max = glmax(line,n)
139 
140  i = 1
141  this%el_lvl = -1
142  ! Check what the mimum value in each element and put in min_vals
143  do e = 1, nelv
144  el_min = minval(line(:,:,:,e))
145  min_vals(:,:,:,e) = el_min
146  ! Check if this element is on the bottom, in this case assign el_lvl = i = 1
147  if (relcmp(el_min, glb_min, this%tol)) then
148  if(this%el_lvl(e) .eq. -1) this%el_lvl(e) = i
149  end if
150  end do
151  ! While loop where at each iteation the global maximum value
152  ! propagates down one level.
153  ! When the minumum value has propagated to the highest level this stops.
154  ! Only works when the bottom plate of the domain is flat.
155  do while (.not. relcmp(glmax(min_vals,n), glb_min, this%tol))
156  i = i + 1
157  do e = 1, nelv
158  !Sets the value at the bottom of each element to glb_max
159  if (this%dir_el(e) .eq. 1) then
160  if (line(1,1,1,e) .gt. line(lx,1,1,e)) then
161  min_vals(lx,:,:,e) = glb_max
162  else
163  min_vals(1,:,:,e) = glb_max
164  end if
165  end if
166  if (this%dir_el(e) .eq. 2) then
167  if (line(1,1,1,e) .gt. line(1,lx,1,e)) then
168  min_vals(:,lx,:,e) = glb_max
169  else
170  min_vals(:,1,:,e) = glb_max
171  end if
172  end if
173  if (this%dir_el(e) .eq. 3) then
174  if (line(1,1,1,e) .gt. line(1,1,lx,e)) then
175  min_vals(:,:,lx,e) = glb_max
176  else
177  min_vals(:,:,1,e) = glb_max
178  end if
179  end if
180  end do
181  !Make sketchy min as GS_OP_MIN is not supported with device mpi
182  min_temp = min_vals
183  if (neko_bcknd_device .eq. 1) &
184  call device_memcpy(min_vals, min_vals_d, n,&
185  host_to_device, sync=.false.)
186  !Propagates the minumum value along the element boundary.
187  call coef%gs_h%op(min_vals, n, gs_op_add)
188  if (neko_bcknd_device .eq. 1) &
189  call device_memcpy(min_vals, min_vals_d, n,&
190  device_to_host, sync=.true.)
191  !Obtain average along boundary
192 
193  call col2(min_vals, coef%mult, n)
194  call cmult(min_temp, -1.0_rp, n)
195  call add2s1(min_vals, min_temp, 2.0_rp, n)
196 
197 
198  !Checks the new minimum value on each element
199  !Assign this value to all points in this element in min_val
200  !If the element has not already been assinged a level,
201  !and it has obtained the minval, set el_lvl = i
202  do e = 1, nelv
203  el_min = minval(min_vals(:,:,:,e))
204  min_vals(:,:,:,e) = el_min
205  if (relcmp(el_min, glb_min, this%tol)) then
206  if (this%el_lvl(e) .eq. -1) this%el_lvl(e) = i
207  end if
208  end do
209  end do
210  this%n_el_lvls = glimax(this%el_lvl,nelv)
211  this%n_gll_lvls = this%n_el_lvls*lx
212  !Numbers the points in each element based on the element level
213  !and its orientation
214  do e = 1, nelv
215  do i = 1, lx
216  lvl = lx * (this%el_lvl(e) - 1) + i
217  if (this%dir_el(e) .eq. 1) then
218  if (line(1,1,1,e) .gt. line(lx,1,1,e)) then
219  this%pt_lvl(lx-i+1,:,:,e) = lvl
220  else
221  this%pt_lvl(i,:,:,e) = lvl
222  end if
223  end if
224  if (this%dir_el(e) .eq. 2) then
225  if (line(1,1,1,e) .gt. line(1,lx,1,e)) then
226  this%pt_lvl(:,lx-i+1,:,e) = lvl
227  else
228  this%pt_lvl(:,i,:,e) = lvl
229  end if
230  end if
231  if (this%dir_el(e) .eq. 3) then
232  if (line(1,1,1,e) .gt. line(1,1,lx,e)) then
233  this%pt_lvl(:,:,lx-i+1,e) = lvl
234  else
235  this%pt_lvl(:,:,i,e) = lvl
236  end if
237  end if
238  end do
239  end do
240  if(allocated(min_vals)) deallocate(min_vals)
241  if(c_associated(min_vals_d)) call device_free(min_vals_d)
242  if(allocated(min_temp)) deallocate(min_temp)
243  allocate(this%volume_per_gll_lvl(this%n_gll_lvls))
244  this%volume_per_gll_lvl =0.0_rp
245  do i = 1, n
246  this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1)) = &
247  this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1)) + coef%B(i,1,1,1)
248  end do
249  call mpi_allreduce(mpi_in_place,this%volume_per_gll_lvl, this%n_gll_lvls, &
250  mpi_real_precision, mpi_sum, neko_comm, ierr)
251 
252  end subroutine map_1d_init
253 
254  subroutine map_1d_init_char(this, coef, dir, tol)
255  class(map_1d_t) :: this
256  type(coef_t), intent(inout), target :: coef
257  character(len=*), intent(in) :: dir
258  real(kind=rp), intent(in) :: tol
259  integer :: idir
260 
261  if (trim(dir) .eq. 'yz' .or. trim(dir) .eq. 'zy') then
262  idir = 1
263  else if (trim(dir) .eq. 'xz' .or. trim(dir) .eq. 'zx') then
264  idir = 2
265  else if (trim(dir) .eq. 'xy' .or. trim(dir) .eq. 'yx') then
266  idir = 3
267  else
268  call neko_error('homogenous direction not supported')
269  end if
270 
271  call this%init(coef,idir,tol)
272 
273  end subroutine map_1d_init_char
274 
275  subroutine map_1d_free(this)
276  class(map_1d_t) :: this
277 
278  if(allocated(this%dir_el)) deallocate(this%dir_el)
279  if(allocated(this%el_lvl)) deallocate(this%el_lvl)
280  if(allocated(this%pt_lvl)) deallocate(this%pt_lvl)
281  if(associated(this%dof)) nullify(this%dof)
282  if(associated(this%msh)) nullify(this%msh)
283  if(associated(this%coef)) nullify(this%coef)
284  if(allocated(this%volume_per_gll_lvl)) deallocate(this%volume_per_gll_lvl)
285  this%dir = 0
286  this%n_el_lvls = 0
287  this%n_gll_lvls = 0
288 
289  end subroutine map_1d_free
290 
291 
297  subroutine map_1d_average_field_list(this, avg_planes, field_list)
298  class(map_1d_t), intent(inout) :: this
299  type(field_list_t), intent(inout) :: field_list
300  type(matrix_t), intent(inout) :: avg_planes
301  integer :: n, ierr, j, i
302  real(kind=rp) :: coord
303  call avg_planes%free()
304  call avg_planes%init(this%n_gll_lvls, field_list%size()+1)
305  avg_planes = 0.0_rp
306  !ugly way of getting coordinates, computes average
307  n = this%dof%size()
308  do i = 1, n
309  if (this%dir .eq. 1) coord = this%dof%x(i,1,1,1)
310  if (this%dir .eq. 2) coord = this%dof%y(i,1,1,1)
311  if (this%dir .eq. 3) coord = this%dof%z(i,1,1,1)
312  avg_planes%x(this%pt_lvl(i,1,1,1),1) = &
313  avg_planes%x(this%pt_lvl(i,1,1,1),1) + coord*this%coef%B(i,1,1,1) &
314  /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
315  end do
316  do j = 2, field_list%size() + 1
317  do i = 1, n
318  avg_planes%x(this%pt_lvl(i,1,1,1),j) = &
319  avg_planes%x(this%pt_lvl(i,1,1,1),j) + &
320  field_list%items(j-1)%ptr%x(i,1,1,1)*this%coef%B(i,1,1,1) &
321  /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
322  end do
323  end do
324  if (pe_size .gt. 1) then
325  call mpi_allreduce(mpi_in_place, avg_planes%x, (field_list%size()+1)*this%n_gll_lvls, &
326  mpi_real_precision, mpi_sum, neko_comm, ierr)
327  end if
328 
329 
330  end subroutine map_1d_average_field_list
331 
337  subroutine map_1d_average_vector_ptr(this, avg_planes, vector_ptr)
338  class(map_1d_t), intent(inout) :: this
339  !Observe is an array...
340  type(vector_ptr_t), intent(inout) :: vector_ptr(:)
341  type(matrix_t), intent(inout) :: avg_planes
342  integer :: n, ierr, j, i
343  real(kind=rp) :: coord
344 
345  call avg_planes%free()
346  call avg_planes%init(this%n_gll_lvls,size(vector_ptr)+1)
347  !ugly way of getting coordinates, computes average
348  avg_planes = 0.0_rp
349 
350  n = this%dof%size()
351  do i = 1, n
352  if (this%dir .eq. 1) coord = this%dof%x(i,1,1,1)
353  if (this%dir .eq. 2) coord = this%dof%y(i,1,1,1)
354  if (this%dir .eq. 3) coord = this%dof%z(i,1,1,1)
355  avg_planes%x(this%pt_lvl(i,1,1,1),1) = &
356  avg_planes%x(this%pt_lvl(i,1,1,1),1) + coord*this%coef%B(i,1,1,1) &
357  /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
358  end do
359  do j = 2, size(vector_ptr)+1
360  do i = 1, n
361  avg_planes%x(this%pt_lvl(i,1,1,1),j) = &
362  avg_planes%x(this%pt_lvl(i,1,1,1),j) + &
363  vector_ptr(j-1)%ptr%x(i)*this%coef%B(i,1,1,1) &
364  /this%volume_per_gll_lvl(this%pt_lvl(i,1,1,1))
365  end do
366  end do
367  call mpi_allreduce(mpi_in_place,avg_planes%x, (size(vector_ptr)+1)*this%n_gll_lvls, &
368  mpi_real_precision, mpi_sum, neko_comm, ierr)
369 
370 
371  end subroutine map_1d_average_vector_ptr
372 
373 end module map_1d
Map a Fortran array to a device (allocate and associate)
Definition: device.F90:57
Copy data between host and device (or device and device)
Definition: device.F90:51
Coefficients.
Definition: coef.f90:34
Definition: comm.F90:1
integer pe_rank
MPI rank.
Definition: comm.F90:28
type(mpi_comm) neko_comm
MPI communicator.
Definition: comm.F90:16
type(mpi_datatype) mpi_real_precision
MPI type for working precision of REAL types.
Definition: comm.F90:23
integer pe_size
MPI size of communicator.
Definition: comm.F90:31
Device abstraction, common interface for various accelerators.
Definition: device.F90:34
integer, parameter, public host_to_device
Definition: device.F90:47
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition: device.F90:185
integer, parameter, public device_to_host
Definition: device.F90:47
Defines a mapping of the degrees of freedom.
Definition: dofmap.f90:35
Gather-scatter.
Logging routines.
Definition: log.f90:34
type(log_t), public neko_log
Global log stream.
Definition: log.f90:65
integer, parameter, public log_size
Definition: log.f90:42
Creates a 1d GLL point map along a specified direction based on the connectivity in the mesh.
Definition: map_1d.f90:3
subroutine map_1d_init(this, coef, dir, tol)
Definition: map_1d.f90:70
subroutine map_1d_free(this)
Definition: map_1d.f90:276
subroutine map_1d_average_field_list(this, avg_planes, field_list)
Computes average if field list in two directions and outputs matrix with averaged values avg_planes c...
Definition: map_1d.f90:298
subroutine map_1d_init_char(this, coef, dir, tol)
Definition: map_1d.f90:255
subroutine map_1d_average_vector_ptr(this, avg_planes, vector_ptr)
Computes average if vector_pt in two directions and outputs matrix with averaged values avg_planes co...
Definition: map_1d.f90:338
Definition: math.f90:60
subroutine, public cmult(a, c, n)
Multiplication by constant c .
Definition: math.f90:311
subroutine, public add2s1(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on first argument)
Definition: math.f90:658
integer function, public glimin(a, n)
Min of an integer vector of length n.
Definition: math.f90:422
subroutine, public col2(a, b, n)
Vector multiplication .
Definition: math.f90:729
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
Definition: math.f90:377
integer function, public glimax(a, n)
Max of an integer vector of length n.
Definition: math.f90:392
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
Definition: math.f90:407
Defines a matrix.
Definition: matrix.f90:34
Defines a mesh.
Definition: mesh.f90:34
MPI derived types.
Definition: mpi_types.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12
Defines a function space.
Definition: space.f90:34
Utilities.
Definition: utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition: utils.f90:245
Defines a vector.
Definition: vector.f90:34
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition: coef.f90:55
field_list_t, To be able to group fields together
Definition: field_list.f90:13
Type that encapsulates a mapping from each gll point in the mesh to its corresponding (global) GLL po...
Definition: map_1d.f90:26
The function space for the SEM solution fields.
Definition: space.f90:62