Neko  0.8.1
A portable framework for high-order spectral element flow simulations
cpr.f90
Go to the documentation of this file.
1 ! Copyright (c) 2022, The Neko Authors
2 ! All rights reserved.
3 !
4 ! Redistribution and use in source and binary forms, with or without
5 ! modification, are permitted provided that the following conditions
6 ! are met:
7 !
8 ! * Redistributions of source code must retain the above copyright
9 ! notice, this list of conditions and the following disclaimer.
10 !
11 ! * Redistributions in binary form must reproduce the above
12 ! copyright notice, this list of conditions and the following
13 ! disclaimer in the documentation and/or other materials provided
14 ! with the distribution.
15 !
16 ! * Neither the name of the authors nor the names of its
17 ! contributors may be used to endorse or promote products derived
18 ! from this software without specific prior written permission.
19 !
20 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 ! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 ! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 ! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 ! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 ! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 ! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 ! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 ! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 ! POSSIBILITY OF SUCH DAMAGE.
32 !
34 module cpr
35  use gather_scatter
36  use neko_config
37  use num_types
38  use field, only : field_t
39  use space, only : space_t
40  use math
41  use mesh, only : mesh_t
42  use coefs, only : coef_t
43  use tensor
44  use mxm_wrapper
45  use logger
46  use dofmap, only : dofmap_t
47  implicit none
48  private
49 
51  type, public :: cpr_t
52  real(kind=rp), allocatable :: v(:,:)
53 
54  real(kind=rp), allocatable :: vt(:,:)
55  real(kind=rp), allocatable :: vinv(:,:)
56  real(kind=rp), allocatable :: vinvt(:,:)
58  real(kind=rp), allocatable :: w(:,:)
59 
60  real(kind=rp), allocatable :: fldhat(:,:,:,:)
61 
62  type(field_t), pointer :: fld => null()
63  type(space_t), pointer :: xh => null()
64  type(mesh_t), pointer :: msh => null()
65  type(dofmap_t), pointer :: dof => null()
66 
67  end type cpr_t
68 
69  interface cpr_init
70  module procedure cpr_init_all
71  end interface cpr_init
72 
73  public :: cpr_init, cpr_free
74 
75 contains
76 
78  subroutine cpr_init_all(cpr, u)
79  type(cpr_t), intent(inout) :: cpr
80  type(field_t), intent(in), target :: u
81 
82  call cpr_free(cpr)
83 
84  cpr%fld => u
85  cpr%msh => u%msh
86  cpr%Xh => u%Xh
87  cpr%dof => u%dof
88 
89 
90  ! Allocate arrays
91  allocate(cpr%v(cpr%Xh%lx, cpr%Xh%lx))
92  allocate(cpr%vt(cpr%Xh%lx, cpr%Xh%lx))
93  allocate(cpr%vinv(cpr%Xh%lx, cpr%Xh%lx))
94  allocate(cpr%vinvt(cpr%Xh%lx, cpr%Xh%lx))
95  allocate(cpr%w(cpr%Xh%lx, cpr%Xh%lx))
96  allocate(cpr%fldhat(cpr%Xh%lx, cpr%Xh%ly, cpr%Xh%lz, cpr%msh%nelv))
97 
98  ! Initialize all the matrices
100 
101  ! Generate the uhat field (legendre coeff)
102  call cpr_goto_space(cpr,'spec')
103 
104  end subroutine cpr_init_all
105 
106 
108  subroutine cpr_free(cpr)
109  type(cpr_t), intent(inout) :: cpr
110 
111  if(allocated(cpr%v)) then
112  deallocate(cpr%v)
113  end if
114 
115  if(allocated(cpr%vt)) then
116  deallocate(cpr%vt)
117  end if
118 
119  if(allocated(cpr%vinv)) then
120  deallocate(cpr%vinv)
121  end if
122 
123  if(allocated(cpr%vinvt)) then
124  deallocate(cpr%vinvt)
125  end if
126 
127  if(allocated(cpr%w)) then
128  deallocate(cpr%w)
129  end if
130 
131  if(allocated(cpr%fldhat)) then
132  deallocate(cpr%fldhat)
133  end if
134 
135  nullify(cpr%fld)
136  nullify(cpr%msh)
137  nullify(cpr%Xh)
138  nullify(cpr%dof)
139 
140 
141  end subroutine cpr_free
142 
143 
145  subroutine cpr_generate_specmat(cpr)
146  type(cpr_t), intent(inout) :: cpr
147  real(kind=rp) :: l(0:cpr%Xh%lx-1)
148  real(kind=rp) :: delta(cpr%Xh%lx)
149  integer :: i, kj, j, j2, kk
150  character(len=LOG_SIZE) :: log_buf
151 
152  associate(xh => cpr%Xh, v=> cpr%v, vt => cpr%vt, &
153  vinv => cpr%vinv, vinvt => cpr%vinvt, w => cpr%w)
154  ! Get the Legendre polynomials for each point
155  ! Then proceed to compose the transform matrix
156  kj = 0
157  do j = 1, xh%lx
158  l(0) = 1.
159  l(1) = xh%zg(j,1)
160  do j2 = 2, xh%lx-1
161  l(j2) = ( (2*j2-1) * xh%zg(j,1) * l(j2-1) &
162  - (j2-1) * l(j2-2) ) / j2
163  end do
164  do kk = 1, xh%lx
165  kj = kj+1
166  v(kj,1) = l(kk-1)
167  end do
168  end do
169 
170  ! transpose the matrix
171  call trsp1(v, xh%lx)
172 
173  ! Calculate the nominal scaling factors
174  do i = 1, xh%lx
175  delta(i) = 2.0_rp / (2*(i-1)+1)
176  end do
177  ! modify last entry
178  delta(xh%lx) = 2.0_rp / (xh%lx-1)
179 
180  ! calculate the inverse to multiply the matrix
181  do i = 1, xh%lx
182  delta(i) = sqrt(1.0_rp / delta(i))
183  end do
184  ! scale the matrix
185  do i = 1, xh%lx
186  do j = 1, xh%lx
187  v(i,j) = v(i,j) * delta(j) ! orthogonal wrt weights
188  end do
189  end do
190 
191  ! get the trasposed
192  call copy(vt, v, xh%lx * xh%lx)
193  call trsp1(vt, xh%lx)
194 
195  !populate the mass matrix
196  kk = 1
197  do i = 1, xh%lx
198  do j = 1, xh%lx
199  if (i .eq. j) then
200  w(i,j) = xh%wx(kk)
201  kk = kk+1
202  else
203  cpr%w(i,j) = 0
204  end if
205  end do
206  end do
207 
208  !Get the inverse of the transform matrix
209  call mxm(vt, xh%lx, w, xh%lx, vinv, xh%lx)
210 
211  !get the transposed of the inverse
212  call copy(vinvt, vinv, xh%lx * xh%lx)
213  call trsp1(vinvt, xh%lx)
214  end associate
215 
216  end subroutine cpr_generate_specmat
217 
218 
220  !the result of the transform is given in fldhat
221  subroutine cpr_goto_space(cpr, space)
222  type(cpr_t), intent(inout) :: cpr
223  real(kind=rp) :: w2(cpr%Xh%lx,cpr%Xh%lx,cpr%Xh%lx)
224  real(kind=rp) :: w1(cpr%Xh%lx,cpr%Xh%lx,cpr%Xh%lx)
225  real(kind=rp) :: specmat(cpr%Xh%lx,cpr%Xh%lx)
226  real(kind=rp) :: specmatt(cpr%Xh%lx,cpr%Xh%lx)
227  integer :: i, j, k, e, nxyz, nelv
228  character(len=LOG_SIZE) :: log_buf
229  character(len=4) :: space
230 
231  ! define some constants
232  nxyz = cpr%Xh%lx*cpr%Xh%lx*cpr%Xh%lx
233  nelv = cpr%msh%nelv
234 
235  ! Define the matrix according to which transform to do
236  if (space .eq. 'spec') then
237  call copy(specmat, cpr%vinv, cpr%Xh%lx*cpr%Xh%lx)
238  call copy(specmatt, cpr%vinvt, cpr%Xh%lx*cpr%Xh%lx)
239  endif
240  if (space .eq. 'phys') then
241  call copy(specmat, cpr%v, cpr%Xh%lx*cpr%Xh%lx)
242  call copy(specmatt, cpr%vt, cpr%Xh%lx*cpr%Xh%lx)
243  endif
244 
245  ! Apply the operator (transform to given space)
246  do e=1,nelv
247  if (space .eq. 'spec') then
248  call copy(w2, cpr%fld%x(1,1,1,e), nxyz) ! start from phys field
249  else
250  call copy(w2, cpr%fldhat(1,1,1,e), nxyz) ! start from spec coeff
251  endif
252  ! apply the operator to the x direction, result in w1
253  call mxm(specmat, cpr%Xh%lx, w2, cpr%Xh%lx, w1, cpr%Xh%lx*cpr%Xh%lx)
254  ! apply matrix to y direction, result in w2
255  do k=1,cpr%Xh%lx
256  call mxm(w1(1,1,k),cpr%Xh%lx,specmatt,cpr%Xh%lx,w2(1,1,k),cpr%Xh%lx)
257  enddo
258  ! apply matrix to z direction, result always in fldhat
259  call mxm (w2, cpr%Xh%lx*cpr%Xh%lx, specmatt, cpr%Xh%lx,&
260  cpr%fldhat(1,1,1,e), cpr%Xh%lx)
261  enddo
262 
263  end subroutine cpr_goto_space
264 
266  subroutine cpr_truncate_wn(cpr, coef)
267  type(cpr_t), intent(inout) :: cpr
268  type(coef_t), intent(inout) :: coef
269  real(kind=rp) :: w2(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
270  real(kind=rp) :: w1(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
271  real(kind=rp) :: vsort(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
272  real(kind=rp) :: vtrunc(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
273  real(kind=rp) :: vtemp(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
274  real(kind=rp) :: errvec(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
275  real(kind=rp) :: fx(cpr%Xh%lx, cpr%Xh%lx)
276  real(kind=rp) :: fy(cpr%Xh%lx, cpr%Xh%lx)
277  real(kind=rp) :: fz(cpr%Xh%lx, cpr%Xh%lx)
278  real(kind=rp) :: l2norm, oldl2norm, targeterr
279  integer :: isort(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
280  integer :: i, j, k, e, nxyz, nelv
281  integer :: kut, kutx, kuty, kutz, nx
282  character(len=LOG_SIZE) :: log_buf
283 
284  ! define some constants
285  nx = cpr%Xh%lx
286  nxyz = cpr%Xh%lx*cpr%Xh%lx*cpr%Xh%lx
287  nelv = cpr%msh%nelv
288  targeterr = 1e-3_rp
289 
290  !truncate for every element
291  do e = 1, nelv
292  ! create temp vector where the trunc coeff will be
293  call copy(vtemp, cpr%fldhat(1,1,1,e), nxyz)
294  call copy(vtrunc, cpr%fldhat(1,1,1,e), nxyz)
295  ! sort the coefficients by absolute value
296  call sortcoeff(vsort, cpr%fldhat(1,1,1,e), isort, nxyz)
297  ! initialize values for iterative procedure
298  l2norm = 0.0_rp
299  kut = 0
300 
301  do while (l2norm .le. targeterr .and. kut .le. (cpr%Xh%lx-1)*3)
302  ! save value from prev it since it met requirements to enter
303  call copy(vtrunc, vtemp, nxyz)
304  oldl2norm = l2norm
305 
306  ! advance kut
307  kut = kut+1
308 
309  ! create filters
310  call build_filter_tf(fx, fy, fz, kut, cpr%Xh%lx)
311 
312  ! truncate, remember that transposed of diag mat is the same
313  call copy(w2, vsort, nxyz)
314  ! apply the operator to the x direction, result in w1
315  call mxm(fx, nx, w2, nx, w1, nx*nx)
316  ! apply matrix to y direction, result in w2
317  do k=1,nx
318  call mxm(w1(1,1,k), nx, fy, nx, w2(1,1,k), nx)
319  enddo
320  ! apply matrix to z direction, result in vtemp
321  call mxm (w2, nx*nx, fz, nx, vtemp, nx)
322 
323  ! vtemp is sorted, so bring it back to real order
324  ! by inverting the swap operation in sortcoeff
325  call reord(vtemp, isort, nxyz)
326 
327  ! calculate the error vector
328  call sub3(errvec, cpr%fldhat(1,1,1,e), vtemp, nxyz)
329 
330  ! get the norm of the error
331  l2norm = get_elem_l2norm(errvec, coef, 'spec' ,e)
332 
333  end do
334 
335  ! copy the truncated field back to the main object
336  call copy(cpr%fldhat(1,1,1,e), vtrunc, nxyz)
337 
338 
339  !================debugging info
340 
341  !just to check that all is good, resort vsort
342  if (e .eq. 50) then
343  write(log_buf, '(A)') &
344  'Debugging info for e=50. Do not forget to delete'
345  call neko_log%message(log_buf)
346 
347  call reord(vsort,isort,nxyz)
348 
349  write(log_buf, '(A)') &
350  'Norm'
351  call neko_log%message(log_buf)
352  !chech that the copy is fine in one entry
353  write(log_buf, '(A,E15.7)') &
354  'l2norm:', oldl2norm
355  call neko_log%message(log_buf)
356  write(log_buf, '(A)') &
357  'cut off level'
358  call neko_log%message(log_buf)
359  !chech that the copy is fine in one entry
360  write(log_buf, '(A,I5)') &
361  'kut:', kut
362  call neko_log%message(log_buf)
363  write(log_buf, '(A)') &
364  'spectral coefficients'
365  call neko_log%message(log_buf)
366  do i = 1, 10
367  write(log_buf, '(A,E15.7,A,E15.7)') &
368  'org coeff:', vsort(i,1,1), ' truncated coeff', &
369  cpr%fldhat(i,1,1,e)
370  call neko_log%message(log_buf)
371  end do
372  end if
373  end do
374 
375  end subroutine cpr_truncate_wn
376 
379  subroutine sortcoeff(vsort, v, isort, nxyz)
380  integer, intent(in) :: nxyz
381  real(kind=rp), intent(inout) :: vsort(nxyz)
382  real(kind=rp), intent(inout) :: v(nxyz)
383  integer, intent(inout) :: isort(nxyz)
384  real(kind=rp) :: wrksort(nxyz)
385  integer :: wrkisort(nxyz)
386  integer :: i, j, k
387 
388  ! copy absolute values to sort by magnitude
389  do i =1, nxyz
390  vsort(i) = abs(v(i))
391  isort(i) = i
392  end do
393 
394  ! sort the absolute values of the vectors, here the index is the
395  ! important part (isort)
396  call sort(vsort, isort, nxyz)
397 
398  ! Flip the indices so they are in a descending order
399  call flipv(vsort, isort, nxyz)
400 
401  ! now re order the fields (non abs value) based on the indices
402  call copy(vsort, v, nxyz)
403  call swap(vsort, isort, nxyz)
404 
405  end subroutine sortcoeff
406 
408  subroutine flipv(b, ind, n)
409  integer, intent(in) :: n
410  real(kind=rp), intent(inout) :: b(n)
411  integer, intent(inout) :: ind(n)
412  real(kind=rp) :: temp(n)
413  integer :: tempind(n)
414  integer :: i, jj
415 
416  do i = 1, n
417  jj = n+1-i
418  temp(jj) = b(i)
419  tempind(jj) = ind(i)
420  end do
421  do i = 1,n
422  b(i) = temp(i)
423  ind(i) = tempind(i)
424  end do
425 
426  end subroutine flipv
427 
429  subroutine swap(b, ind, n)
430  integer, intent(in) :: n
431  real(kind=rp), intent(inout) :: b(n)
432  integer, intent(inout) :: ind(n)
433  real(kind=rp) :: temp(n)
434  integer :: i, jj
435 
436  do i = 1, n
437  temp(i)=b(i)
438  end do
439  do i = 1, n
440  jj=ind(i)
441  b(i)=temp(jj)
442  end do
443 
444  end subroutine swap
445 
447  subroutine reord(b, ind, n)
448  integer, intent(in) :: n
449  real(kind=rp), intent(inout) :: b(n)
450  integer, intent(inout) :: ind(n)
451  real(kind=rp) :: temp(n)
452  integer :: i, jj
453 
454  do i = 1, n
455  temp(i) = b(i)
456  end do
457  do i = 1, n
458  jj = ind(i)
459  b(jj) = temp(i)
460  end do
461 
462  end subroutine reord
463 
465  subroutine build_filter_tf(fx, fy, fz, kut, lx)
466  integer, intent(in) :: lx
467  integer, intent(in) :: kut
468  real(kind=rp), intent(inout) :: fx(lx,lx)
469  real(kind=rp), intent(inout) :: fy(lx,lx)
470  real(kind=rp), intent(inout) :: fz(lx,lx)
471  integer :: i, j, k, k0, kk, kutx, kuty, kutz
472 
473  ! set the values acording to kut
474  if (kut .eq. 0) then
475  kutz = 0
476  kuty = 0
477  kutx = 0
478  end if
479  if (kut .gt. 0 .and. kut .le. (lx-1)) then
480  kutz = kut
481  kuty = 0
482  kutx = 0
483  end if
484  if (kut .gt. (lx-1) .and. kut .le. (lx-1)*2) then
485  kutz = lx-1
486  kuty = kut-(lx-1)
487  kutx = 0
488  end if
489  if (kut .gt. (lx-1)*2 .and. kut .le. (lx-1)*3) then
490  kutz = lx-1
491  kuty = lx-1
492  kutx = kut-(lx-1)*2
493  end if
494 
495  ! create identity matrices
496  do i = 1, lx
497  do j = 1, lx
498  if (i .eq. j) then
499  fx(i,j) = 1
500  fy(i,j) = 1
501  fz(i,j) = 1
502  else
503  fx(i,j) = 0
504  fy(i,j) = 0
505  fz(i,j) = 0
506  end if
507  end do
508  end do
509 
510  ! truncate the matrices acording to input kut
511  k0 = lx-kutx
512  do k = k0+1, lx
513  kk = k+lx*(k-1)
514  fx(kk,1) = 0
515  end do
516  k0 = lx-kuty
517  do k = k0+1, lx
518  kk = k+lx*(k-1)
519  fy(kk,1) = 0
520  end do
521  k0 = lx-kutz
522  do k = k0+1, lx
523  kk = k+lx*(k-1)
524  fz(kk,1) = 0
525  end do
526 
527  end subroutine build_filter_tf
528 
529 
530  function get_elem_l2norm(elemdata, coef, space, e) result(l2e)
531  type(coef_t), intent(in) :: coef
532  real(kind=rp) :: elemdata(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx)
533  real(kind=rp) :: vole, suma, l2e
534  integer i, e, eg, nxyz
535  character(len=4) :: space
536 
537  ! Get the volume of the element
538  nxyz = coef%Xh%lx*coef%Xh%lx*coef%Xh%lx
539  vole=0
540  do i = 1, nxyz
541  vole = vole+coef%B(i,1,1,e)
542  end do
543 
544  ! Get the weighted l2 norm of the element
545  suma = 0
546  if (space .eq. 'spec') then
547  do i = 1, nxyz
548  suma = suma+elemdata(i,1,1)*elemdata(i,1,1)*coef%jac(i,1,1,e)
549  end do
550  end if
551  if (space .eq. 'phys') then
552  do i = 1, nxyz
553  suma = suma+elemdata(i,1,1)*elemdata(i,1,1)*coef%B(i,1,1,e)
554  end do
555  end if
556 
557  l2e = sqrt(suma)/sqrt(vole)
558 
559  end function get_elem_l2norm
560 
561 
562 end module cpr
Coefficients.
Definition: coef.f90:34
Compression.
Definition: cpr.f90:34
subroutine build_filter_tf(fx, fy, fz, kut, lx)
create filter transfer function
Definition: cpr.f90:466
real(kind=rp) function get_elem_l2norm(elemdata, coef, space, e)
Definition: cpr.f90:531
subroutine cpr_truncate_wn(cpr, coef)
Truncate the frequencies.
Definition: cpr.f90:267
subroutine swap(b, ind, n)
sort the array acording to ind vector
Definition: cpr.f90:430
subroutine cpr_init_all(cpr, u)
Initialize cpr.
Definition: cpr.f90:79
subroutine sortcoeff(vsort, v, isort, nxyz)
Sort the spectral coefficient in descending order array vsort. The original indices are stored in the...
Definition: cpr.f90:380
subroutine flipv(b, ind, n)
Flip vector b and ind.
Definition: cpr.f90:409
subroutine cpr_goto_space(cpr, space)
Tranform to spectral space (using tensor product)
Definition: cpr.f90:222
subroutine reord(b, ind, n)
reorder the array - inverse of swap
Definition: cpr.f90:448
subroutine cpr_generate_specmat(cpr)
Generate spectral tranform matrices.
Definition: cpr.f90:146
subroutine, public cpr_free(cpr)
Deallocate coefficients.
Definition: cpr.f90:109
Defines a mapping of the degrees of freedom.
Definition: dofmap.f90:35
Defines a field.
Definition: field.f90:34
Gather-scatter.
Logging routines.
Definition: log.f90:34
Definition: math.f90:60
subroutine, public copy(a, b, n)
Copy a vector .
Definition: math.f90:211
Defines a mesh.
Definition: mesh.f90:34
Wrapper for all matrix-matrix product implementations.
Definition: mxm_wrapper.F90:2
subroutine, public mxm(a, n1, b, n2, c, n3)
Compute matrix-matrix product for contiguously packed matrices A,B, and C.
Definition: mxm_wrapper.F90:29
Build configurations.
Definition: neko_config.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12
Defines a function space.
Definition: space.f90:34
Tensor operations.
Definition: tensor.f90:61
subroutine, public trsp1(a, n)
In-place transpose of a square tensor.
Definition: tensor.f90:137
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition: coef.f90:54
include information needed for compressing fields
Definition: cpr.f90:51
The function space for the SEM solution fields.
Definition: space.f90:62