!>
!> @file conmat.tpl
!>
!> @brief
!>
!> @copyright
!> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne)
!> SPC (Swiss Plasma Center)
!>
!> SPClibs is free software: you can redistribute it and/or modify it under
!> the terms of the GNU Lesser General Public License as published by the Free
!> Software Foundation, either version 3 of the License, or (at your option)
!> any later version.
!>
!> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY
!> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
!> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!>
!> You should have received a copy of the GNU Lesser General Public License
!> along with this program. If not, see .
!>
!> @authors
!> (in alphabetical order)
!> @author Trach-Minh Tran
!>
!
! In this version s[lines are precalculted
! (on all n1/n2 intervals
!
INTERFACE
SUBROUTINE coefeq(x, y, idt, idw, c)
DOUBLE PRECISION, INTENT(in) :: x, y
INTEGER, INTENT(out) :: idt(:,:), idw(:,:)
DOUBLE PRECISION, INTENT(out) :: c(:)
END SUBROUTINE coefeq
END INTERFACE
INTEGER, OPTIONAL :: maxder(2) ! maximum oder of derivatives
LOGICAL, OPTIONAL :: nat_order ! Natural ordering for 2d-1d mapping
!
INTEGER :: n1, nidbas1, ndim1, n1e
INTEGER :: n2, nidbas2, ndim2, n2e
INTEGER :: ng1, ng2
INTEGER :: i1, i2, ig1, ig2
INTEGER :: igt1, igt2, igw1, igw2, irow, jcol
INTEGER, ALLOCATABLE :: left1(:), left2(:)
!
LOGICAL :: nlper1, nlper2, nlnat
!
INTEGER :: kterms ! Number of terms in weak form
INTEGER :: k, kmaxder, it1, iw1, it2, iw2
INTEGER, ALLOCATABLE :: idert(:,:), iderw(:,:) ! Derivative order
DOUBLE PRECISION, ALLOCATABLE :: coefs(:,:,:) ! Terms in weak form
!
DOUBLE PRECISION, POINTER :: xg1(:,:), xg2(:,:), wg1(:,:), wg2(:,:)
DOUBLE PRECISION, ALLOCATABLE :: fun1(:,:,:,:), fun2(:,:,:,:)
DOUBLE PRECISION, ALLOCATABLE :: mata(:,:,:,:), matc(:,:)
DOUBLE PRECISION, ALLOCATABLE :: matg(:,:,:), matf(:,:,:), matcg(:,:,:)
!===========================================================================
! 1.0 Prologue
!
! Properties of spline space
!
CALL get_dim(spl%sp1, ndim1, n1, nidbas1)
CALL get_dim(spl%sp2, ndim2, n2, nidbas2)
nlper1 = spl%sp1%period
nlper2 = spl%sp2%period
!
n1e = n1+nidbas1 ! Number of elements in 1st coordinate
n2e = n2+nidbas2 ! Number of elements in 2nd coordinate
iF(nlper2) n2e = n2
!
! Gauss points and weights on all intervals
!
xg1 => spl%sp1%gausx ! xg1(ng1,n1)
wg1 => spl%sp1%gausw ! wg1(ng1,n1)
ng1 = SIZE(xg1,1)
xg2 => spl%sp2%gausx
wg2 => spl%sp2%gausw
ng2 = SIZE(xg2,1)
!
! Splines on all intervals
!
kmaxder = 1
IF(PRESENT(maxder)) kmaxder = maxder(1)
ALLOCATE(fun1(0:nidbas1,0:kmaxder,ng1,n1))
ALLOCATE(left1(ng1))
DO i1=1,n1
left1 = i1
CALL basfun(xg1(:,i1), spl%sp1, fun1(:,:,:,i1), left1)
END DO
DEALLOCATE(left1)
!
kmaxder = 1
IF(PRESENT(maxder)) kmaxder = maxder(2)
ALLOCATE(fun2(0:nidbas2,0:kmaxder,ng2,n2))
ALLOCATE(left2(ng2))
DO i2=1,n2
left2 = i2
CALL basfun(xg2(:,i2), spl%sp2, fun2(:,:,:,i2), left2)
END DO
DEALLOCATE(left2)
!
! Ordering in local to global matrix mapping
!
nlnat = .FALSE.
IF(PRESENT(nat_order)) nlnat = nat_order
!===========================================================================
! 2.0 Assembly loop
!
! Weak form
!
kterms = mat%nterms
ALLOCATE(idert(kterms,2))
ALLOCATE(iderw(kterms,2))
ALLOCATE(coefs(kterms,ng1,ng2))
!
! Allocate local matrices
!
ALLOCATE(mata(0:nidbas1,0:nidbas1,0:nidbas2,0:nidbas2))
ALLOCATE(matc(ng1,ng2))
ALLOCATE(matg(0:nidbas2,0:nidbas2,ng2))
ALLOCATE(matf(0:nidbas1,0:nidbas1,ng1))
ALLOCATE(matcg(ng1,0:nidbas2,0:nidbas2))
!
DO i1=1,n1
DO i2=1,n2
!
! Coefficients of the weak form
!
DO ig1=1,ng1
DO ig2=1,ng2
CALL coefeq(xg1(ig1,i1), xg2(ig2,i2), &
& idert, iderw, coefs(:,ig1,ig2))
END DO
END DO
!
! Compute local matrix: A <- E*(C*D^T) + A
!
mata = 0.0d0
DO k=1,kterms
!
matc(1:ng1,1:ng2) = coefs(k,1:ng1,1:ng2)
!
DO it1=0,nidbas1
DO iw1=0,nidbas1
DO ig1=1,ng1
matf(it1,iw1,ig1) = wg1(ig1,i1) * &
& fun1(it1,idert(k,1),ig1,i1) * &
& fun1(iw1,iderw(k,1),ig1,i1)
END DO
END DO
END DO
!
DO it2=0,nidbas2
DO iw2=0,nidbas2
DO ig2=1,ng2
matg(it2,iw2,ig2) = wg2(ig2,i2) * &
& fun2(it2,idert(k,2),ig2,i2) * &
& fun2(iw2,iderw(k,2),ig2,i2)
END DO
END DO
END DO
!
CALL dgemm('N', 'T', ng1, (nidbas2+1)*(nidbas2+1), ng2, 1.0d0, &
& matc, ng1, matg, (nidbas2+1)*(nidbas2+1), 0.0d0, &
& matcg, ng1)
CALL dgemm('N', 'N', (nidbas1+1)*(nidbas1+1), (nidbas2+1)*(nidbas2+1), &
& ng1, 1.0d0, matf, (nidbas1+1)*(nidbas1+1), matcg, ng1, 1.0d0, &
& mata, (nidbas1+1)*(nidbas1+1))
!
END DO
!
! Map local matrix A to global matrix
!
DO it1=0,nidbas1
igt1 = i1+it1; IF(nlper1) igt1 = MODULO(igt1-1,n1) + 1
DO it2=0,nidbas2
igt2 = i2+it2; IF(nlper2) igt2 = MODULO(igt2-1, n2) + 1
irow = glmap(igt1, igt2, n1e, n2e)
DO iw1=0,nidbas1
igw1 = i1+iw1; IF(nlper1) igw1 = MODULO(igw1-1,n1) + 1
DO iw2=0,nidbas2
igw2 = i2+iw2; IF(nlper2) igw2 = MODULO(igw2-1, n2) + 1
jcol = glmap(igw1, igw2, n1e, n2e)
CALL updtmat(mat, irow, jcol, mata(it1,iw1,it2,iw2))
END DO
END DO
END DO
END DO
!
END DO
END DO
!===========================================================================
! 9.0 Epilogue
!
DEALLOCATE(fun1)
DEALLOCATE(fun2)
DEALLOCATE(idert, iderw, coefs)
DEALLOCATE(mata)
DEALLOCATE(matc)
DEALLOCATE(matg)
DEALLOCATE(matcg)
DEALLOCATE(matf)
!
CONTAINS
INTEGER FUNCTION glmap(i,j,n1,n2)
INTEGER, INTENT(in) :: i,j,n1,n2
IF(nlnat) THEN
glmap = (j-1)*n1 + i
ELSE
glmap = (i-1)*n2 + j
END IF
END FUNCTION glmap