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 call parse_variable(namespace, 'DerivativesLaplacianFilter', m_one, der%lapl_cutoff)
242 end if
244 !%Variable DerivativesOrder
245 !%Type integer
246 !%Default 4
247 !%Section Mesh::Derivatives
248 !%Description
249 !% This variable gives the discretization order for the approximation of
250 !% the differential operators. This means, basically, that
251 !% <tt>DerivativesOrder</tt> points are used in each positive/negative
252 !% spatial direction, <i>e.g.</i> <tt>DerivativesOrder = 1</tt> would give
253 !% the well-known three-point formula in 1D.
254 !% The number of points actually used for the Laplacian
255 !% depends on the stencil used. Let <math>O</math> = <tt>DerivativesOrder</tt>, and <math>d</math> = <tt>Dimensions</tt>.
256 !% <ul>
257 !% <li> <tt>stencil_star</tt>: <math>2 O d + 1</math>
258 !% <li> <tt>stencil_cube</tt>: <math>(2 O + 1)^d</math>
259 !% <li> <tt>stencil_starplus</tt>: <math>2 O d + 1 + n</math> with <i>n</i> being 8
260 !% in 2D and 24 in 3D.
261 !% </ul>
262 !%End
263 call parse_variable(namespace, 'DerivativesOrder', 4, der%order)
264 ! overwrite order if given as argument
265 if (present(order)) then
266 der%order = order
267 end if
269#ifdef HAVE_MPI
270 !%Variable ParallelizationOfDerivatives
271 !%Type integer
272 !%Default non_blocking
273 !%Section Execution::Parallelization
274 !%Description
275 !% This option selects how the communication of mesh boundaries is performed.
276 !%Option blocking 1
277 !% Blocking communication.
278 !%Option non_blocking 2
279 !% Communication is based on non-blocking point-to-point communication.
280 !%End
281
282 call parse_variable(namespace, 'ParallelizationOfDerivatives', non_blocking, der%comm_method)
283
284 if (.not. varinfo_valid_option('ParallelizationOfDerivatives', der%comm_method)) then
285 call messages_input_error(namespace, 'ParallelizationOfDerivatives')
286 end if
287
288 call messages_obsolete_variable(namespace, 'OverlapDerivatives', 'ParallelizationOfDerivatives')
289#endif
290
291 ! if needed, der%masses should be initialized in modelmb_particles_init
292 safe_allocate(der%masses(1:space%dim))
293 der%masses = m_one
294
295 ! construct lapl and grad structures
296 safe_allocate(der%op(1:der%dim + 1))
297 der%grad => der%op
298 der%lapl => der%op(der%dim + 1)
299
300 call derivatives_get_stencil_lapl(der, space, coord_system)
302
303 ! find out how many ghost points we need in each dimension
304 safe_allocate(der%n_ghost(1:der%dim))
305 der%n_ghost(:) = 0
306 do idir = 1, der%dim
307 der%n_ghost(idir) = maxval(abs(der%lapl%stencil%points(idir, :)))
308 end do
309
310 nullify(der%coarser)
311 nullify(der%finer)
312 nullify(der%to_coarser)
313 nullify(der%to_finer)
314
315 if (accel_is_enabled()) then
316 ! Check if we can build the uvw_to_xyz kernel
317 select type (coord_system)
318 type is (cartesian_t)
319 ! In this case one does not need to call the kernel, so all is fine
320 class default
321 if (der%dim > 3) then
322 message(1) = "Calculation of derivatives on the GPU with dimension > 3 are only implemented for Cartesian coordinates."
323 call messages_fatal(1, namespace=namespace)
324 else
325 write(flags, '(A,I1.1)') ' -DDIMENSION=', der%dim
326 call accel_kernel_build(kernel_uvw_xyz, 'uvw_to_xyz.cl', 'uvw_to_xyz', flags)
327 end if
328 end select
329 call accel_kernel_build(kernel_dcurl, 'curl.cl', 'dcurl', flags = '-DRTYPE_DOUBLE')
330 call accel_kernel_build(kernel_zcurl, 'curl.cl', 'zcurl', flags = '-DRTYPE_COMPLEX')
331 end if
332
333 pop_sub(derivatives_init)
334 end subroutine derivatives_init
335
336
337 ! ---------------------------------------------------------
338 subroutine derivatives_end(der)
339 type(derivatives_t), intent(inout) :: der
340
341 integer :: idim
342
343 push_sub(derivatives_end)
344
345 assert(allocated(der%op))
346
347 do idim = 1, der%dim+1
348 call nl_operator_end(der%op(idim))
349 end do
350
351 safe_deallocate_a(der%masses)
352
353 safe_deallocate_a(der%n_ghost)
354
355 safe_deallocate_a(der%op)
356 nullify(der%lapl, der%grad)
357
358 nullify(der%coarser)
359 nullify(der%finer)
360 nullify(der%to_coarser)
361 nullify(der%to_finer)
362
363 call boundaries_end(der%boundaries)
364
365 pop_sub(derivatives_end)
366 end subroutine derivatives_end
367
368
369 ! ---------------------------------------------------------
370 subroutine derivatives_get_stencil_lapl(der, space, coord_system)
371 type(derivatives_t), intent(inout) :: der
372 class(space_t), intent(in) :: space
373 class(coordinate_system_t), intent(in) :: coord_system
374
376
377 assert(associated(der%lapl))
378
379 ! initialize nl operator
380 call nl_operator_init(der%lapl, "Laplacian")
381
382 ! create stencil
383 select case (der%stencil_type)
384 case (der_star, der_variational)
385 call stencil_star_get_lapl(der%lapl%stencil, der%dim, der%order)
386 case (der_cube)
387 call stencil_cube_get_lapl(der%lapl%stencil, der%dim, der%order)
388 case (der_starplus)
389 call stencil_starplus_get_lapl(der%lapl%stencil, der%dim, der%order)
390 case (der_stargeneral)
391 call stencil_stargeneral_get_arms(der%lapl%stencil, space%dim, coord_system)
392 call stencil_stargeneral_get_lapl(der%lapl%stencil, der%dim, der%order)
393 end select
394
396 end subroutine derivatives_get_stencil_lapl
397
398
399 ! ---------------------------------------------------------
401 subroutine derivatives_lapl_diag(der, lapl)
402 type(derivatives_t), intent(in) :: der
403 real(real64), intent(out) :: lapl(:)
404
405 push_sub(derivatives_lapl_diag)
406
407 assert(ubound(lapl, dim=1) >= der%mesh%np)
408
409 ! the Laplacian is a real operator
410 call dnl_operator_operate_diag(der%lapl, lapl)
411
412 pop_sub(derivatives_lapl_diag)
413
414 end subroutine derivatives_lapl_diag
415
416
417 ! ---------------------------------------------------------
418 subroutine derivatives_get_stencil_grad(der)
419 type(derivatives_t), intent(inout) :: der
420
421
422 integer :: ii
423 character :: dir_label
424
426
427 assert(associated(der%grad))
428
429 ! initialize nl operator
430 do ii = 1, der%dim
431 dir_label = ' '
432 if (ii < 5) dir_label = index2axis(ii)
433
434 call nl_operator_init(der%grad(ii), "Gradient "//dir_label)
435
436 ! create stencil
437 select case (der%stencil_type)
438 case (der_star, der_variational)
439 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
440 case (der_cube)
441 call stencil_cube_get_grad(der%grad(ii)%stencil, der%dim, der%order)
442 case (der_starplus)
443 call stencil_starplus_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
444 case (der_stargeneral)
445 ! use the simple star stencil
446 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
447 end select
448 end do
449
451
452 end subroutine derivatives_get_stencil_grad
453
454 ! ---------------------------------------------------------
486 subroutine derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
487 type(derivatives_t), intent(inout) :: der
488 type(namespace_t), intent(in) :: namespace
489 class(space_t), intent(in) :: space
490 class(mesh_t), target, intent(in) :: mesh
491 real(real64), optional, intent(in) :: qvector(:)
493 logical, optional, intent(in) :: regenerate
494 logical, optional, intent(in) :: verbose
495
496 integer, allocatable :: polynomials(:,:)
497 real(real64), allocatable :: rhs(:,:)
498 integer :: i
499 logical :: const_w_
500 character(len=32) :: name
501 type(nl_operator_t) :: auxop
502 integer :: np_zero_bc
503
504 push_sub(derivatives_build)
505
506 if (.not. optional_default(regenerate, .false.)) then
507 call boundaries_init(der%boundaries, namespace, space, mesh, qvector)
508 end if
509
510 assert(allocated(der%op))
511 assert(der%stencil_type >= der_star .and. der%stencil_type <= der_stargeneral)
512 assert(.not.(der%stencil_type == der_variational .and. mesh%use_curvilinear))
513
514 der%mesh => mesh ! make a pointer to the underlying mesh
515
516 const_w_ = .true.
517
518 ! need non-constant weights for curvilinear and scattering meshes
519 if (mesh%use_curvilinear) const_w_ = .false.
520
521 np_zero_bc = 0
522
523 ! build operators
524 do i = 1, der%dim+1
525 if (optional_default(regenerate, .false.)) then
526 safe_deallocate_a(der%op(i)%w)
527 end if
528 call nl_operator_build(space, mesh, der%op(i), der%mesh%np, const_w = const_w_, &
529 regenerate=regenerate)
530 np_zero_bc = max(np_zero_bc, nl_operator_np_zero_bc(der%op(i)))
531 end do
532
533 assert(np_zero_bc > mesh%np .and. np_zero_bc <= mesh%np_part)
534
535 select case (der%stencil_type)
536
537 case (der_star, der_starplus, der_stargeneral) ! Laplacian and gradient have different stencils
538 do i = 1, der%dim + 1
539 safe_allocate(polynomials(1:der%dim, 1:der%op(i)%stencil%size))
540 safe_allocate(rhs(1:der%op(i)%stencil%size, 1))
541
542 if (i <= der%dim) then ! gradient
543 call stencil_stars_pol_grad(der%stencil_type, der%dim, i, der%order, polynomials)
544 call get_rhs_grad(der, polynomials, i, rhs(:,1))
545 name = index2axis(i) // "-gradient"
546 else ! Laplacian
547 call stencil_stars_pol_lapl(der%stencil_type, der%op(der%dim+1)%stencil, der%dim, der%order, polynomials)
548 call get_rhs_lapl(der, polynomials, rhs(:,1))
549 name = "Laplacian"
550 end if
551
552 call derivatives_make_discretization(namespace, der%dim, der%periodic_dim, der%mesh, der%masses, polynomials, rhs, 1, &
553 der%op(i:i), name, verbose=verbose)
554 safe_deallocate_a(polynomials)
555 safe_deallocate_a(rhs)
556 end do
557
558 case (der_cube)
559 ! Laplacian and gradient have similar stencils, so use one call to derivatives_make_discretization
560 ! to solve the linear equation once for several right-hand sides
561 safe_allocate(polynomials(1:der%dim, 1:der%op(1)%stencil%size))
562 safe_allocate(rhs(1:der%op(1)%stencil%size, 1:der%dim + 1))
563 call stencil_cube_polynomials_lapl(der%dim, der%order, polynomials)
564
565 do i = 1, der%dim
566 call get_rhs_grad(der, polynomials, i, rhs(:,i))
567 end do
568 call get_rhs_lapl(der, polynomials, rhs(:, der%dim+1))
569
570 name = "derivatives"
571 call derivatives_make_discretization(namespace, der%dim, der%periodic_dim, der%mesh, der%masses, polynomials, rhs, &
572 der%dim+1, der%op(:), name, verbose=verbose)
573
574 safe_deallocate_a(polynomials)
575 safe_deallocate_a(rhs)
576
577 case (der_variational)
578 ! we have the explicit coefficients
579 call stencil_variational_coeff_lapl(der%dim, der%order, mesh%spacing, der%lapl, alpha = der%lapl_cutoff)
580 end select
581
582
583 ! Here the Laplacian is forced to be self-adjoint, and the gradient to be skew-self-adjoint
584 if (mesh%use_curvilinear) then
585 ! The nl_operator_copy routine has an assert
586 if (accel_is_enabled()) then
587 call messages_write('Curvilinear coordinates on GPUs is not implemented')
588 call messages_fatal(namespace=namespace)
589 end if
590
591 do i = 1, der%dim
592 call nl_operator_init(auxop, "auxop")
593 call nl_operator_adjoint(der%grad(i), auxop, der%mesh, self_adjoint=.false.)
594
595 call nl_operator_end(der%grad(i))
596 call nl_operator_copy(der%grad(i), auxop)
597 call nl_operator_end(auxop)
598 end do
599 call nl_operator_init(auxop, "auxop")
600 call nl_operator_adjoint(der%lapl, auxop, der%mesh, self_adjoint=.true.)
601
602 call nl_operator_end(der%lapl)
603 call nl_operator_copy(der%lapl, auxop)
604 call nl_operator_end(auxop)
605 end if
606
607 pop_sub(derivatives_build)
608
609 contains
610 subroutine stencil_stars_pol_grad(stencil_type, dim, direction, order, polynomials)
611 integer, intent(in) :: stencil_type
612 integer, intent(in) :: dim
613 integer, intent(in) :: direction
614 integer, intent(in) :: order
615 integer, intent(inout) :: polynomials(:, :)
616
617 select case (der%stencil_type)
618 case (der_star, der_stargeneral)
619 call stencil_star_polynomials_grad(direction, order, polynomials)
620 case (der_starplus)
621 call stencil_starplus_pol_grad(dim, direction, order, polynomials)
622 end select
623 end subroutine stencil_stars_pol_grad
624
625 subroutine stencil_stars_pol_lapl(stencil_type, stencil, dim, order, polynomials)
626 integer, intent(in) :: stencil_type
627 type(stencil_t), intent(in) :: stencil
628 integer, intent(in) :: dim
629 integer, intent(in) :: order
630 integer, intent(inout) :: polynomials(:, :)
631
632 select case (der%stencil_type)
633 case (der_star)
634 call stencil_star_polynomials_lapl(dim, order, polynomials)
635 case (der_starplus)
636 call stencil_starplus_pol_lapl(dim, order, polynomials)
637 case (der_stargeneral)
638 call stencil_stargeneral_pol_lapl(stencil, dim, order, polynomials)
639 end select
640 end subroutine stencil_stars_pol_lapl
641
642 end subroutine derivatives_build
643
644 ! ---------------------------------------------------------
645 subroutine get_rhs_lapl(der, polynomials, rhs)
646 type(derivatives_t), intent(in) :: der
647 integer, intent(in) :: polynomials(:,:)
648 real(real64), intent(out) :: rhs(:)
649
650 integer :: i, j, k
651 real(real64) :: f(1:der%dim, 1:der%dim)
652 integer :: powers(0:2)
653
654 push_sub(get_rhs_lapl)
655
656 ! assume orthogonal basis as default (i.e. for curvilinear coordinates)
657 f = m_zero
658 do i = 1, der%dim
659 f(i, i) = m_one
660 end do
661
662 select type (coord => der%mesh%coord_system)
663 class is (affine_coordinates_t)
664 f(1:der%dim, 1:der%dim) = matmul(coord%basis%change_of_basis_matrix(1:der%dim, 1:der%dim), &
665 transpose(coord%basis%change_of_basis_matrix(1:der%dim, 1:der%dim)))
666 class is (curv_gygi_t)
667 class is (curv_briggs_t)
668 class is (curv_modine_t)
669 class default
670 message(1) = "Weight computation not implemented for the coordinate system chosen."
671 call messages_fatal(1)
672 end select
673
674 ! find right-hand side for operator
675 rhs(:) = m_zero
676 do j = 1, size(polynomials, dim=2)
677 ! count the powers of the polynomials
678 powers = 0
679 do i = 1, der%dim
680 if (polynomials(i, j) <= 2) then
681 powers(polynomials(i, j)) = powers(polynomials(i, j)) + 1
682 end if
683 end do
684
685 ! find all polynomials for which exactly one term is quadratic
686 ! for these, the Laplacian on the polynomial is 2*F(i, i)
687 if (powers(2) == 1 .and. powers(0) == der%dim - 1) then
688 do i = 1, der%dim
689 if (polynomials(i, j) == 2) then
690 rhs(j) = m_two*f(i, i)
691 end if
692 end do
693 end if
694 ! find all polynomials for which exactly two terms are linear
695 ! for these, the Laplacian on the polynomial is F(i, k) + F(k, i)
696 if (powers(1) == 2 .and. powers(0) == der%dim - 2) then
697 do i = 1, der%dim
698 if (polynomials(i, j) == 1) then
699 do k = i+1, der%dim
700 if (polynomials(k, j) == 1) then
701 rhs(j) = f(i, k) + f(k, i)
702 end if
703 end do
704 end if
705 end do
706 end if
707 end do
708
709 pop_sub(get_rhs_lapl)
710 end subroutine get_rhs_lapl
711
712 ! ---------------------------------------------------------
713 subroutine get_rhs_grad(der, polynomials, dir, rhs)
714 type(derivatives_t), intent(in) :: der
715 integer, intent(in) :: polynomials(:,:)
716 integer, intent(in) :: dir
717 real(real64), intent(out) :: rhs(:)
719 integer :: j, k
720 logical :: this_one
721
722 push_sub(get_rhs_grad)
723
724 ! find right-hand side for operator
725 rhs(:) = m_zero
726 do j = 1, der%grad(dir)%stencil%size
727 this_one = .true.
728 do k = 1, der%dim
729 if (k == dir .and. polynomials(k, j) /= 1) this_one = .false.
730 if (k /= dir .and. polynomials(k, j) /= 0) this_one = .false.
731 end do
732 if (this_one) rhs(j) = m_one
733 end do
734
735 pop_sub(get_rhs_grad)
736 end subroutine get_rhs_grad
737
739 ! ---------------------------------------------------------
740 subroutine derivatives_make_discretization(namespace, dim, periodic_dim, mesh, masses, pol, rhs, nderiv, op, name, &
741 verbose)
742 type(namespace_t), intent(in) :: namespace
743 integer, intent(in) :: dim
744 integer, intent(in) :: periodic_dim
745 type(mesh_t), intent(in) :: mesh
746 real(real64), intent(in) :: masses(:)
747 integer, intent(in) :: pol(:,:)
748 integer, intent(in) :: nderiv
749 real(real64), contiguous, intent(inout) :: rhs(:,:)
750 type(nl_operator_t), intent(inout) :: op(:)
751 character(len=32), intent(in) :: name
752 logical, optional, intent(in) :: verbose
753
754 integer :: p, p_max, i, j, k, pow_max
755 real(real64) :: x(dim)
756 real(real64), allocatable :: mat(:,:), sol(:,:), powers(:,:)
757 logical :: transform_to_cartesian
758
760
761 safe_allocate(mat(1:op(1)%stencil%size, 1:op(1)%stencil%size))
762 safe_allocate(sol(1:op(1)%stencil%size, 1:nderiv))
763
764 if (optional_default(verbose, .true.)) then
765 message(1) = 'Info: Generating weights for finite-difference discretization of ' // trim(name)
766 call messages_info(1, namespace=namespace)
767 end if
768
769 select type (coord => mesh%coord_system)
770 class is (affine_coordinates_t)
771 transform_to_cartesian = .false.
772 class is (curv_gygi_t)
773 transform_to_cartesian = .true.
774 class is (curv_briggs_t)
775 transform_to_cartesian = .true.
776 class is (curv_modine_t)
777 transform_to_cartesian = .true.
778 class default
779 message(1) = "Weight computation not implemented for the coordinate system chosen."
780 call messages_fatal(1)
781 end select
782
783 ! use to generate power lookup table
784 pow_max = maxval(pol)
785 safe_allocate(powers(1:dim, 0:pow_max))
786 powers(:,:) = m_zero
787 powers(:,0) = m_one
788
789 p_max = op(1)%np
790 if (op(1)%const_w) p_max = 1
791
792 do p = 1, p_max
793 ! first polynomial is just a constant
794 mat(1,:) = m_one
795 ! i indexes the point in the stencil
796 do i = 1, op(1)%stencil%size
797 if (mesh%use_curvilinear) then
798 x = mesh%x(p + op(1)%ri(i, op(1)%rimap(p)), :) - mesh%x(p, :)
799 else
800 x = real(op(1)%stencil%points(:, i), real64) *mesh%spacing
801 ! transform to Cartesisan coordinates only for curvilinear meshes
802 if (transform_to_cartesian) then
803 x = mesh%coord_system%to_cartesian(x)
804 end if
805 end if
807 ! NB: these masses are applied on the cartesian directions. Should add a check for non-orthogonal axes
808 x = x*sqrt(masses)
809
810 ! calculate powers
811 powers(:, 1) = x
812 do k = 2, pow_max
813 powers(:, k) = x*powers(:, k-1)
814 end do
815
816 ! generate the matrix
817 ! j indexes the polynomial being used
818 do j = 2, op(1)%stencil%size
819 mat(j, i) = powers(1, pol(1, j))
820 do k = 2, dim
821 mat(j, i) = mat(j, i)*powers(k, pol(k, j))
822 end do
823 end do
824 end do ! loop over i = point in stencil
825
826 ! linear problem to solve for derivative weights:
827 ! mat * sol = rhs
828 call lalg_linsyssolve(op(1)%stencil%size, nderiv, mat, rhs, sol)
829
830 ! for the cube stencil, all derivatives are calculated at once, so assign
831 ! the correct solution to each operator
832 do i = 1, nderiv
833 op(i)%w(:, p) = sol(:, i)
834 end do
835
836 end do ! loop over points p
837
838 do i = 1, nderiv
840 end do
841
842 ! In case of constant weights, we store the weights of the Laplacian on the GPU, as this
843 ! saves many unecessary transfers
844 do i = 1, nderiv
847 end do
848
849
850 safe_deallocate_a(mat)
851 safe_deallocate_a(sol)
852 safe_deallocate_a(powers)
853
856
857#ifdef HAVE_MPI
858 ! ---------------------------------------------------------
859 logical function derivatives_overlap(this) result(overlap)
860 type(derivatives_t), intent(in) :: this
861
862 push_sub(derivatives_overlap)
863
864 overlap = this%comm_method /= blocking
865
866 pop_sub(derivatives_overlap)
867 end function derivatives_overlap
868#endif
869
870 ! ---------------------------------------------------------
871 subroutine derivatives_get_lapl(this, namespace, op, space, name, order)
872 type(derivatives_t), intent(in) :: this
873 type(namespace_t), intent(in) :: namespace
874 type(nl_operator_t), intent(inout) :: op(:)
875 class(space_t), intent(in) :: space
876 character(len=32), intent(in) :: name
877 integer, intent(in) :: order
878
879 integer, allocatable :: polynomials(:,:)
880 real(real64), allocatable :: rhs(:,:)
881
882 push_sub(derivatives_get_lapl)
883
884 call nl_operator_init(op(1), name)
885 if (.not. this%mesh%coord_system%orthogonal) then
886 call stencil_stargeneral_get_arms(op(1)%stencil, this%dim, this%mesh%coord_system)
887 call stencil_stargeneral_get_lapl(op(1)%stencil, this%dim, order)
888 else
889 call stencil_star_get_lapl(op(1)%stencil, this%dim, order)
890 end if
891 call nl_operator_build(space, this%mesh, op(1), this%mesh%np, const_w = .not. this%mesh%use_curvilinear)
892
893 !At the moment this code is almost copy-pasted from derivatives_build.
894 safe_allocate(polynomials(1:this%dim, 1:op(1)%stencil%size))
895 safe_allocate(rhs(1:op(1)%stencil%size, 1))
896 if (.not. this%mesh%coord_system%orthogonal) then
897 call stencil_stargeneral_pol_lapl(op(1)%stencil, this%dim, order, polynomials)
898 else
899 call stencil_star_polynomials_lapl(this%dim, order, polynomials)
900 end if
901 call get_rhs_lapl(this, polynomials, rhs(:, 1))
902 call derivatives_make_discretization(namespace, this%dim, this%periodic_dim, this%mesh, this%masses, &
903 polynomials, rhs, 1, op(1:1), name)
904 safe_deallocate_a(polynomials)
905 safe_deallocate_a(rhs)
906
907 pop_sub(derivatives_get_lapl)
908 end subroutine derivatives_get_lapl
909
910 ! ---------------------------------------------------------
923 function derivatives_get_inner_boundary_mask(this) result(mask)
924 type(derivatives_t), intent(in) :: this
925
926 logical :: mask(1:this%mesh%np)
927 integer :: ip, is, index
928
929 mask = .false.
930 ! Loop through all points in the grid
931 do ip = 1, this%mesh%np
932 ! For each of them, loop through all points in the stencil
933 do is = 1, this%lapl%stencil%size
934 ! Get the index of the point obtained as: grid_point + displament_due_to_stencil
935 index = nl_operator_get_index(this%lapl, is, ip)
936 ! Check whether the displaced point if outsude the grid. Is so, it belongs to the mask
937 if (index > this%mesh%np + this%mesh%pv%np_ghost) then
938 mask(ip) = .true.
939 exit
940 end if
941 end do
942 end do
943
945
946 ! ---------------------------------------------------------
951 real(real64) function derivatives_lapl_get_max_eigenvalue(this)
952 type(derivatives_t), intent(in) :: this
953
954 integer :: i
955
956 push_sub(derivatives_lapl_get_max_eigenvalue)
957
958 derivatives_lapl_get_max_eigenvalue = m_zero
959 if ((this%stencil_type == der_star .or. this%stencil_type == der_stargeneral) &
960 .and. .not. this%mesh%use_curvilinear) then
961 ! use Fourier transform of stencil evaluated at the maximum phase
962 do i = 1, this%lapl%stencil%size
963 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
964 (-1)**maxval(abs(this%lapl%stencil%points(:, i)))*this%lapl%w(i, 1)
965 end do
966 derivatives_lapl_get_max_eigenvalue = abs(derivatives_lapl_get_max_eigenvalue)
967 else
968 ! use upper bound from continuum for other stencils
969 do i = 1, this%dim
970 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
971 m_pi**2/this%mesh%spacing(i)**2
972 end do
973 end if
974
975 pop_sub(derivatives_lapl_get_max_eigenvalue)
977
978
979#include "undef.F90"
980#include "real.F90"
981#include "derivatives_inc.F90"
982
983#include "undef.F90"
984#include "complex.F90"
985#include "derivatives_inc.F90"
986
987end module derivatives_oct_m
988
989!! Local Variables:
990!! mode: f90
991!! coding: utf-8
992!! 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:2067
pure logical function, public accel_is_enabled()
Definition: accel.F90:400
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:189
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:185
real(real64), parameter, public m_one
Definition: global.F90:188
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:1057
subroutine, public messages_info(no_lines, iunit, verbose_limit, stress, all_nodes, namespace)
Definition: messages.F90:624
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:420
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
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
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)