FE-Project
Loading...
Searching...
No Matches
scale_element_SIACfilter.F90
Go to the documentation of this file.
1!-------------------------------------------------------------------------------
2!> module FElib / Element/ SIAC filter
3!!
4!! @par Description
5!! A module to provide a Smoothness-Increasing Accuracy-Increasing (SIAC) filter
6!!
7!! @par Reference
8!! - Cockburn et al. 2003:
9!! Enhanced accuracy by post-processing for finite element methods for hyperbolic equations.
10!! Mathematics of Computation, 72(242), 577–506.
11!!
12!! @author Yuta Kawai, Team SCALE
13!<
14!-------------------------------------------------------------------------------
15#include "scaleFElib.h"
17 !-----------------------------------------------------------------------------
18 !
19 !++ Used modules
20 !
21 use scale_precision
22 use scale_io
23 use scale_prc
24 use scale_prof
25
26 use scale_element_base, only: &
28 use scale_element_line, only: &
30 !-----------------------------------------------------------------------------
31 implicit none
32 private
33 !-----------------------------------------------------------------------------
34 !
35 !++ Public procedures
36 !
37
38 !-----------------------------------------------------------------------------
39 !
40 !++ Public type
41 !
42 !> Derived type to provide a SIAC filter
43 type, public :: siac_filter
44 integer :: spline_ord
45 integer :: spline_num
46 integer :: spline_r
47
48 integer :: npts_per_elem !< Number of sampling points per element
49
50 integer :: kernelhalfw !< Half width of kernel function
51
52 integer :: nintglpt
53 real(rp), allocatable :: intrpmat(:,:,:,:)
54 real(rp), allocatable :: int_x(:)
55 real(rp), allocatable :: int_w(:)
56
57 real(rp), allocatable :: kernel_func_coef(:)
58 real(rp), allocatable :: kernel_func(:,:,:,:)
59
60 real(rp), allocatable :: x_pts_per_elem(:)
61 contains
62 procedure :: init => siac_filter_init
63 procedure :: final => siac_filter_final
64 procedure :: apply1d => siac_filter_apply1d
65 procedure :: get_kernel_func => siac_filter_get_kernel_func
66 end type siac_filter
67
68 !-----------------------------------------------------------------------------
69 !
70 !++ Private procedures & variables
71 !
72 !-------------------
73
74 private :: central_bspline
75
76contains
77!> Initialize a object for SIAC filter
78!!
79!! @param r the number of B-splines - 1
80!! @param l the order of B-spline
81!OCL SERIAL
82 subroutine siac_filter_init( this, &
83 r, l, &
84 x_pts_per_elem, elem1D )
85 use scale_polynomial, only: &
88 implicit none
89 class(siac_filter), intent(inout) :: this
90 integer, intent(in) :: r
91 integer, intent(in) :: l
92 real(RP), intent(in) :: x_pts_per_elem(:)
93 class(lineelement), intent(in) :: elem1D
94
95 integer :: i
96 integer :: p
97 integer :: m
98
99 real(RP), allocatable :: IntrpMat_dummy(:,:)
100 real(RP) :: x0, x1, x2
101 real(RP), allocatable :: int_x_tmp(:)
102
103 real(RP), allocatable :: P1D_ori(:,:)
104 !--------------------------------------
105
106 this%spline_r = r
107 this%spline_num = r + 1
108 this%spline_ord = l
109
110 this%KernelHalfW = ceiling(0.5_rp * real(r+l,kind=rp))
111
112 this%Npts_per_elem = size(x_pts_per_elem)
113
114 !---
115 allocate( this%x_pts_per_elem(this%Npts_per_elem) )
116 this%x_pts_per_elem(:) = x_pts_per_elem(:)
117
118 this%NintGLPt = ceiling( ( r + l ) / 2.0_rp )
119 allocate( intrpmat_dummy(this%NintGLPt,elem1d%Np) )
120 allocate( this%int_x(this%NintGLPt), this%int_w(this%NintGLPt) )
121
122 intrpmat_dummy(:,:) = elem1d%GenIntGaussLegendreIntrpMat( this%NintGLPt, this%int_w, this%int_x )
123
124 allocate( this%IntrpMat(this%NintGLPt,elem1d%Np,2,this%Npts_per_elem) )
125 allocate( int_x_tmp(this%NintGLPt) )
126 allocate( p1d_ori(this%NintGLPt,elem1d%Np) )
127 do i=1, this%Npts_per_elem
128 x0 = - 1.0_rp; x2 = 1.0_rp
129 x1 = x_pts_per_elem(i)
130
131 int_x_tmp(:) = x0 + 0.5_rp * (x1 - x0) * ( 1.0_rp + this%int_x(:) )
132 p1d_ori(:,:) = polynomial_genlegendrepoly( elem1d%PolyOrder, int_x_tmp(:) )
133 do p=1, elem1d%Np
134 p1d_ori(:,p) = p1d_ori(:,p) * sqrt(real(p-1,kind=rp) + 0.5_rp)
135 end do
136 this%IntrpMat(:,:,1,i) = matmul( p1d_ori, elem1d%invV )
137 ! this%IntrpMat(:,:,1,i) = Polynomial_GenLagrangePoly( elem1D%PolyOrder, elem1D%x1, int_x_tmp(:) )
138
139 int_x_tmp(:) = x1 + 0.5_rp * (x2 - x1) * ( 1.0_rp + this%int_x(:) )
140 p1d_ori(:,:) = polynomial_genlegendrepoly( elem1d%PolyOrder, int_x_tmp(:) )
141 do p=1, elem1d%Np
142 p1d_ori(:,p) = p1d_ori(:,p) * sqrt(real(p-1,kind=rp) + 0.5_rp)
143 end do
144 this%IntrpMat(:,:,2,i) = matmul( p1d_ori, elem1d%invV )
145 ! this%IntrpMat(:,:,2,i) = Polynomial_GenLagrangePoly( elem1D%PolyOrder, elem1D%x1, int_x_tmp(:) )
146 end do
147
148 !---
149 allocate( this%kernel_func_coef(0:r) )
150 call calculate_kernel_func_coef( this%kernel_func_coef, &
151 r, l, this%int_x, this%int_w, this%NintGLPt )
152
153 allocate( this%kernel_func(this%NintGLPt,2,-this%KernelHalfW:this%KernelHalfW,this%Npts_per_elem) )
154
155 do i=1, this%Npts_per_elem
156 call construct_kernel_func( this%kernel_func(:,:,:,i), &
157 r, l, this%kernel_func_coef, this%KernelHalfW, &
158 this%int_x, this%NintGLPt, x_pts_per_elem(i) )
159 end do
160
161 log_info("SIAC_filter_Init",*) "r, l=", r, l
162 log_info("SIAC_filter_Init",*) "KernelFunc coef:", this%kernel_func_coef
163 do i=1, this%Npts_per_elem
164 log_info("SIAC_filter_Init",*) "--- KernelFunc xi=", x_pts_per_elem(i)
165 do m=-this%KernelHalfW,this%KernelHalfW
166 log_info("SIAC_filter_Init",*) this%kernel_func(:,1,m,i), ":", this%kernel_func(:,2,m,i)
167 end do
168 end do
169
170 do i=1, this%Npts_per_elem
171 log_info("SIAC_filter_Init",*) "--- InterpMat xi=", x_pts_per_elem(i)
172 log_info("SIAC_filter_Init",*) "L", this%IntrpMat(1,:,1,i)
173 log_info("SIAC_filter_Init",*) "L", this%IntrpMat(2,:,1,i)
174 log_info("SIAC_filter_Init",*) "R", this%IntrpMat(1,:,2,i)
175 log_info("SIAC_filter_Init",*) "R", this%IntrpMat(2,:,2,i)
176 end do
177
178 return
179 end subroutine siac_filter_init
180
181!OCL SERIAL
182 subroutine siac_filter_final( this )
183 implicit none
184 class(siac_filter), intent(inout) :: this
185 !--------------------------------------
186
187 deallocate( this%IntrpMat, this%int_x, this%int_w )
188 deallocate( this%kernel_func )
189
190 deallocate( this%x_pts_per_elem )
191
192 return
193 end subroutine siac_filter_final
194
195!OCL SERIAL
196 subroutine siac_filter_apply1d( this, filtered_q, &
197 q, Np1D, Ne, Nmesh, NmeshHalo )
198 implicit none
199 class(siac_filter), intent(in) :: this
200 integer, intent(in) :: Np1D
201 integer, intent(in) :: Ne
202 integer, intent(in) :: Nmesh
203 integer, intent(in) :: NmeshHalo
204 real(RP), intent(out) :: filtered_q(this%Npts_per_elem,Ne)
205 real(RP), intent(in) :: q(Np1D,Ne*Nmesh)
206 !--------------------------------------------
207
208 call siac_filter_apply_core( filtered_q, &
209 q, np1d, ne, nmesh, nmeshhalo, this%Npts_per_elem, &
210 this%kernel_func, this%x_pts_per_elem, this%IntrpMat, this%int_w, &
211 this%KernelHalfW, this%NintGLPt )
212
213 return
214 end subroutine siac_filter_apply1d
215
216!OCL SERIAL
217 subroutine siac_filter_apply_core( filtered_q, &
218 q, Np1D, Ne, Nmesh, NmeshHalo, Npts_per_elem, &
219 kernel_func, xi, IntrpMat, int_w, HalfW, NintGLPt )
220 implicit none
221 integer, intent(in) :: Np1D
222 integer, intent(in) :: Ne
223 integer, intent(in) :: Nmesh
224 integer, intent(in) :: NmeshHalo
225 integer, intent(in) :: Npts_per_elem
226 integer, intent(in) :: HalfW
227 integer, intent(in) :: NintGLpt
228 real(RP), intent(out) :: filtered_q(Npts_per_elem,Ne)
229 real(RP), intent(in) :: q(Np1D,Ne*Nmesh)
230 real(RP), intent(in) :: kernel_func(NintGLpt,2,-HalfW:HalfW,Npts_per_elem)
231 real(RP), intent(in) :: xi(Npts_per_elem)
232 real(RP), intent(in) :: IntrpMat(NintGLpt,Np1D,2,Npts_per_elem)
233 real(RP), intent(in) :: int_w(NintGLpt)
234
235 integer :: p
236 integer :: m
237
238 integer :: ke_os
239 integer :: ke, kee
240
241 real(RP) :: q_intrp(NintGLpt,2)
242 real(RP) :: int_w2(NintGLpt,2)
243 real(RP) :: tmp
244 !--------------------------------------------
245
246 ke_os = ne * nmeshhalo
247 !$omp parallel do collapse(2) private(kee, tmp, m, q_intrp, int_w2)
248 do ke=1, ne
249 do p=1, npts_per_elem
250 kee = ke + ke_os
251 tmp = 0.0_rp
252
253 int_w2(:,1) = ( xi(p) + 1.0_rp ) * int_w(:)
254 int_w2(:,2) = ( 1.0_rp - xi(p) ) * int_w(:)
255 do m=-halfw, halfw
256 q_intrp(:,1) = matmul( intrpmat(:,:,1,p), q(:,kee+m) )
257 q_intrp(:,2) = matmul( intrpmat(:,:,2,p), q(:,kee+m) )
258 tmp = tmp + sum( int_w2(:,:) * q_intrp(:,:) * kernel_func(:,:,m,p) )
259 end do
260 filtered_q(p,ke) = tmp * 0.25_rp
261 end do
262 end do
263
264 return
265 end subroutine siac_filter_apply_core
266
267!OCL SERIAL
268 subroutine siac_filter_get_kernel_func( this, kernel_func, Np, &
269 x )
270 implicit none
271 class(siac_filter), intent(in) :: this
272 integer, intent(in) :: Np
273 real(RP), intent(in) :: x(Np)
274 real(RP), intent(out) :: kernel_func(Np)
275
276 integer :: i
277 integer :: gam
278 real(RP) :: kernel_func_tmp
279 real(RP) :: x_gam
280 real(RP) :: psi
281 !--------------------------------------
282
283 do i=1, np
284 kernel_func_tmp = 0.0_rp
285 do gam=0, this%spline_r
286 x_gam = - 0.5_rp * real(this%spline_r, kind=rp) + gam
287
288 psi = central_bspline(x(i) - x_gam, this%spline_ord)
289 kernel_func_tmp = kernel_func_tmp + psi * this%kernel_func_coef(gam)
290 end do
291 kernel_func(i) = kernel_func_tmp
292 end do
293 return
294 end subroutine siac_filter_get_kernel_func
295
296!-- private --
297!OCL SERAIL
298 subroutine construct_kernel_func( kernel_func, &
299 r, l, kernel_coef, halfW, int_xi, NintPts, xi )
301 implicit none
302 integer, intent(in) :: halfW
303 integer, intent(in) :: NintPts
304 real(RP), intent(out) :: kernel_func(NintPts,2,-halfW:halfW)
305 integer, intent(in) :: r
306 integer, intent(in) :: l !< l=k+1
307 real(RP), intent(in) :: kernel_coef(0:r)
308 real(RP), intent(in) :: int_xi(NintPts)
309 real(RP), intent(in ):: xi
310
311 real(RP) :: x_gam
312 integer :: gam
313
314 real(RP) :: psi(NintPts,2)
315 real(RP) :: y1, y2
316
317 integer :: i
318 integer :: m
319
320 real(RP) :: kernel_func_tmp(NintPts,2)
321 real(RP) :: x0, x1, x2
322 !--------------------------------------------------------
323
324 do i=-halfw, halfw
325 kernel_func_tmp(:,:) = 0.0_rp
326 do gam=0, r
327 x_gam = - 0.5_rp * real(r, kind=rp) + gam
328 do m=1, nintpts
329 x0 = i - 0.5_rp; x2 = i + 0.5_rp
330 x1 = x0 + 0.5_rp * ( xi + 1.0_rp )
331
332 y1 = x0 + 0.5_rp * ( ( x1 - x0 ) * ( int_xi(m) + 1.0_rp ) - xi ) &
333 - x_gam
334 y2 = x1 + 0.5_rp * ( ( x2 - x1 ) * ( int_xi(m) + 1.0_rp ) - xi ) &
335 - x_gam
336 psi(m,1) = central_bspline(y1,l)
337 psi(m,2) = central_bspline(y2,l)
338 end do
339 kernel_func_tmp(:,:) = kernel_func_tmp(:,:) + kernel_coef(gam) * psi(:,:)
340 end do
341 kernel_func(:,:,i) = kernel_func_tmp(:,:)
342 end do
343 return
344 end subroutine construct_kernel_func
345
346!OCL SERAIL
347 subroutine calculate_kernel_func_coef( coef, &
348 r, l, int_xi, int_w, NintPts )
351 implicit none
352 integer, intent(in) :: r
353 integer, intent(in) :: l !< l=k+1
354 integer, intent(in) :: NintPts
355 real(RP), intent(in) :: int_xi(NintPts)
356 real(RP), intent(in) :: int_w(NintPts)
357 real(RP), intent(out) :: coef(0:r)
358 real(RP) :: gam
359 real(RP) :: x_gam
360
361 integer :: i, j
362 integer :: ii, jj
363 integer :: m, mm
364
365 real(RP) :: LinMat(0:r,0:r)
366 real(RP) :: b(0:r)
367 real(RP) :: coef_(0:r)
368
369 real(RP) :: x_knots(0:l)
370 real(RP) :: x0, x1
371
372 real(RP) :: x_intrp(NintPts)
373 real(RP) :: psi(NintPts)
374
375 real(RP) :: int_tmp
376 real(RP) :: int_w2(NintPts)
377 real(RP) :: int_coef
378
379 real(RP) :: P(NintPts,0:r)
380 real(RP) :: zero(1)
381 real(RP) :: P_x0(1,0:r)
382
383 real(RP) :: scale_s(0:r)
384 real(RP) :: scale_r(0:r)
385 !---------------------------------------------
386
387 do i=0, l
388 x_knots(i) = - 0.5_rp * real(l, kind=rp) + real(i, kind=rp)
389 end do
390 !$omp parallel do collapse(2) private(i, ii, j, jj, &
391 !$omp gam, x_gam, m, int_tmp, x0, x1, int_coef, x_intrp, int_w2, mm, psi, P)
392 do jj=0, r
393 do ii=0, r
394 i = ii; j = jj
395 gam = j
396 x_gam = - 0.5_rp * real(r, kind=rp) + gam
397
398 int_tmp = 0.0_rp
399 do m=0, l-1
400 x0 = x_knots(m); x1 = x_knots(m+1)
401 int_coef = 0.5_rp * ( x1 - x0 )
402
403 x_intrp(:) = x0 + int_coef * ( 1.0_rp + int_xi(:) )
404 int_w2(:) = int_coef * int_w(:)
405
406 do mm=1, nintpts
407 psi(mm) = central_bspline( x_intrp(mm), l )
408 end do
409
410 ! int_tmp = int_tmp &
411 ! + sum( int_w2(:) * psi(:) * ( x_intrp(:) - x_gam )**i )
412 p(:,0:i) = polynomial_genlegendrepoly( i, x_intrp(:) - x_gam )
413 int_tmp = int_tmp &
414 + sum( int_w2(:) * psi(:) * p(:,i) )
415
416 ! if (i==1) then
417 ! LOG_INFO("SIAC_filter_calc_coef",*) m, x0, x1, "Psi: ", psi(:)
418 ! LOG_INFO("SIAC_filter_calc_coef",*) m, x0, x1, "x+x_gam: ", x_intrp(:) + x_gam
419 ! end if
420 end do
421 linmat(ii,jj) = int_tmp
422 end do
423 end do
424
425 ! do i=0, r
426 ! LOG_INFO("SIAC_filter_calc_coef",*) "LinMat: ", LinMat(i,:)
427 ! end do
428
429 ! b(:) = 0.0_RP
430 ! b(0) = 1.0_RP
431 zero(:) = 0.0_rp
432 p_x0(:,:) = polynomial_genlegendrepoly( r, zero(:) )
433 b(:) = p_x0(1,:)
434
435 do j=0, r
436 scale_s(j) = sqrt(sum(linmat(:,j)**2))
437 if ( scale_s(j) /= 0.0_rp ) then
438 linmat(:,j) = linmat(:,j) / scale_s(j)
439 end if
440 end do
441 do i=0, r
442 scale_r(i) = sqrt(sum(linmat(i,:)**2))
443 if ( scale_r(i) /= 0.0_rp ) then
444 linmat(i,:) = linmat(i,:) / scale_r(i)
445 b(i) = b(i) / scale_r(i)
446 end if
447 end do
448 call linalgebra_solvelineq( linmat, b, coef_ )
449 do j=0, r
450 coef(j) = coef_(j) / scale_s(j)
451 end do
452
453 return
454 end subroutine calculate_kernel_func_coef
455
456!OCL SERIAL
457 recursive function central_bspline( x, k ) result(b)
458 implicit none
459 real(RP), intent(in) :: x
460 integer, intent(in) :: k
461 real(RP) :: b
462
463 real(RP) :: coef1, coef2
464 !--------------------------------------
465
466 if ( k==1 ) then
467 if ( - 0.5_rp < x .and. x <= 0.5_rp ) then
468 b = 1.0_rp
469 else
470 b = 0.0_rp
471 end if
472 else
473 coef1 = central_bspline( x + 0.5_rp, k-1 )
474 coef2 = central_bspline( x - 0.5_rp, k-1 )
475 b = ( ( 0.5_rp * k + x ) * coef1 &
476 + ( 0.5_rp * k - x ) * coef2 ) / real(k-1, kind=rp)
477 end if
478 return
479 end function central_bspline
Solve a linear equation Ax=b using a direct solver.
module FElib / Element / Base
module FElib / Element / line
module FElib / Element/ SIAC filter
subroutine siac_filter_init(this, r, l, x_pts_per_elem, elem1d)
Initialize a object for SIAC filter.
Module common / Linear algebra.
Module common / Polynomial.
real(rp) function, dimension(size(x), nord+1), public polynomial_genlegendrepoly(nord, x)
A function to obtain the values of Legendre polynomials which are evaluated at arbitrary points.
real(rp) function, dimension(size(x), nord+1), public polynomial_genlagrangepoly(nord, x_lgl, x)
A function to obtain the Lagrange basis functions related to the Gauss-Legendre-Lobatto (GLL) points.
Derived type representing a 1D reference element.
Derived type representing a line element.
Derived type to provide a SIAC filter.