Neko 0.9.99
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
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!
34module cpr
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
75contains
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
151 associate(xh => cpr%Xh, v=> cpr%v, vt => cpr%vt, &
152 vinv => cpr%vinv, vinvt => cpr%vinvt, w => cpr%w)
153 ! Get the Legendre polynomials for each point
154 ! Then proceed to compose the transform matrix
155 kj = 0
156 do j = 1, xh%lx
157 l(0) = 1.
158 l(1) = xh%zg(j,1)
159 do j2 = 2, xh%lx-1
160 l(j2) = ( (2*j2-1) * xh%zg(j,1) * l(j2-1) &
161 - (j2-1) * l(j2-2) ) / j2
162 end do
163 do kk = 1, xh%lx
164 kj = kj+1
165 v(kj,1) = l(kk-1)
166 end do
167 end do
168
169 ! transpose the matrix
170 call trsp1(v, xh%lx)
171
172 ! Calculate the nominal scaling factors
173 do i = 1, xh%lx
174 delta(i) = 2.0_rp / (2*(i-1)+1)
175 end do
176 ! modify last entry
177 delta(xh%lx) = 2.0_rp / (xh%lx-1)
178
179 ! calculate the inverse to multiply the matrix
180 do i = 1, xh%lx
181 delta(i) = sqrt(1.0_rp / delta(i))
182 end do
183 ! scale the matrix
184 do i = 1, xh%lx
185 do j = 1, xh%lx
186 v(i,j) = v(i,j) * delta(j) ! orthogonal wrt weights
187 end do
188 end do
189
190 ! get the trasposed
191 call copy(vt, v, xh%lx * xh%lx)
192 call trsp1(vt, xh%lx)
193
194 !populate the mass matrix
195 kk = 1
196 do i = 1, xh%lx
197 do j = 1, xh%lx
198 if (i .eq. j) then
199 w(i,j) = xh%wx(kk)
200 kk = kk+1
201 else
202 cpr%w(i,j) = 0
203 end if
204 end do
205 end do
206
207 !Get the inverse of the transform matrix
208 call mxm(vt, xh%lx, w, xh%lx, vinv, xh%lx)
209
210 !get the transposed of the inverse
211 call copy(vinvt, vinv, xh%lx * xh%lx)
212 call trsp1(vinvt, xh%lx)
213 end associate
214
215 end subroutine cpr_generate_specmat
216
217
219 !the result of the transform is given in fldhat
220 subroutine cpr_goto_space(cpr, space)
221 type(cpr_t), intent(inout) :: cpr
222 real(kind=rp) :: w2(cpr%Xh%lx,cpr%Xh%lx,cpr%Xh%lx)
223 real(kind=rp) :: w1(cpr%Xh%lx,cpr%Xh%lx,cpr%Xh%lx)
224 real(kind=rp) :: specmat(cpr%Xh%lx,cpr%Xh%lx)
225 real(kind=rp) :: specmatt(cpr%Xh%lx,cpr%Xh%lx)
226 integer :: k, e, nxyz, nelv
227 character(len=4) :: space
228
229 ! define some constants
230 nxyz = cpr%Xh%lx*cpr%Xh%lx*cpr%Xh%lx
231 nelv = cpr%msh%nelv
232
233 ! Define the matrix according to which transform to do
234 if (space .eq. 'spec') then
235 call copy(specmat, cpr%vinv, cpr%Xh%lx*cpr%Xh%lx)
236 call copy(specmatt, cpr%vinvt, cpr%Xh%lx*cpr%Xh%lx)
237 endif
238 if (space .eq. 'phys') then
239 call copy(specmat, cpr%v, cpr%Xh%lx*cpr%Xh%lx)
240 call copy(specmatt, cpr%vt, cpr%Xh%lx*cpr%Xh%lx)
241 endif
242
243 ! Apply the operator (transform to given space)
244 do e=1,nelv
245 if (space .eq. 'spec') then
246 call copy(w2, cpr%fld%x(1,1,1,e), nxyz) ! start from phys field
247 else
248 call copy(w2, cpr%fldhat(1,1,1,e), nxyz) ! start from spec coeff
249 endif
250 ! apply the operator to the x direction, result in w1
251 call mxm(specmat, cpr%Xh%lx, w2, cpr%Xh%lx, w1, cpr%Xh%lx*cpr%Xh%lx)
252 ! apply matrix to y direction, result in w2
253 do k=1,cpr%Xh%lx
254 call mxm(w1(1,1,k),cpr%Xh%lx,specmatt,cpr%Xh%lx,w2(1,1,k),cpr%Xh%lx)
255 enddo
256 ! apply matrix to z direction, result always in fldhat
257 call mxm (w2, cpr%Xh%lx*cpr%Xh%lx, specmatt, cpr%Xh%lx,&
258 cpr%fldhat(1,1,1,e), cpr%Xh%lx)
259 enddo
260
261 end subroutine cpr_goto_space
262
264 subroutine cpr_truncate_wn(cpr, coef)
265 type(cpr_t), intent(inout) :: cpr
266 type(coef_t), intent(inout) :: coef
267 real(kind=rp) :: w2(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
268 real(kind=rp) :: w1(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
269 real(kind=rp) :: vsort(cpr%Xh%lx * cpr%Xh%lx * cpr%Xh%lx)
270 real(kind=rp) :: vtrunc(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
271 real(kind=rp) :: vtemp(cpr%Xh%lx * cpr%Xh%lx * cpr%Xh%lx)
272 real(kind=rp) :: errvec(cpr%Xh%lx, cpr%Xh%lx, cpr%Xh%lx)
273 real(kind=rp) :: fx(cpr%Xh%lx, cpr%Xh%lx)
274 real(kind=rp) :: fy(cpr%Xh%lx, cpr%Xh%lx)
275 real(kind=rp) :: fz(cpr%Xh%lx, cpr%Xh%lx)
276 real(kind=rp) :: l2norm, oldl2norm, targeterr
277 integer :: isort(cpr%Xh%lx * cpr%Xh%lx * cpr%Xh%lx)
278 integer :: i, j, k, e, nxyz, nelv
279 integer :: kut, kutx, kuty, kutz, nx
280 character(len=LOG_SIZE) :: log_buf
281
282 ! define some constants
283 nx = cpr%Xh%lx
284 nxyz = cpr%Xh%lx*cpr%Xh%lx*cpr%Xh%lx
285 nelv = cpr%msh%nelv
286 targeterr = 1e-3_rp
287
288 !truncate for every element
289 do e = 1, nelv
290 ! create temp vector where the trunc coeff will be
291 call copy(vtemp, cpr%fldhat(1,1,1,e), nxyz)
292 call copy(vtrunc, cpr%fldhat(1,1,1,e), nxyz)
293 ! sort the coefficients by absolute value
294 call sortcoeff(vsort, cpr%fldhat(1,1,1,e), isort, nxyz)
295 ! initialize values for iterative procedure
296 l2norm = 0.0_rp
297 kut = 0
298
299 do while (l2norm .le. targeterr .and. kut .le. (cpr%Xh%lx-1)*3)
300 ! save value from prev it since it met requirements to enter
301 call copy(vtrunc, vtemp, nxyz)
302 oldl2norm = l2norm
303
304 ! advance kut
305 kut = kut+1
306
307 ! create filters
308 call build_filter_tf(fx, fy, fz, kut, cpr%Xh%lx)
309
310 ! truncate, remember that transposed of diag mat is the same
311 call copy(w2, vsort, nxyz)
312 ! apply the operator to the x direction, result in w1
313 call mxm(fx, nx, w2, nx, w1, nx*nx)
314 ! apply matrix to y direction, result in w2
315 do k=1,nx
316 call mxm(w1(1,1,k), nx, fy, nx, w2(1,1,k), nx)
317 enddo
318 ! apply matrix to z direction, result in vtemp
319 call mxm (w2, nx*nx, fz, nx, vtemp, nx)
320
321 ! vtemp is sorted, so bring it back to real order
322 ! by inverting the swap operation in sortcoeff
323 call reord(vtemp, isort, nxyz)
324
325 ! calculate the error vector
326 call sub3(errvec, cpr%fldhat(1,1,1,e), vtemp, nxyz)
327
328 ! get the norm of the error
329 l2norm = get_elem_l2norm(errvec, coef, 'spec' ,e)
330
331 end do
332
333 ! copy the truncated field back to the main object
334 call copy(cpr%fldhat(1,1,1,e), vtrunc, nxyz)
335
336
337 !================debugging info
338
339 !just to check that all is good, resort vsort
340 if (e .eq. 50) then
341 write(log_buf, '(A)') &
342 'Debugging info for e=50. Do not forget to delete'
343 call neko_log%message(log_buf)
344
345 call reord(vsort,isort,nxyz)
346
347 write(log_buf, '(A)') &
348 'Norm'
349 call neko_log%message(log_buf)
350 !chech that the copy is fine in one entry
351 write(log_buf, '(A,E15.7)') &
352 'l2norm:', oldl2norm
353 call neko_log%message(log_buf)
354 write(log_buf, '(A)') &
355 'cut off level'
356 call neko_log%message(log_buf)
357 !chech that the copy is fine in one entry
358 write(log_buf, '(A,I5)') &
359 'kut:', kut
360 call neko_log%message(log_buf)
361 write(log_buf, '(A)') &
362 'spectral coefficients'
363 call neko_log%message(log_buf)
364 do i = 1, 10
365 write(log_buf, '(A,E15.7,A,E15.7)') &
366 'org coeff:', vsort(i), ' truncated coeff', &
367 cpr%fldhat(i,1,1,e)
368 call neko_log%message(log_buf)
369 end do
370 end if
371 end do
372
373 end subroutine cpr_truncate_wn
374
377 subroutine sortcoeff(vsort, v, isort, nxyz)
378 integer, intent(in) :: nxyz
379 real(kind=rp), intent(inout) :: vsort(nxyz)
380 real(kind=rp), intent(inout) :: v(nxyz)
381 integer, intent(inout) :: isort(nxyz)
382 integer :: i
383
384 ! copy absolute values to sort by magnitude
385 do i =1, nxyz
386 vsort(i) = abs(v(i))
387 isort(i) = i
388 end do
389
390 ! sort the absolute values of the vectors, here the index is the
391 ! important part (isort)
392 call sort(vsort, isort, nxyz)
393
394 ! Flip the indices so they are in a descending order
395 call flipv(vsort, isort, nxyz)
396
397 ! now re order the fields (non abs value) based on the indices
398 call copy(vsort, v, nxyz)
399 call swap(vsort, isort, nxyz)
400
401 end subroutine sortcoeff
402
404 subroutine build_filter_tf(fx, fy, fz, kut, lx)
405 integer, intent(in) :: lx
406 integer, intent(in) :: kut
407 real(kind=rp), intent(inout) :: fx(lx,lx)
408 real(kind=rp), intent(inout) :: fy(lx,lx)
409 real(kind=rp), intent(inout) :: fz(lx,lx)
410 integer :: i, j, k, k0, kk, kutx, kuty, kutz
411
412 ! set the values acording to kut
413 if (kut .eq. 0) then
414 kutz = 0
415 kuty = 0
416 kutx = 0
417 end if
418 if (kut .gt. 0 .and. kut .le. (lx-1)) then
419 kutz = kut
420 kuty = 0
421 kutx = 0
422 end if
423 if (kut .gt. (lx-1) .and. kut .le. (lx-1)*2) then
424 kutz = lx-1
425 kuty = kut-(lx-1)
426 kutx = 0
427 end if
428 if (kut .gt. (lx-1)*2 .and. kut .le. (lx-1)*3) then
429 kutz = lx-1
430 kuty = lx-1
431 kutx = kut-(lx-1)*2
432 end if
433
434 ! create identity matrices
435 do i = 1, lx
436 do j = 1, lx
437 if (i .eq. j) then
438 fx(i,j) = 1
439 fy(i,j) = 1
440 fz(i,j) = 1
441 else
442 fx(i,j) = 0
443 fy(i,j) = 0
444 fz(i,j) = 0
445 end if
446 end do
447 end do
448
449 ! truncate the matrices acording to input kut
450 k0 = lx-kutx
451 do k = k0+1, lx
452 kk = k+lx*(k-1)
453 fx(kk,1) = 0
454 end do
455 k0 = lx-kuty
456 do k = k0+1, lx
457 kk = k+lx*(k-1)
458 fy(kk,1) = 0
459 end do
460 k0 = lx-kutz
461 do k = k0+1, lx
462 kk = k+lx*(k-1)
463 fz(kk,1) = 0
464 end do
465
466 end subroutine build_filter_tf
467
468
469 function get_elem_l2norm(elemdata, coef, space, e) result(l2e)
470 type(coef_t), intent(in) :: coef
471 real(kind=rp) :: elemdata(coef%Xh%lx, coef%Xh%lx, coef%Xh%lx)
472 real(kind=rp) :: vole, suma, l2e
473 integer i, e, nxyz
474 character(len=4) :: space
475
476 ! Get the volume of the element
477 nxyz = coef%Xh%lx*coef%Xh%lx*coef%Xh%lx
478 vole=0
479 do i = 1, nxyz
480 vole = vole+coef%B(i,1,1,e)
481 end do
482
483 ! Get the weighted l2 norm of the element
484 suma = 0
485 if (space .eq. 'spec') then
486 do i = 1, nxyz
487 suma = suma+elemdata(i,1,1)*elemdata(i,1,1)*coef%jac(i,1,1,e)
488 end do
489 end if
490 if (space .eq. 'phys') then
491 do i = 1, nxyz
492 suma = suma+elemdata(i,1,1)*elemdata(i,1,1)*coef%B(i,1,1,e)
493 end do
494 end if
495
496 l2e = sqrt(suma)/sqrt(vole)
497
498 end function get_elem_l2norm
499
500
501end 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:405
real(kind=rp) function get_elem_l2norm(elemdata, coef, space, e)
Definition cpr.f90:470
subroutine cpr_truncate_wn(cpr, coef)
Truncate the frequencies.
Definition cpr.f90:265
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:378
subroutine cpr_goto_space(cpr, space)
Tranform to spectral space (using tensor product)
Definition cpr.f90:221
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:238
Defines a mesh.
Definition mesh.f90:34
Wrapper for all matrix-matrix product implementations.
subroutine, public mxm(a, n1, b, n2, c, n3)
Compute matrix-matrix product for contiguously packed matrices A,B, and C.
Build configurations.
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:55
include information needed for compressing fields
Definition cpr.f90:51
The function space for the SEM solution fields.
Definition space.f90:62