Octopus
derivatives.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
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
27
29 use accel_oct_m
31 use batch_oct_m
34 use debug_oct_m
40 use global_oct_m
41 use iso_c_binding
42 use, intrinsic :: iso_fortran_env
45 use loct_oct_m
46 use math_oct_m
47 use mesh_oct_m
53 use parser_oct_m
55 use space_oct_m
63 use types_oct_m
64 use utils_oct_m
66
67! debug purposes
68! use io_binary_oct_m
69! use io_function_oct_m
70! use io_oct_m
71! use unit_oct_m
72! use unit_system_oct_m
73
74 implicit none
75
76 private
77 public :: &
115
116
117 integer, parameter :: &
118 DER_BC_ZERO_F = 0, & !< function is zero at the boundaries
119 der_bc_zero_df = 1, &
120 der_bc_period = 2
122 integer, parameter, public :: &
123 DER_STAR = 1, &
124 der_variational = 2, &
125 der_cube = 3, &
126 der_starplus = 4, &
128
129 integer, parameter :: &
130 BLOCKING = 1, &
131 non_blocking = 2
132
135 type derivatives_t
136 ! Components are public by default
137 type(boundaries_t) :: boundaries
138 type(mesh_t), pointer :: mesh => null()
139 integer :: dim = 0
140 integer, private :: periodic_dim = 0
141 integer :: order = 0
142 integer :: stencil_type = 0
143
144 real(real64), allocatable :: masses(:)
145
148 real(real64), private :: lapl_cutoff = m_zero
149
150 type(nl_operator_t), allocatable, private :: op(:)
152 type(nl_operator_t), pointer :: lapl => null()
153 type(nl_operator_t), pointer :: grad(:) => null()
154
155 integer, allocatable :: n_ghost(:)
156!#if defined(HAVE_MPI)
157 integer, private :: comm_method = 0
158!#endif
159 type(derivatives_t), pointer :: finer => null()
160 type(derivatives_t), pointer :: coarser => null()
161 type(transfer_table_t), pointer :: to_finer => null()
162 type(transfer_table_t), pointer :: to_coarser => null()
163 end type derivatives_t
164
167 private
168!#ifdef HAVE_MPI
169 type(par_vec_handle_batch_t) :: pv_h
170!#endif
171 type(derivatives_t), pointer :: der
172 type(nl_operator_t), pointer :: op
173 type(batch_t), pointer :: ff
174 type(batch_t), pointer :: opff
175 logical :: ghost_update
176 logical :: factor_present
177 real(real64) :: factor
179
180 type(accel_kernel_t) :: kernel_uvw_xyz, kernel_dcurl, kernel_zcurl
181
182contains
183
184 ! ---------------------------------------------------------
185 subroutine derivatives_init(der, namespace, space, coord_system, order)
186 type(derivatives_t), target, intent(inout) :: der
187 type(namespace_t), intent(in) :: namespace
188 class(space_t), intent(in) :: space
189 class(coordinate_system_t), intent(in) :: coord_system
190 integer, optional, intent(in) :: order
191
192 integer :: idir
193 integer :: default_stencil
194 character(len=40) :: flags
195
196 push_sub(derivatives_init)
197
198 ! Non-orthogonal curvilinear coordinates are currently not implemented
199 assert(.not. coord_system%local_basis .or. coord_system%orthogonal)
200
201 ! copy this value to my structure
202 der%dim = space%dim
203 der%periodic_dim = space%periodic_dim
204
205 !%Variable DerivativesStencil
206 !%Type integer
207 !%Default stencil_star
208 !%Section Mesh::Derivatives
209 !%Description
210 !% Decides what kind of stencil is used, <i>i.e.</i> which points, around
211 !% each point in the mesh, are the neighboring points used in the
212 !% expression of the differential operator.
213 !%
214 !% If curvilinear coordinates are to be used, then only the <tt>stencil_starplus</tt>
215 !% or the <tt>stencil_cube</tt> may be used. We only recommend the <tt>stencil_starplus</tt>,
216 !% since the cube typically needs far too much memory.
217 !%Option stencil_star 1
218 !% A star around each point (<i>i.e.</i>, only points on the axis).
219 !%Option stencil_variational 2
220 !% Same as the star, but with coefficients built in a different way.
221 !%Option stencil_cube 3
222 !% A cube of points around each point.
223 !%Option stencil_starplus 4
224 !% The star, plus a number of off-axis points.
225 !%Option stencil_stargeneral 5
226 !% The general star. Default for non-orthogonal grids.
227 !%End
228 default_stencil = der_star
229 if (coord_system%local_basis) default_stencil = der_starplus
230 if (.not. coord_system%orthogonal) default_stencil = der_stargeneral
232 call parse_variable(namespace, 'DerivativesStencil', default_stencil, der%stencil_type)
234 if (.not. varinfo_valid_option('DerivativesStencil', der%stencil_type)) then
235 call messages_input_error(namespace, 'DerivativesStencil')
236 end if
237 call messages_print_var_option("DerivativesStencil", der%stencil_type, namespace=namespace)
238
239 if (coord_system%local_basis .and. der%stencil_type < der_cube) call messages_input_error(namespace, 'DerivativesStencil')
240 if (der%stencil_type == der_variational) then
241 !%Variable DerivativesLaplacianFilter
242 !%Type float
243 !%Default 1.0
244 !%Section Mesh::Derivatives
245 !%Description
246 !% Undocumented
247 !%End
248 call parse_variable(namespace, 'DerivativesLaplacianFilter', m_one, der%lapl_cutoff)
249 end if
251 !%Variable DerivativesOrder
252 !%Type integer
253 !%Default 4
254 !%Section Mesh::Derivatives
255 !%Description
256 !% This variable gives the discretization order for the approximation of
257 !% the differential operators. This means, basically, that
258 !% <tt>DerivativesOrder</tt> points are used in each positive/negative
259 !% spatial direction, <i>e.g.</i> <tt>DerivativesOrder = 1</tt> would give
260 !% the well-known three-point formula in 1D.
261 !% The number of points actually used for the Laplacian
262 !% depends on the stencil used. Let <math>O</math> = <tt>DerivativesOrder</tt>, and <math>d</math> = <tt>Dimensions</tt>.
263 !% <ul>
264 !% <li> <tt>stencil_star</tt>: <math>2 O d + 1</math>
265 !% <li> <tt>stencil_cube</tt>: <math>(2 O + 1)^d</math>
266 !% <li> <tt>stencil_starplus</tt>: <math>2 O d + 1 + n</math> with <i>n</i> being 8
267 !% in 2D and 24 in 3D.
268 !% </ul>
269 !%End
270 call parse_variable(namespace, 'DerivativesOrder', 4, der%order)
271 ! overwrite order if given as argument
272 if (present(order)) then
273 der%order = order
274 end if
275
276#ifdef HAVE_MPI
277 !%Variable ParallelizationOfDerivatives
278 !%Type integer
279 !%Default non_blocking
280 !%Section Execution::Parallelization
281 !%Description
282 !% This option selects how the communication of mesh boundaries is performed.
283 !%Option blocking 1
284 !% Blocking communication.
285 !%Option non_blocking 2
286 !% Communication is based on non-blocking point-to-point communication.
287 !%End
288
289 call parse_variable(namespace, 'ParallelizationOfDerivatives', non_blocking, der%comm_method)
290
291 if (.not. varinfo_valid_option('ParallelizationOfDerivatives', der%comm_method)) then
292 call messages_input_error(namespace, 'ParallelizationOfDerivatives')
293 end if
294
295 call messages_obsolete_variable(namespace, 'OverlapDerivatives', 'ParallelizationOfDerivatives')
296#endif
297
298 ! if needed, der%masses should be initialized in modelmb_particles_init
299 safe_allocate(der%masses(1:space%dim))
300 der%masses = m_one
301
302 ! construct lapl and grad structures
303 safe_allocate(der%op(1:der%dim + 1))
304 der%grad => der%op
305 der%lapl => der%op(der%dim + 1)
306
307 call derivatives_get_stencil_lapl(der, space, coord_system)
309
310 ! find out how many ghost points we need in each dimension
311 safe_allocate(der%n_ghost(1:der%dim))
312 der%n_ghost(:) = 0
313 do idir = 1, der%dim
314 der%n_ghost(idir) = maxval(abs(der%lapl%stencil%points(idir, :)))
315 end do
316
317 nullify(der%coarser)
318 nullify(der%finer)
319 nullify(der%to_coarser)
320 nullify(der%to_finer)
321
322 if (accel_is_enabled()) then
323 ! Check if we can build the uvw_to_xyz kernel
324 select type (coord_system)
325 type is (cartesian_t)
326 ! In this case one does not need to call the kernel, so all is fine
327 class default
328 if (der%dim > 3) then
329 message(1) = "Calculation of derivatives on the GPU with dimension > 3 are only implemented for Cartesian coordinates."
330 call messages_fatal(1, namespace=namespace)
331 else
332 write(flags, '(A,I1.1)') ' -DDIMENSION=', der%dim
333 call accel_kernel_build(kernel_uvw_xyz, 'uvw_to_xyz.cl', 'uvw_to_xyz', flags)
334 end if
335 end select
336 call accel_kernel_build(kernel_dcurl, 'curl.cl', 'dcurl', flags = '-DRTYPE_DOUBLE')
337 call accel_kernel_build(kernel_zcurl, 'curl.cl', 'zcurl', flags = '-DRTYPE_COMPLEX')
338 end if
339
340 pop_sub(derivatives_init)
341 end subroutine derivatives_init
342
343
344 ! ---------------------------------------------------------
345 subroutine derivatives_end(der)
346 type(derivatives_t), intent(inout) :: der
347
348 integer :: idim
349
350 push_sub(derivatives_end)
351
352 assert(allocated(der%op))
353
354 do idim = 1, der%dim+1
355 call nl_operator_end(der%op(idim))
356 end do
357
358 safe_deallocate_a(der%masses)
359
360 safe_deallocate_a(der%n_ghost)
361
362 safe_deallocate_a(der%op)
363 nullify(der%lapl, der%grad)
364
365 nullify(der%coarser)
366 nullify(der%finer)
367 nullify(der%to_coarser)
368 nullify(der%to_finer)
369
370 call boundaries_end(der%boundaries)
371
372 pop_sub(derivatives_end)
373 end subroutine derivatives_end
374
375
376 ! ---------------------------------------------------------
377 subroutine derivatives_get_stencil_lapl(der, space, coord_system)
378 type(derivatives_t), intent(inout) :: der
379 class(space_t), intent(in) :: space
380 class(coordinate_system_t), intent(in) :: coord_system
381
383
384 assert(associated(der%lapl))
385
386 ! initialize nl operator
387 call nl_operator_init(der%lapl, "Laplacian")
388
389 ! create stencil
390 select case (der%stencil_type)
391 case (der_star, der_variational)
392 call stencil_star_get_lapl(der%lapl%stencil, der%dim, der%order)
393 case (der_cube)
394 call stencil_cube_get_lapl(der%lapl%stencil, der%dim, der%order)
395 case (der_starplus)
396 call stencil_starplus_get_lapl(der%lapl%stencil, der%dim, der%order)
397 case (der_stargeneral)
398 call stencil_stargeneral_get_arms(der%lapl%stencil, space%dim, coord_system)
399 call stencil_stargeneral_get_lapl(der%lapl%stencil, der%dim, der%order)
400 end select
401
403 end subroutine derivatives_get_stencil_lapl
404
405
406 ! ---------------------------------------------------------
408 subroutine derivatives_lapl_diag(der, lapl)
409 type(derivatives_t), intent(in) :: der
410 real(real64), intent(out) :: lapl(:)
411
412 push_sub(derivatives_lapl_diag)
413
414 assert(ubound(lapl, dim=1) >= der%mesh%np)
415
416 ! the Laplacian is a real operator
417 call dnl_operator_operate_diag(der%lapl, lapl)
418
419 pop_sub(derivatives_lapl_diag)
420
421 end subroutine derivatives_lapl_diag
422
423
424 ! ---------------------------------------------------------
425 subroutine derivatives_get_stencil_grad(der)
426 type(derivatives_t), intent(inout) :: der
427
428
429 integer :: ii
430 character :: dir_label
431
433
434 assert(associated(der%grad))
435
436 ! initialize nl operator
437 do ii = 1, der%dim
438 dir_label = ' '
439 if (ii < 5) dir_label = index2axis(ii)
440
441 call nl_operator_init(der%grad(ii), "Gradient "//dir_label)
442
443 ! create stencil
444 select case (der%stencil_type)
445 case (der_star, der_variational)
446 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
447 case (der_cube)
448 call stencil_cube_get_grad(der%grad(ii)%stencil, der%dim, der%order)
449 case (der_starplus)
450 call stencil_starplus_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
451 case (der_stargeneral)
452 ! use the simple star stencil
453 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
454 end select
455 end do
456
458
459 end subroutine derivatives_get_stencil_grad
460
461 ! ---------------------------------------------------------
493 subroutine derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
494 type(derivatives_t), intent(inout) :: der
495 type(namespace_t), intent(in) :: namespace
496 class(space_t), intent(in) :: space
497 class(mesh_t), target, intent(in) :: mesh
498 real(real64), optional, intent(in) :: qvector(:)
500 logical, optional, intent(in) :: regenerate
501 logical, optional, intent(in) :: verbose
502
503 integer, allocatable :: polynomials(:,:)
504 real(real64), allocatable :: rhs(:,:)
505 integer :: i
506 logical :: const_w_
507 character(len=32) :: name
508 type(nl_operator_t) :: auxop
509 integer :: np_zero_bc
510
511 push_sub(derivatives_build)
512
513 if (.not. optional_default(regenerate, .false.)) then
514 call boundaries_init(der%boundaries, namespace, space, mesh, qvector)
515 end if
516
517 assert(allocated(der%op))
518 assert(der%stencil_type >= der_star .and. der%stencil_type <= der_stargeneral)
519 assert(.not.(der%stencil_type == der_variational .and. mesh%use_curvilinear))
520
521 der%mesh => mesh ! make a pointer to the underlying mesh
522
523 const_w_ = .true.
524
525 ! need non-constant weights for curvilinear and scattering meshes
526 if (mesh%use_curvilinear) const_w_ = .false.
527
528 np_zero_bc = 0
529
530 ! build operators
531 do i = 1, der%dim+1
532 if (optional_default(regenerate, .false.)) then
533 safe_deallocate_a(der%op(i)%w)
534 end if
535 call nl_operator_build(space, mesh, der%op(i), der%mesh%np, const_w = const_w_, &
536 regenerate=regenerate)
537 np_zero_bc = max(np_zero_bc, nl_operator_np_zero_bc(der%op(i)))
538 end do
539
540 assert(np_zero_bc > mesh%np .and. np_zero_bc <= mesh%np_part)
541
542 select case (der%stencil_type)
543
544 case (der_star, der_starplus, der_stargeneral) ! Laplacian and gradient have different stencils
545 do i = 1, der%dim + 1
546 safe_allocate(polynomials(1:der%dim, 1:der%op(i)%stencil%size))
547 safe_allocate(rhs(1:der%op(i)%stencil%size, 1))
548
549 if (i <= der%dim) then ! gradient
550 call stencil_stars_pol_grad(der%stencil_type, der%dim, i, der%order, polynomials)
551 call get_rhs_grad(der, polynomials, i, rhs(:,1))
552 name = index2axis(i) // "-gradient"
553 else ! Laplacian
554 call stencil_stars_pol_lapl(der%stencil_type, der%op(der%dim+1)%stencil, der%dim, der%order, polynomials)
555 call get_rhs_lapl(der, polynomials, rhs(:,1))
556 name = "Laplacian"
557 end if
558
559 call derivatives_make_discretization(namespace, der%dim, der%periodic_dim, der%mesh, der%masses, polynomials, rhs, 1, &
560 der%op(i:i), name, verbose=verbose)
561 safe_deallocate_a(polynomials)
562 safe_deallocate_a(rhs)
563 end do
564
565 case (der_cube)
566 ! Laplacian and gradient have similar stencils, so use one call to derivatives_make_discretization
567 ! to solve the linear equation once for several right-hand sides
568 safe_allocate(polynomials(1:der%dim, 1:der%op(1)%stencil%size))
569 safe_allocate(rhs(1:der%op(1)%stencil%size, 1:der%dim + 1))
570 call stencil_cube_polynomials_lapl(der%dim, der%order, polynomials)
571
572 do i = 1, der%dim
573 call get_rhs_grad(der, polynomials, i, rhs(:,i))
574 end do
575 call get_rhs_lapl(der, polynomials, rhs(:, der%dim+1))
576
577 name = "derivatives"
578 call derivatives_make_discretization(namespace, der%dim, der%periodic_dim, der%mesh, der%masses, polynomials, rhs, &
579 der%dim+1, der%op(:), name, verbose=verbose)
580
581 safe_deallocate_a(polynomials)
582 safe_deallocate_a(rhs)
583
584 case (der_variational)
585 ! we have the explicit coefficients
586 call stencil_variational_coeff_lapl(der%dim, der%order, mesh%spacing, der%lapl, alpha = der%lapl_cutoff)
587 end select
588
589
590 ! Here the Laplacian is forced to be self-adjoint, and the gradient to be skew-self-adjoint
591 if (mesh%use_curvilinear) then
592 ! The nl_operator_copy routine has an assert
593 if (accel_is_enabled()) then
594 call messages_write('Curvilinear coordinates on GPUs is not implemented')
595 call messages_fatal(namespace=namespace)
596 end if
597
598 do i = 1, der%dim
599 call nl_operator_init(auxop, "auxop")
600 call nl_operator_adjoint(der%grad(i), auxop, der%mesh, self_adjoint=.false.)
601
602 call nl_operator_end(der%grad(i))
603 call nl_operator_copy(der%grad(i), auxop)
604 call nl_operator_end(auxop)
605 end do
606 call nl_operator_init(auxop, "auxop")
607 call nl_operator_adjoint(der%lapl, auxop, der%mesh, self_adjoint=.true.)
608
609 call nl_operator_end(der%lapl)
610 call nl_operator_copy(der%lapl, auxop)
611 call nl_operator_end(auxop)
612 end if
613
614 pop_sub(derivatives_build)
615
616 contains
617 subroutine stencil_stars_pol_grad(stencil_type, dim, direction, order, polynomials)
618 integer, intent(in) :: stencil_type
619 integer, intent(in) :: dim
620 integer, intent(in) :: direction
621 integer, intent(in) :: order
622 integer, intent(inout) :: polynomials(:, :)
623
624 select case (der%stencil_type)
625 case (der_star, der_stargeneral)
626 call stencil_star_polynomials_grad(direction, order, polynomials)
627 case (der_starplus)
628 call stencil_starplus_pol_grad(dim, direction, order, polynomials)
629 end select
630 end subroutine stencil_stars_pol_grad
631
632 subroutine stencil_stars_pol_lapl(stencil_type, stencil, dim, order, polynomials)
633 integer, intent(in) :: stencil_type
634 type(stencil_t), intent(in) :: stencil
635 integer, intent(in) :: dim
636 integer, intent(in) :: order
637 integer, intent(inout) :: polynomials(:, :)
638
639 select case (der%stencil_type)
640 case (der_star)
641 call stencil_star_polynomials_lapl(dim, order, polynomials)
642 case (der_starplus)
643 call stencil_starplus_pol_lapl(dim, order, polynomials)
644 case (der_stargeneral)
645 call stencil_stargeneral_pol_lapl(stencil, dim, order, polynomials)
646 end select
647 end subroutine stencil_stars_pol_lapl
648
649 end subroutine derivatives_build
650
651 ! ---------------------------------------------------------
652 subroutine get_rhs_lapl(der, polynomials, rhs)
653 type(derivatives_t), intent(in) :: der
654 integer, intent(in) :: polynomials(:,:)
655 real(real64), intent(out) :: rhs(:)
656
657 integer :: i, j, k
658 real(real64) :: f(1:der%dim, 1:der%dim)
659 integer :: powers(0:2)
660
661 push_sub(get_rhs_lapl)
662
663 ! assume orthogonal basis as default (i.e. for curvilinear coordinates)
664 f = m_zero
665 do i = 1, der%dim
666 f(i, i) = m_one
667 end do
668
669 select type (coord => der%mesh%coord_system)
670 class is (affine_coordinates_t)
671 f(1:der%dim, 1:der%dim) = matmul(coord%basis%change_of_basis_matrix(1:der%dim, 1:der%dim), &
672 transpose(coord%basis%change_of_basis_matrix(1:der%dim, 1:der%dim)))
673 class is (curv_gygi_t)
674 class is (curv_briggs_t)
675 class is (curv_modine_t)
676 class default
677 message(1) = "Weight computation not implemented for the coordinate system chosen."
678 call messages_fatal(1)
679 end select
680
681 ! find right-hand side for operator
682 rhs(:) = m_zero
683 do j = 1, size(polynomials, dim=2)
684 ! count the powers of the polynomials
685 powers = 0
686 do i = 1, der%dim
687 if (polynomials(i, j) <= 2) then
688 powers(polynomials(i, j)) = powers(polynomials(i, j)) + 1
689 end if
690 end do
691
692 ! find all polynomials for which exactly one term is quadratic
693 ! for these, the Laplacian on the polynomial is 2*F(i, i)
694 if (powers(2) == 1 .and. powers(0) == der%dim - 1) then
695 do i = 1, der%dim
696 if (polynomials(i, j) == 2) then
697 rhs(j) = m_two*f(i, i)
698 end if
699 end do
700 end if
701 ! find all polynomials for which exactly two terms are linear
702 ! for these, the Laplacian on the polynomial is F(i, k) + F(k, i)
703 if (powers(1) == 2 .and. powers(0) == der%dim - 2) then
704 do i = 1, der%dim
705 if (polynomials(i, j) == 1) then
706 do k = i+1, der%dim
707 if (polynomials(k, j) == 1) then
708 rhs(j) = f(i, k) + f(k, i)
709 end if
710 end do
711 end if
712 end do
713 end if
714 end do
715
716 pop_sub(get_rhs_lapl)
717 end subroutine get_rhs_lapl
718
719 ! ---------------------------------------------------------
720 subroutine get_rhs_grad(der, polynomials, dir, rhs)
721 type(derivatives_t), intent(in) :: der
722 integer, intent(in) :: polynomials(:,:)
723 integer, intent(in) :: dir
724 real(real64), intent(out) :: rhs(:)
726 integer :: j, k
727 logical :: this_one
728
729 push_sub(get_rhs_grad)
730
731 ! find right-hand side for operator
732 rhs(:) = m_zero
733 do j = 1, der%grad(dir)%stencil%size
734 this_one = .true.
735 do k = 1, der%dim
736 if (k == dir .and. polynomials(k, j) /= 1) this_one = .false.
737 if (k /= dir .and. polynomials(k, j) /= 0) this_one = .false.
738 end do
739 if (this_one) rhs(j) = m_one
740 end do
741
742 pop_sub(get_rhs_grad)
743 end subroutine get_rhs_grad
744
746 ! ---------------------------------------------------------
747 subroutine derivatives_make_discretization(namespace, dim, periodic_dim, mesh, masses, pol, rhs, nderiv, op, name, &
748 verbose)
749 type(namespace_t), intent(in) :: namespace
750 integer, intent(in) :: dim
751 integer, intent(in) :: periodic_dim
752 type(mesh_t), intent(in) :: mesh
753 real(real64), intent(in) :: masses(:)
754 integer, intent(in) :: pol(:,:)
755 integer, intent(in) :: nderiv
756 real(real64), contiguous, intent(inout) :: rhs(:,:)
757 type(nl_operator_t), intent(inout) :: op(:)
758 character(len=32), intent(in) :: name
759 logical, optional, intent(in) :: verbose
760
761 integer :: p, p_max, i, j, k, pow_max
762 real(real64) :: x(dim)
763 real(real64), allocatable :: mat(:,:), sol(:,:), powers(:,:)
764 logical :: transform_to_cartesian
765
767
768 safe_allocate(mat(1:op(1)%stencil%size, 1:op(1)%stencil%size))
769 safe_allocate(sol(1:op(1)%stencil%size, 1:nderiv))
770
771 if (optional_default(verbose, .true.)) then
772 message(1) = 'Info: Generating weights for finite-difference discretization of ' // trim(name)
773 call messages_info(1, namespace=namespace)
774 end if
775
776 select type (coord => mesh%coord_system)
777 class is (affine_coordinates_t)
778 transform_to_cartesian = .false.
779 class is (curv_gygi_t)
780 transform_to_cartesian = .true.
781 class is (curv_briggs_t)
782 transform_to_cartesian = .true.
783 class is (curv_modine_t)
784 transform_to_cartesian = .true.
785 class default
786 message(1) = "Weight computation not implemented for the coordinate system chosen."
787 call messages_fatal(1)
788 end select
789
790 ! use to generate power lookup table
791 pow_max = maxval(pol)
792 safe_allocate(powers(1:dim, 0:pow_max))
793 powers(:,:) = m_zero
794 powers(:,0) = m_one
795
796 p_max = op(1)%np
797 if (op(1)%const_w) p_max = 1
798
799 do p = 1, p_max
800 ! first polynomial is just a constant
801 mat(1,:) = m_one
802 ! i indexes the point in the stencil
803 do i = 1, op(1)%stencil%size
804 if (mesh%use_curvilinear) then
805 x = mesh%x(p + op(1)%ri(i, op(1)%rimap(p)), :) - mesh%x(p, :)
806 else
807 x = real(op(1)%stencil%points(:, i), real64) *mesh%spacing
808 ! transform to Cartesisan coordinates only for curvilinear meshes
809 if (transform_to_cartesian) then
810 x = mesh%coord_system%to_cartesian(x)
811 end if
812 end if
814 ! NB: these masses are applied on the cartesian directions. Should add a check for non-orthogonal axes
815 x = x*sqrt(masses)
816
817 ! calculate powers
818 powers(:, 1) = x
819 do k = 2, pow_max
820 powers(:, k) = x*powers(:, k-1)
821 end do
822
823 ! generate the matrix
824 ! j indexes the polynomial being used
825 do j = 2, op(1)%stencil%size
826 mat(j, i) = powers(1, pol(1, j))
827 do k = 2, dim
828 mat(j, i) = mat(j, i)*powers(k, pol(k, j))
829 end do
830 end do
831 end do ! loop over i = point in stencil
832
833 ! linear problem to solve for derivative weights:
834 ! mat * sol = rhs
835 call lalg_linsyssolve(op(1)%stencil%size, nderiv, mat, rhs, sol)
836
837 ! for the cube stencil, all derivatives are calculated at once, so assign
838 ! the correct solution to each operator
839 do i = 1, nderiv
840 op(i)%w(:, p) = sol(:, i)
841 end do
842
843 end do ! loop over points p
844
845 do i = 1, nderiv
847 end do
848
849 ! In case of constant weights, we store the weights of the Laplacian on the GPU, as this
850 ! saves many unecessary transfers
851 do i = 1, nderiv
854 end do
855
856
857 safe_deallocate_a(mat)
858 safe_deallocate_a(sol)
859 safe_deallocate_a(powers)
860
863
864#ifdef HAVE_MPI
865 ! ---------------------------------------------------------
866 logical function derivatives_overlap(this) result(overlap)
867 type(derivatives_t), intent(in) :: this
868
869 push_sub(derivatives_overlap)
870
871 overlap = this%comm_method /= blocking
872
873 pop_sub(derivatives_overlap)
874 end function derivatives_overlap
875#endif
876
877 ! ---------------------------------------------------------
878 subroutine derivatives_get_lapl(this, namespace, op, space, name, order)
879 type(derivatives_t), intent(in) :: this
880 type(namespace_t), intent(in) :: namespace
881 type(nl_operator_t), intent(inout) :: op(:)
882 class(space_t), intent(in) :: space
883 character(len=32), intent(in) :: name
884 integer, intent(in) :: order
885
886 integer, allocatable :: polynomials(:,:)
887 real(real64), allocatable :: rhs(:,:)
888
889 push_sub(derivatives_get_lapl)
890
891 call nl_operator_init(op(1), name)
892 if (.not. this%mesh%coord_system%orthogonal) then
893 call stencil_stargeneral_get_arms(op(1)%stencil, this%dim, this%mesh%coord_system)
894 call stencil_stargeneral_get_lapl(op(1)%stencil, this%dim, order)
895 else
896 call stencil_star_get_lapl(op(1)%stencil, this%dim, order)
897 end if
898 call nl_operator_build(space, this%mesh, op(1), this%mesh%np, const_w = .not. this%mesh%use_curvilinear)
899
900 !At the moment this code is almost copy-pasted from derivatives_build.
901 safe_allocate(polynomials(1:this%dim, 1:op(1)%stencil%size))
902 safe_allocate(rhs(1:op(1)%stencil%size, 1))
903 if (.not. this%mesh%coord_system%orthogonal) then
904 call stencil_stargeneral_pol_lapl(op(1)%stencil, this%dim, order, polynomials)
905 else
906 call stencil_star_polynomials_lapl(this%dim, order, polynomials)
907 end if
908 call get_rhs_lapl(this, polynomials, rhs(:, 1))
909 call derivatives_make_discretization(namespace, this%dim, this%periodic_dim, this%mesh, this%masses, &
910 polynomials, rhs, 1, op(1:1), name)
911 safe_deallocate_a(polynomials)
912 safe_deallocate_a(rhs)
913
914 pop_sub(derivatives_get_lapl)
915 end subroutine derivatives_get_lapl
916
917 ! ---------------------------------------------------------
930 function derivatives_get_inner_boundary_mask(this) result(mask)
931 type(derivatives_t), intent(in) :: this
932
933 logical :: mask(1:this%mesh%np)
934 integer :: ip, is, index
935
936 mask = .false.
937 ! Loop through all points in the grid
938 do ip = 1, this%mesh%np
939 ! For each of them, loop through all points in the stencil
940 do is = 1, this%lapl%stencil%size
941 ! Get the index of the point obtained as: grid_point + displament_due_to_stencil
942 index = nl_operator_get_index(this%lapl, is, ip)
943 ! Check whether the displaced point if outsude the grid. Is so, it belongs to the mask
944 if (index > this%mesh%np + this%mesh%pv%np_ghost) then
945 mask(ip) = .true.
946 exit
947 end if
948 end do
949 end do
950
952
953 ! ---------------------------------------------------------
958 real(real64) function derivatives_lapl_get_max_eigenvalue(this)
959 type(derivatives_t), intent(in) :: this
960
961 integer :: i
962
963 push_sub(derivatives_lapl_get_max_eigenvalue)
964
965 derivatives_lapl_get_max_eigenvalue = m_zero
966 if ((this%stencil_type == der_star .or. this%stencil_type == der_stargeneral) &
967 .and. .not. this%mesh%use_curvilinear) then
968 ! use Fourier transform of stencil evaluated at the maximum phase
969 do i = 1, this%lapl%stencil%size
970 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
971 (-1)**maxval(abs(this%lapl%stencil%points(:, i)))*this%lapl%w(i, 1)
972 end do
973 derivatives_lapl_get_max_eigenvalue = abs(derivatives_lapl_get_max_eigenvalue)
974 else
975 ! use upper bound from continuum for other stencils
976 do i = 1, this%dim
977 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
978 m_pi**2/this%mesh%spacing(i)**2
979 end do
980 end if
981
982 pop_sub(derivatives_lapl_get_max_eigenvalue)
984
985
986#include "undef.F90"
987#include "real.F90"
988#include "derivatives_inc.F90"
989
990#include "undef.F90"
991#include "complex.F90"
992#include "derivatives_inc.F90"
993
994end module derivatives_oct_m
995
996!! Local Variables:
997!! mode: f90
998!! coding: utf-8
999!! End:
subroutine stencil_stars_pol_grad(stencil_type, dim, direction, order, polynomials)
subroutine stencil_stars_pol_lapl(stencil_type, stencil, dim, order, polynomials)
double sqrt(double __x) __attribute__((__nothrow__
subroutine, public accel_kernel_build(this, file_name, kernel_name, flags)
Definition: accel.F90:2053
pure logical function, public accel_is_enabled()
Definition: accel.F90:401
This module implements batches of mesh functions.
Definition: batch.F90:133
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:116
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:122
subroutine, public boundaries_end(this)
Definition: boundaries.F90:428
subroutine, public boundaries_init(this, namespace, space, mesh, qvector)
initialize the boundary contitions
Definition: boundaries.F90:227
This module implements the curvilinear coordinates given in E.L. Briggs, D.J. Sullivan,...
This module implements the curvilinear coordinates given in F. Gygi and G. Galli, PRB 52 R2229 (1996)...
Definition: curv_gygi.F90:117
This module implements the curvilinear coordinates given in N. A. Modine, G. Zumbach,...
This module calculates the derivatives (gradients, Laplacians, etc.) of a function.
subroutine, public dderivatives_test(this, namespace, repetitions, min_blocksize, max_blocksize)
unit test for derivatives
subroutine derivatives_get_stencil_lapl(der, space, coord_system)
subroutine, public dderivatives_batch_grad(der, ffb, opffb, ghost_update, set_bc, to_cartesian, metric, factor)
apply the gradient to a batch of mesh functions
subroutine, public zderivatives_curl(der, ff, op_ff, ghost_update, set_bc)
apply the curl operator to a vector of mesh functions
subroutine, public dderivatives_perform(op, der, ff, op_ff, ghost_update, set_bc, factor)
apply a nl_operator to a mesh function
subroutine, public derivatives_lapl_diag(der, lapl)
Returns the diagonal elements of the Laplacian, needed for preconditioning.
integer, parameter, public der_cube
subroutine, public dderivatives_batch_curl_from_gradient(der, ffb, gradb)
calculate the curl from a batch and its gradient
subroutine, public derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
build the derivatives object:
subroutine get_rhs_grad(der, polynomials, dir, rhs)
subroutine, public zderivatives_batch_curl_from_gradient(der, ffb, gradb)
calculate the curl from a batch and its gradient
subroutine, public zderivatives_batch_div(der, ffb, opffb, ghost_update, set_bc, to_cartesian)
calculate the divergence of a vector of batches
subroutine, public dderivatives_partial(der, ff, op_ff, dir, ghost_update, set_bc)
apply the partial derivative along dir to a mesh function
subroutine, public dderivatives_batch_perform(op, der, ff, opff, ghost_update, set_bc, factor, async)
apply an operator to a bach of mesh functions
subroutine, public zderivatives_div(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the divergence operator to a vector of mesh functions
integer, parameter der_bc_period
boundary is periodic
subroutine, public dderivatives_batch_finish(handle, async)
apply a non-local operator to a batch (2nd part)
subroutine, public dderivatives_curl(der, ff, op_ff, ghost_update, set_bc)
apply the curl operator to a vector of mesh functions
subroutine derivatives_get_stencil_grad(der)
subroutine, public dderivatives_grad(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the gradient to a mesh function
subroutine, public derivatives_init(der, namespace, space, coord_system, order)
subroutine, public derivatives_end(der)
integer, parameter der_bc_zero_df
first derivative of the function is zero
subroutine, public dderivatives_batch_div(der, ffb, opffb, ghost_update, set_bc, to_cartesian)
calculate the divergence of a vector of batches
subroutine, public derivatives_get_lapl(this, namespace, op, space, name, order)
subroutine get_rhs_lapl(der, polynomials, rhs)
subroutine, public zderivatives_batch_perform(op, der, ff, opff, ghost_update, set_bc, factor, async)
apply an operator to a bach of mesh functions
subroutine, public zderivatives_batch_grad(der, ffb, opffb, ghost_update, set_bc, to_cartesian, metric, factor)
apply the gradient to a batch of mesh functions
subroutine, public dderivatives_batch_start(op, der, ff, opff, handle, ghost_update, set_bc, factor)
apply a non-local operator to a batch (1st part)
subroutine, public dderivatives_lapl(der, ff, op_ff, ghost_update, set_bc, factor)
apply the Laplacian to a mesh function
real(real64) function, public derivatives_lapl_get_max_eigenvalue(this)
Get maximum eigenvalue of discrete Laplacian. For the star and star_general stencils,...
logical function derivatives_overlap(this)
subroutine, public dderivatives_batch_curl(der, ffb, ghost_update, set_bc)
apply the curl to a batch of mesh functions
subroutine, public zderivatives_grad(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the gradient to a mesh function
subroutine derivatives_make_discretization(namespace, dim, periodic_dim, mesh, masses, pol, rhs, nderiv, op, name, verbose)
subroutine, public zderivatives_partial(der, ff, op_ff, dir, ghost_update, set_bc)
apply the partial derivative along dir to a mesh function
subroutine, public zderivatives_batch_start(op, der, ff, opff, handle, ghost_update, set_bc, factor)
apply a non-local operator to a batch (1st part)
logical function, dimension(1:this%mesh%np), public derivatives_get_inner_boundary_mask(this)
This function tells whether a point in the grid is contained in a layer of the width of the stencil b...
integer, parameter, public der_starplus
subroutine, public zderivatives_perform(op, der, ff, op_ff, ghost_update, set_bc, factor)
apply a nl_operator to a mesh function
subroutine, public zderivatives_batch_curl(der, ffb, ghost_update, set_bc)
apply the curl to a batch of mesh functions
subroutine, public zderivatives_test(this, namespace, repetitions, min_blocksize, max_blocksize)
unit test for derivatives
integer, parameter, public der_variational
subroutine, public zderivatives_lapl(der, ff, op_ff, ghost_update, set_bc, factor)
apply the Laplacian to a mesh function
subroutine, public zderivatives_batch_finish(handle, async)
apply a non-local operator to a batch (2nd part)
subroutine, public dderivatives_div(der, ff, op_ff, ghost_update, set_bc, to_cartesian)
apply the divergence operator to a vector of mesh functions
integer, parameter non_blocking
integer, parameter, public der_stargeneral
real(real64), parameter, public m_two
Definition: global.F90:190
real(real64), parameter, public m_zero
Definition: global.F90:188
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:186
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
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1045
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:414
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:713
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
This module defines non-local operators.
subroutine, public dnl_operator_operate_diag(op, fo)
subroutine, public nl_operator_init(op, label)
initialize an instance of a non-local operator by setting the label
subroutine, public nl_operator_update_gpu_buffers(op)
subroutine, public nl_operator_copy(opo, opi)
subroutine, public nl_operator_output_weights(this)
subroutine, public nl_operator_end(op)
subroutine, public nl_operator_build(space, mesh, op, np, const_w, regenerate)
subroutine, public nl_operator_adjoint(op, opt, mesh, self_adjoint)
opt has to be initialised and built.
integer pure function, public nl_operator_np_zero_bc(op)
integer pure function, public nl_operator_get_index(op, is, ip)
subroutine, public nl_operator_allocate_gpu_buffers(op)
Some general things and nomenclature:
Definition: par_vec.F90:171
This module defines routines, generating operators for a cubic stencil.
subroutine, public stencil_cube_get_lapl(this, dim, order)
subroutine, public stencil_cube_polynomials_lapl(dim, order, pol)
subroutine, public stencil_cube_get_grad(this, dim, order)
This module defines stencils used in Octopus.
Definition: stencil.F90:135
This module defines routines, generating operators for a star stencil.
subroutine, public stencil_star_get_grad(this, dim, dir, order)
subroutine, public stencil_star_get_lapl(this, dim, order)
subroutine, public stencil_star_polynomials_grad(dir, order, pol)
subroutine, public stencil_star_polynomials_lapl(dim, order, pol)
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)
subroutine, public stencil_stargeneral_get_lapl(this, dim, order)
This module defines routines, generating operators for a stencil consisting of a star and a cross....
subroutine, public stencil_starplus_pol_grad(dim, dir, order, pol)
subroutine, public stencil_starplus_pol_lapl(dim, order, pol)
subroutine, public stencil_starplus_get_lapl(this, dim, order)
subroutine, public stencil_starplus_get_grad(this, dim, dir, order)
Implements the variational discretization of the Laplacian as proposed by P. Maragakis,...
subroutine, public stencil_variational_coeff_lapl(dim, order, h, lapl, alpha)
This module is intended to contain simple general-purpose utility functions and procedures.
Definition: utils.F90:118
character pure function, public index2axis(idir)
Definition: utils.F90:202
static double f(double w, void *p)
abstract class to describe coordinate systems
handle to transfer data from the start() to finish() calls.
class representing derivatives
Describes mesh distribution to nodes.
Definition: mesh.F90:186
data type for non local operators
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:163
int true(void)