-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumerics.f90
135 lines (126 loc) · 3.97 KB
/
numerics.f90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
subroutine fullOrder(r,s,p,k)
implicit none
integer, intent(in) :: r,s,p
integer, intent(out) :: k
integer :: sp
k = r + 1
do sp = 0, s-1
k = k + (p + 1 - sp)
enddo
end subroutine fullOrder
subroutine triLagrange2D(p,C)
implicit none
integer, intent(in) :: p
integer :: i,ix,iy,k,s,r,N
real(8), dimension((p+1)*(p+2)/2,(p+1)*(p+2)/2) :: A,C
real(8), dimension(p+1) :: xi, eta
N = (p+1)*(p+2)/2
xi = (/(i, i=0,p+1,1)/)
xi = xi/p
eta = xi
A = 0.d0
C = A
i = 1
do iy = 0, p
do ix = 0, p-iy
k = 1
do s = 0, p
do r = 0, p-s
A(i,k) = xi(ix+1)**r * eta(iy+1)**s
k = k+1
enddo
enddo
i = i + 1
enddo
enddo
call matInv(N,A,C)
end subroutine triLagrange2D
subroutine basis2D(xy, p, phi, n_xy)
implicit none
! evaluates 2D basis functions at xy
integer, intent(in) :: n_xy, p
real(8), intent(in), dimension(n_xy,2) :: xy
real(8), intent(out), dimension(n_xy,(p+1)*(p+2)/2) :: phi
!f2py intent(in) xy
!f2py intent(out) phi
integer :: s, r, k, j, i_xy
real(8), dimension((p+1)*(p+2)/2,(p+1)*(p+2)/2) :: C
call triLagrange2D(p,C)
phi(:,:) = 0.d0
do j = 1,(p+1)*(p+2)/2
do s = 0, p
do r = 0, p-s
call fullOrder(r,s,p,k)
do i_xy = 1,n_xy
phi(i_xy,j) = phi(i_xy,j) + C(k,j) * xy(i_xy,1)**r * xy(i_xy,2)**s
enddo
enddo
enddo
enddo
end subroutine basis2D
subroutine gbasis2D(xy, p, gphi, n_xy)
implicit none
! evaluates gradient of 2D basis functions at xy
integer, intent(in) :: n_xy, p
real(8), intent(in), dimension(n_xy,2) :: xy
real(8), intent(out), dimension(n_xy,(p+1)*(p+2)/2,2) :: gphi
!f2py intent(in) xy
!f2py intent(out) gphi
integer :: s, r, k, j, i_xy
real(8), dimension((p+1)*(p+2)/2,(p+1)*(p+2)/2) :: C
call triLagrange2D(p,C)
gphi(:,:,:) = 0.d0
do j = 1, (p+1)*(p+2)/2
do s = 0, p
do r = 0, p-s
call fullOrder(r,s,p,k)
do i_xy = 1,n_xy
gphi(i_xy,j,1) = gphi(i_xy,j,1) + r * C(k,j) * xy(i_xy,1)**(r-1) * xy(i_xy,2)**s
gphi(i_xy,j,2) = gphi(i_xy,j,2) + s * C(k,j) * xy(i_xy,1)**r * xy(i_xy,2)**(s-1)
if (gphi(i_xy,j,1) /= gphi(i_xy,j,1)) then ! Needed for 0/0 errors? Not really sure
gphi(i_xy,j,1) = 0.d0 ! TODO: make this more efficient, check at end
endif
if (gphi(i_xy,j,2) /= gphi(i_xy,j,2)) then
gphi(i_xy,j,2) = 0.d0
endif
enddo
enddo
enddo
enddo
end subroutine gbasis2D
subroutine matInv(n,A,Ainv)
! -----------------------------------------------------------------------
! Purpose: Calculates the matrix inverse of A using LAPACK's LU factorization
!
! Inputs:
! n = the size of the system
! A[n,n] = the matrix to be inverted
!
! Outs:
! Ainv[n,n] = the inverse of matrix A
! -----------------------------------------------------------------------
implicit none
integer, intent(in) :: n
real(8), intent(in),dimension(n,n) :: A
real(8), intent(out),dimension(n,n) :: Ainv
!f2py intent(in) n, A
!f2py intent(out) Ainv
real(8), dimension(n) :: work
real(8), dimension(n,n) :: LU
integer :: info
integer, dimension(n) :: ipiv
LU = A
call DGETRF(n,n,LU,n,ipiv,info)
Ainv = LU
call DGETRI(n,Ainv,n,ipiv,work,n,info)
end subroutine matInv
subroutine solveLinSys(A,x,b,n)
implicit none
real(8), intent(in), dimension(n,n) :: A
real(8), intent(in), dimension(n) :: b
real(8), intent(out), dimension(n) :: x
integer, intent(in) :: n
integer :: ipiv,info
call DGESV(n,1,A,n,ipiv,b,n,info)
x = b
end subroutine solveLinSys