Octopus
stencil_stargeneral.F90
Go to the documentation of this file.
1!! Copyright (C) 2016 U. De Giovannini, H Huebener; 2019 N. Tancogne-Dejean
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
28 use debug_oct_m
29 use global_oct_m
30 use, intrinsic :: iso_fortran_env
31 use math_oct_m
34
35 implicit none
36
37 private
38 public :: &
44
45
46
47contains
48
49 ! ---------------------------------------------------------
52 subroutine stencil_stargeneral_get_arms(this, dim, coord_system)
53 type(stencil_t), intent(inout) :: this
54 integer, intent(in) :: dim
55 class(coordinate_system_t), intent(in) :: coord_system
56
57 real(real64) :: theta(dim), basis_vectors(dim, dim)
58 integer :: arm(dim)
59 integer :: ii, jj, kk
60 real(real64) :: norm, min_norm(dim)
61
62 real(real64), parameter :: tol = 1e-14_real64
63
65
66 assert(dim <= 3)
67
68 this%stargeneral%narms = 0
69 this%stargeneral%arms = 0
70
71 if (dim == 1) then
72 !we are done
74 return
75 end if
76
77 select type (coord_system)
78 class is (affine_coordinates_t)
79 basis_vectors = coord_system%basis%vectors
80 class default
81 message(1) = "Stencil stargeneral can currently only be used with affine coordinate systems."
82 call messages_fatal(1)
83 end select
84
85 if (dim == 2) then
86 !get the angle between the primitive vectors
87 theta(1) = acos(clamp(dot_product(basis_vectors(:, 1), basis_vectors(:, 2)), -m_one, m_one))
88
89 if (theta(1) < m_pi*m_half) then
90 this%stargeneral%narms = this%stargeneral%narms + 1
91 arm = (/1,-1/)
92 this%stargeneral%arms(this%stargeneral%narms, 1:dim) = arm
93 else if (theta(1) > m_pi*m_half) then
94 this%stargeneral%narms = this%stargeneral%narms + 1
95 arm = (/1,+1/)
96 this%stargeneral%arms(this%stargeneral%narms, 1:dim) = arm
97 end if
98 !if theta == pi/2 we do not need additional arms
99
100 ! NB: you have supposed the axis of the 2D system is along z.
101 !we are done
103 return
104 end if
105
106 ! dim>2
107
108 !We first count how many arms we need
109 theta(1) = acos(clamp(dot_product(basis_vectors(:, 1), basis_vectors(:, 2)), -m_one, m_one))
110 if (abs(theta(1) - m_pi*m_half) > 1e-8_real64) this%stargeneral%narms = this%stargeneral%narms + 1
111
112 theta(2) = acos(clamp(dot_product(basis_vectors(:, 2), basis_vectors(:, 3)), -m_one, m_one))
113 if (abs(theta(2)-m_pi*m_half) > 1e-8_real64) this%stargeneral%narms = this%stargeneral%narms + 1
114
115 theta(3) = acos(clamp(dot_product(basis_vectors(:, 3), basis_vectors(:, 1)), -m_one, m_one))
116 if (abs(theta(3) - m_pi*m_half) > 1e-8_real64) this%stargeneral%narms = this%stargeneral%narms + 1
117
119 !Cubic cell, no extra arms
120 if (this%stargeneral%narms == 0) then
122 return
123 end if
124
125
126 !We find the three closest neighbours, to define the direction of the arms
127 min_norm = m_huge
128 do ii= -1,1
129 do jj = -1,1
130 do kk = -1,1
131 !The nearest points could not be along the primitive axis
132 if (ii == 0 .and. jj == 0) cycle
133 if (ii == 0 .and. kk == 0) cycle
134 if (kk == 0 .and. jj == 0) cycle
135
136 !Nor in a plane formed by orthogonal vectors
137 if (abs(theta(1) - m_pi*m_half) <= 1e-8_real64 .and. kk == 0) cycle
138 if (abs(theta(2) - m_pi*m_half) <= 1e-8_real64 .and. ii == 0) cycle
139 if (abs(theta(3) - m_pi*m_half) <= 1e-8_real64 .and. jj == 0) cycle
140
141 norm = sum((ii*basis_vectors(:, 1) + jj*basis_vectors(:, 2) + kk*basis_vectors(:, 3))**2)
142
143 if (min_norm(1) - norm > tol) then
144 if (min_norm(2) - min_norm(1) > tol .and. this%stargeneral%narms >= 2) then
145 if (min_norm(3) - min_norm(2) > tol .and. this%stargeneral%narms == 3) then
146 this%stargeneral%arms(3, 1:3) = this%stargeneral%arms(2, 1:3)
147 min_norm(3) = min_norm(2)
148 end if
149 this%stargeneral%arms(2, 1:3) = this%stargeneral%arms(1, 1:3)
150 min_norm(2) = min_norm(1)
151 end if
152 min_norm(1) = norm
153 this%stargeneral%arms(1, 1:3) = (/ii, jj, kk/)
154 cycle
155 end if
156
157 ! Note: this should not be needed since we now have tolerances
158 if (this%stargeneral%arms(1, 1) == -ii &
159 .and. this%stargeneral%arms(1, 2) == -jj &
160 .and. this%stargeneral%arms(1, 3) == -kk) cycle
161
162 if (this%stargeneral%narms == 1) cycle
163
164 if (min_norm(2) - norm > tol) then
165 if (min_norm(3) - min_norm(2) > tol .and. this%stargeneral%narms == 3) then
166 this%stargeneral%arms(3, 1:3) = this%stargeneral%arms(2, 1:3)
167 min_norm(3) = min_norm(2)
168 end if
169 min_norm(2) = norm
170 this%stargeneral%arms(2, 1:3) = (/ii, jj, kk/)
171 cycle
172 end if
173
174 if (this%stargeneral%narms == 2) cycle
175
176 ! Note: this should not be needed since we now have tolerances
177 if (this%stargeneral%arms(2, 1) == -ii &
178 .and. this%stargeneral%arms(2, 2) == -jj &
179 .and. this%stargeneral%arms(2, 3) == -kk) cycle
180
181 if (min_norm(3) - norm > tol) then
182 min_norm(3) = norm
183 this%stargeneral%arms(3, 1:3) = (/ii, jj, kk/)
184 end if
185 end do
186 end do
187 end do
188
190 end subroutine stencil_stargeneral_get_arms
191
192
193 ! ---------------------------------------------------------
194 integer function stencil_stargeneral_size_lapl(this, dim, order) result(n)
195 type(stencil_t), intent(inout) :: this
196 integer, intent(in) :: dim
197 integer, intent(in) :: order
198
200
201 !normal star
202 n = 2*dim*order + 1
203
204 ! star general
205 n = n + 2 * order * this%stargeneral%narms
206
207
210
211
212 ! ---------------------------------------------------------
215 integer function stencil_stargeneral_extent(dir, order)
216 integer, intent(in) :: dir
217 integer, intent(in) :: order
218
219 integer :: extent
220
222
223 extent = 0
224 if (dir >= 1 .and. dir <= 3) then
225 if (order <= 2) then
226 extent = 2
227 else
228 extent = order
229 end if
230 end if
232
234 end function stencil_stargeneral_extent
235
236
237
238 ! ---------------------------------------------------------
239 subroutine stencil_stargeneral_get_lapl(this, dim, order)
240 type(stencil_t), intent(inout) :: this
241 integer, intent(in) :: dim
242 integer, intent(in) :: order
243
244 integer :: i, j, n
245 logical :: got_center
246
248
249 call stencil_allocate(this, dim, stencil_stargeneral_size_lapl(this, dim, order))
250
251 n = 1
252 select case (dim)
253 case (1)
254 n = 1
255 do i = 1, dim
256 do j = -order, order
257 if (j == 0) cycle
258 n = n + 1
259 this%points(i, n) = j
260 end do
261 end do
262 case (2)
263 n = 1
264 do i = 1, dim
265 do j = -order, order
266 if (j == 0) cycle
267 n = n + 1
268 this%points(i, n) = j
269 end do
270 end do
271
272 do j = -order, order
273 if (j == 0) cycle
274 do i = 1, this%stargeneral%narms
275 n = n + 1
276 this%points(1:2, n) = this%stargeneral%arms(i, 1:2)*j
277 end do
278 end do
279
280 case (3)
281 got_center = .false.
282
283 n = 0
284 do i = 1, dim
285 do j = -order, order
286
287 ! count center only once
288 if (j == 0) then
289 if (got_center) then
290 cycle
291 else
292 got_center = .true.
293 end if
294
295 end if
296 n = n + 1
297 this%points(i, n) = j
298 end do
299 end do
300
301 do j = -order, order
302 if (j == 0) cycle
303 do i = 1, this%stargeneral%narms
304 n = n + 1
305 this%points(1:3, n) = this%stargeneral%arms(i, 1:3)*j
306 end do
307 end do
309 end select
310
311 call stencil_init_center(this)
312
314 end subroutine stencil_stargeneral_get_lapl
315
316
317
318
319 ! ---------------------------------------------------------
320 subroutine stencil_stargeneral_pol_lapl(this, dim, order, pol)
321 type(stencil_t), intent(in) :: this
322 integer, intent(in) :: dim
323 integer, intent(in) :: order
324 integer, intent(out) :: pol(:,:)
325
326 integer :: i, j, n, j1
327 logical :: zeros_treated(dim)
328
330
331 n = 1
332 select case (dim)
333 case (1)
334 n = 1
335 pol(:,:) = 0
336 do i = 1, dim
337 do j = 1, 2*order
338 n = n + 1
339 pol(i, n) = j
340 end do
341 end do
342 case (2)
343 n = 1
344 pol(:,:) = 0
345 do i = 1, dim
346 do j = 1, 2*order
347 n = n + 1
348 pol(i, n) = j
349 end do
350 end do
351
352 do j = 1, 2*order
353 do i = 1, this%stargeneral%narms
354 n = n + 1
355 if (sum(this%stargeneral%arms(i,1:dim)) == 0) then
356 pol(1:2, n) = (/j,1/)
357 else
358 pol(1:2, n) = (/1,j/)
359 end if
360 end do
361 end do
362
363 case (3)
364 n = 1
365 pol(:,:) = 0
366 do i = 1, dim
367 do j = 1, 2*order
368 n = n + 1
369 pol(i, n) = j
370 end do
371 end do
372
373 ! first, treat arms with zeros: they should have polynomials with zeros in the
374 ! corresponding dimension
375 zeros_treated = .false.
376 do i = 1, this%stargeneral%narms
377 if (this%stargeneral%arms(i, 1) == 0) then
378 do j1 = 1, 2*order
379 n = n + 1
380 pol(1:3, n) = (/0, 1, j1/)
381 end do
382 zeros_treated(1) = .true.
383 else if (this%stargeneral%arms(i, 2) == 0) then
384 do j1 = 1, 2*order
385 n = n + 1
386 pol(1:3, n) = (/j1, 0, 1/)
387 end do
388 zeros_treated(2) = .true.
389 else if (this%stargeneral%arms(i, 3) == 0) then
390 do j1 = 1, 2*order
391 n = n + 1
392 pol(1:3, n) = (/1, j1, 0/)
393 end do
394 zeros_treated(3) = .true.
395 end if
396 end do ! end loop on number of arms
397 ! then treat the remaining arms, use the polynomials that have not been used yet
398 do i = 1, this%stargeneral%narms - count(zeros_treated)
399 if (.not. zeros_treated(1)) then
400 do j1 = 1, 2*order
401 n = n + 1
402 pol(1:3, n) = (/0, 1, j1/)
403 end do
404 zeros_treated(1) = .true.
405 else if (.not. zeros_treated(2)) then
406 do j1 = 1, 2*order
407 n = n + 1
408 pol(1:3, n) = (/j1, 0, 1/)
409 end do
410 zeros_treated(2) = .true.
411 else if (.not. zeros_treated(3)) then
412 do j1 = 1, 2*order
413 n = n + 1
414 pol(1:3, n) = (/1, j1, 0/)
415 end do
416 zeros_treated(3) = .true.
417 end if
418 end do ! end loop on number of arms
419 end select
420
422 end subroutine stencil_stargeneral_pol_lapl
423
424
426
427!! Local Variables:
428!! mode: f90
429!! coding: utf-8
430!! End:
double acos(double __x) __attribute__((__nothrow__
real(real64), parameter, public m_huge
Definition: global.F90:206
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
real(real64), parameter, public m_half
Definition: global.F90:194
real(real64), parameter, public m_one
Definition: global.F90:189
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
elemental real(real64) function, public clamp(x, xmin, xmax)
Return the value of x restricted to [xmin;xmax].
Definition: math.F90:1549
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:161
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:415
This module defines stencils used in Octopus.
Definition: stencil.F90:135
subroutine, public stencil_allocate(this, dim, size)
Definition: stencil.F90:178
subroutine, public stencil_init_center(this)
Definition: stencil.F90:275
This module defines routines, generating operators for a generalized star stencil.
subroutine, public stencil_stargeneral_get_arms(this, dim, coord_system)
Finds the direction of the arms of the star-general stencil as described in Natan et al....
subroutine, public stencil_stargeneral_pol_lapl(this, dim, order, pol)
integer function, public stencil_stargeneral_extent(dir, order)
Returns maximum extension of the stencil in spatial direction dir = 1, 2, 3 for a given discretizatio...
subroutine, public stencil_stargeneral_get_lapl(this, dim, order)
integer function, public stencil_stargeneral_size_lapl(this, dim, order)
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:163
int true(void)