Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_poisson_2d_fem.F90
Go to the documentation of this file.
1 
9 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
12 #include "sll_poisson_solvers_macros.h"
13 
14  implicit none
15 
16  public :: &
17  sll_o_create, &
20 
21  private
22 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 
31  sll_real64, dimension(:, :), pointer :: a
32  sll_real64, dimension(:, :), pointer :: m
33  sll_real64, dimension(:, :), pointer :: mat
34  sll_real64, dimension(:), pointer :: hx
35  sll_real64, dimension(:), pointer :: hy
36  sll_int32 :: nx
37  sll_int32 :: ny
38  sll_int32 :: nd
39  sll_int32, dimension(:), pointer :: id
40  sll_real64, dimension(:), pointer :: xd
41  sll_real64, dimension(:), pointer :: yd
42  end type sll_t_poisson_2d_fem
43 
45  interface sll_o_create
46  module procedure initialize_poisson_2d_fem
47  end interface sll_o_create
48 
50  interface sll_o_solve
51  module procedure solve_poisson_2d_fem
52  end interface sll_o_solve
53 
54 contains
55 
57  subroutine initialize_poisson_2d_fem(self, x, y, nn_x, nn_y)
58 
59  type(sll_t_poisson_2d_fem) :: self
60  sll_int32, intent(in) :: nn_x
61  sll_int32, intent(in) :: nn_y
62  sll_real64, dimension(nn_x) :: x
63  sll_real64, dimension(nn_y) :: y
64  sll_int32 :: ii
65  sll_int32 :: jj
66 
67  sll_real64, dimension(4, 4) :: axelem
68  sll_real64, dimension(4, 4) :: ayelem
69  sll_real64, dimension(4, 4) :: mmelem
70  sll_real64, dimension(2, 2) :: mfelem
71  sll_int32, dimension(4) :: isom
72  sll_int32 :: i
73  sll_int32 :: j
74  sll_int32 :: k
75  sll_int32 :: nx
76  sll_int32 :: ny
77  sll_int32 :: error
78 
79  sll_int32 :: kd
80  sll_int32 :: nd
81  sll_int32 :: n
82 
83  self%nx = nn_x - 1
84  self%ny = nn_y - 1
85 
86  nx = self%nx
87  ny = self%ny
88 
89  sll_allocate(self%hx(1:nx), error)
90  sll_allocate(self%hy(1:ny), error)
91  sll_allocate(self%A((nx + 1)*(ny + 1), (nx + 1)*(ny + 1)), error)
92  sll_allocate(self%M((nx + 1)*(ny + 1), (nx + 1)*(ny + 1)), error)
93 
94  do i = 1, nx
95  self%hx(i) = x(i + 1) - x(i)
96  end do
97 
98  do j = 1, ny
99  self%hy(j) = y(j + 1) - y(j)
100  end do
101 
102 !** Construction des matrices elementaires
103  axelem(1, :) = [2.0_f64, -2.0_f64, -1.0_f64, 1.0_f64]
104  axelem(2, :) = [-2.0_f64, 2.0_f64, 1.0_f64, -1.0_f64]
105  axelem(3, :) = [-1.0_f64, 1.0_f64, 2.0_f64, -2.0_f64]
106  axelem(4, :) = [1.0_f64, -1.0_f64, -2.0_f64, 2.0_f64]
107 
108  axelem = axelem/6.0_f64
109 
110  ayelem(1, :) = [2.0_f64, 1.0_f64, -1.0_f64, -2.0_f64]
111  ayelem(2, :) = [1.0_f64, 2.0_f64, -2.0_f64, -1.0_f64]
112  ayelem(3, :) = [-1.0_f64, -2.0_f64, 2.0_f64, 1.0_f64]
113  ayelem(4, :) = [-2.0_f64, -1.0_f64, 1.0_f64, 2.0_f64]
114 
115  ayelem = ayelem/6.0_f64
116 
117  mmelem(1, :) = [4.0_f64, 2.0_f64, 1.0_f64, 2.0_f64]
118  mmelem(2, :) = [2.0_f64, 4.0_f64, 2.0_f64, 1.0_f64]
119  mmelem(3, :) = [1.0_f64, 2.0_f64, 4.0_f64, 2.0_f64]
120  mmelem(4, :) = [2.0_f64, 1.0_f64, 2.0_f64, 4.0_f64]
121 
122  mmelem = mmelem/36.0_f64
123 
124  mfelem(1, :) = [2.0_f64, 1.0_f64]
125  mfelem(2, :) = [1.0_f64, 2.0_f64]
126 
127  mfelem = mfelem/6.0_f64
128 
129  self%A = 0.0_f64
130  self%M = 0.0_f64
131 
132 !*** Interior mesh ***
133  do i = 1, nx
134  do j = 1, ny
135  isom(1) = som(self%nx, i, j, 1)
136  isom(2) = som(self%nx, i, j, 2)
137  isom(3) = som(self%nx, i, j, 3)
138  isom(4) = som(self%nx, i, j, 4)
139  do ii = 1, 4
140  do jj = 1, 4
141  self%A(isom(ii), isom(jj)) = self%A(isom(ii), isom(jj)) &
142  & + axelem(ii, jj)*self%hy(j)/self%hx(i) &
143  & + ayelem(ii, jj)*self%hx(i)/self%hy(j)
144  self%M(isom(ii), isom(jj)) = self%M(isom(ii), isom(jj)) &
145  & + mmelem(ii, jj)*self%hy(j)*self%hx(i)
146  end do
147  end do
148  end do
149  end do
150 
151 !Set nodes dirichlet boundary conditions
152  self%nd = 2*(nx + ny)
153  allocate (self%id(self%nd))
154  nd = 0
155  do i = 1, nx
156  k = i
157  nd = nd + 1
158  self%id(nd) = k
159  k = (nx + 1)*(ny + 1) - i + 1
160  nd = nd + 1
161  self%id(nd) = k
162  end do
163  do i = nx + 1, nx*(ny + 1), nx + 1
164  k = i
165  nd = nd + 1
166  self%id(nd) = k
167  k = i + 1
168  nd = nd + 1
169  self%id(nd) = k
170  end do
171 
172  do i = 1, self%nd
173  k = self%id(i)
174  self%A(k, k) = 1d20
175  end do
176 
177  kd = nx + 2
178  sll_allocate(self%mat(kd + 1, (nx + 1)*(ny + 1)), error)
179  self%mat = 0.0_f64
180  n = (nx + 1)*(ny + 1)
181  do i = 1, n
182  do j = i, min(n, i + kd)
183  self%mat(kd + 1 + i - j, j) = self%a(i, j)
184  end do
185  end do
186 
187  call dpbtrf('U', (nx + 1)*(ny + 1), kd, self%mat, kd + 1, error)
188 
189  allocate (self%xd((nx + 1)*(ny + 1)))
190  allocate (self%yd((nx + 1)*(ny + 1)))
191 
192  k = 0
193  do j = 1, ny + 1
194  do i = 1, nx + 1
195  k = k + 1
196  self%xd(k) = x(i)
197  self%yd(k) = y(j)
198  end do
199  end do
200 
201  end subroutine initialize_poisson_2d_fem
202 
204  integer function som(nx, i, j, k)
205 
206  integer :: i, j, k, nx
207 
208  if (k == 1) then
209  som = i + (j - 1)*(nx + 1)
210  else if (k == 2) then
211  som = i + (j - 1)*(nx + 1) + 1
212  else if (k == 3) then
213  som = i + (j - 1)*(nx + 1) + nx + 2
214  else if (k == 4) then
215  som = i + (j - 1)*(nx + 1) + nx + 1
216  end if
217 
218  end function som
219 
221  subroutine solve_poisson_2d_fem(self, ex, ey, rho)
222  type(sll_t_poisson_2d_fem) :: self
223  sll_real64, dimension(:, :) :: ex
224  sll_real64, dimension(:, :) :: ey
225  sll_real64, dimension(:, :) :: rho
226  sll_real64, dimension((self%nx + 1)*(self%ny + 1)) :: b
227 
228  sll_int32 :: nx
229  sll_int32 :: ny
230  sll_int32 :: i, j, k
231  sll_int32 :: error
232 
233  nx = self%nx
234  ny = self%ny
235 
236  k = 0
237  do j = 1, ny + 1
238  do i = 1, nx + 1
239  k = k + 1
240  b(k) = rho(i, j)
241  end do
242  end do
243 
244  b = matmul(self%M, b)
245 
246  do i = 1, self%nd
247  k = self%id(i)
248  b(k) = 1.0d20*(self%xd(k)*self%xd(k) + self%yd(k)*self%yd(k))
249  end do
250 
251  call dpbtrs('U', (nx + 1)*(ny + 1), nx + 2, 1, self%mat, nx + 3, b, (nx + 1)*(ny + 1), error)
252 
253  rho = 0.0_8
254  k = 0
255  do j = 1, ny + 1
256  do i = 1, nx + 1
257  k = k + 1
258  rho(i, j) = b(k)
259  end do
260  end do
261 
262  do j = 1, ny + 1
263  do i = 1, nx
264  ex(i, j) = -(rho(i + 1, j) - rho(i, j))/self%hx(i)
265  end do
266  end do
267 
268  do j = 1, ny
269  do i = 1, nx + 1
270  ey(i, j) = -(rho(i, j + 1) - rho(i, j))/self%hy(j)
271  end do
272  end do
273 
274  end subroutine solve_poisson_2d_fem
275 
276 end module sll_m_poisson_2d_fem
Compute the electric potential.
Poisson solver using finite element.
integer function som(nx, i, j, k)
Get the node index.
subroutine initialize_poisson_2d_fem(self, x, y, nn_x, nn_y)
Initialize Poisson solver object using finite elements method.
subroutine solve_poisson_2d_fem(self, ex, ey, rho)
Solve the poisson equation.
Structure to solve Poisson equation on 2d domain. Mesh is cartesian and could be irregular.
    Report Typos and Errors