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
121
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
145 logical, private :: stencil_primitive_coordinates
146
147 real(real64), allocatable :: masses(:)
148
151 real(real64), private :: lapl_cutoff = m_zero
152
153 type(nl_operator_t), allocatable, private :: op(:)
155 type(nl_operator_t), pointer :: lapl => null()
156 type(nl_operator_t), pointer :: grad(:) => null()
157
158 integer, allocatable :: n_ghost(:)
159!#if defined(HAVE_MPI)
160 integer, private :: comm_method = 0
161!#endif
162 type(derivatives_t), pointer :: finer => null()
163 type(derivatives_t), pointer :: coarser => null()
164 type(transfer_table_t), pointer :: to_finer => null()
165 type(transfer_table_t), pointer :: to_coarser => null()
166 end type derivatives_t
167
170 private
171!#ifdef HAVE_MPI
172 type(par_vec_handle_batch_t) :: pv_h
173!#endif
174 type(derivatives_t), pointer :: der
175 type(nl_operator_t), pointer :: op
176 type(batch_t), pointer :: ff
177 type(batch_t), pointer :: opff
178 logical :: ghost_update
179 logical :: factor_present
180 real(real64) :: factor
182
183 type(accel_kernel_t) :: kernel_uvw_xyz, kernel_dcurl, kernel_zcurl
184
185contains
186
187 ! ---------------------------------------------------------
188 subroutine derivatives_init(der, namespace, space, coord_system, order)
189 type(derivatives_t), target, intent(inout) :: der
190 type(namespace_t), intent(in) :: namespace
191 class(space_t), intent(in) :: space
192 class(coordinate_system_t), intent(in) :: coord_system
193 integer, optional, intent(in) :: order
194
195 integer :: idir
196 integer :: default_stencil
197 character(len=40) :: flags
198 logical :: stencil_primitive_coordinates
199
200 push_sub(derivatives_init)
201
202 ! Non-orthogonal curvilinear coordinates are currently not implemented
203 assert(.not. coord_system%local_basis .or. coord_system%orthogonal)
204
205 ! copy this value to my structure
206 der%dim = space%dim
207 der%periodic_dim = space%periodic_dim
208
209 !%Variable DerivativesStencil
210 !%Type integer
211 !%Default stencil_star
212 !%Section Mesh::Derivatives
213 !%Description
214 !% Decides what kind of stencil is used, <i>i.e.</i> which points, around
215 !% each point in the mesh, are the neighboring points used in the
216 !% expression of the differential operator.
217 !%
218 !% If curvilinear coordinates are to be used, then only the <tt>stencil_starplus</tt>
219 !% or the <tt>stencil_cube</tt> may be used. We only recommend the <tt>stencil_starplus</tt>,
220 !% since the cube typically needs far too much memory.
221 !%Option stencil_star 1
222 !% A star around each point (<i>i.e.</i>, only points on the axis).
223 !%Option stencil_variational 2
224 !% Same as the star, but with coefficients built in a different way.
225 !%Option stencil_cube 3
226 !% A cube of points around each point.
227 !%Option stencil_starplus 4
228 !% The star, plus a number of off-axis points.
229 !%Option stencil_stargeneral 5
230 !% The general star. Default for non-orthogonal grids.
231 !%End
232 default_stencil = der_star
233 if (coord_system%local_basis) default_stencil = der_starplus
234 if (.not. coord_system%orthogonal) default_stencil = der_stargeneral
236 call parse_variable(namespace, 'DerivativesStencil', default_stencil, der%stencil_type)
238 if (.not. varinfo_valid_option('DerivativesStencil', der%stencil_type)) then
239 call messages_input_error(namespace, 'DerivativesStencil')
240 end if
241 call messages_print_var_option("DerivativesStencil", der%stencil_type, namespace=namespace)
243 if (coord_system%local_basis .and. der%stencil_type < der_cube) call messages_input_error(namespace, 'DerivativesStencil')
244 if (der%stencil_type == der_variational) then
245 !%Variable DerivativesLaplacianFilter
246 !%Type float
247 !%Default 1.0
248 !%Section Mesh::Derivatives
249 !%Description
250 !% Undocumented
251 !%End
252 call parse_variable(namespace, 'DerivativesLaplacianFilter', m_one, der%lapl_cutoff)
253 end if
254
255 !%Variable DerivativesOrder
256 !%Type integer
257 !%Default 4
258 !%Section Mesh::Derivatives
259 !%Description
260 !% This variable gives the discretization order for the approximation of
261 !% the differential operators. This means, basically, that
262 !% <tt>DerivativesOrder</tt> points are used in each positive/negative
263 !% spatial direction, <i>e.g.</i> <tt>DerivativesOrder = 1</tt> would give
264 !% the well-known three-point formula in 1D.
265 !% The number of points actually used for the Laplacian
266 !% depends on the stencil used. Let <math>O</math> = <tt>DerivativesOrder</tt>, and <math>d</math> = <tt>Dimensions</tt>.
267 !% <ul>
268 !% <li> <tt>stencil_star</tt>: <math>2 O d + 1</math>
269 !% <li> <tt>stencil_cube</tt>: <math>(2 O + 1)^d</math>
270 !% <li> <tt>stencil_starplus</tt>: <math>2 O d + 1 + n</math> with <i>n</i> being 8
271 !% in 2D and 24 in 3D.
272 !% </ul>
273 !%End
274 call parse_variable(namespace, 'DerivativesOrder', 4, der%order)
275 ! overwrite order if given as argument
276 if (present(order)) then
277 der%order = order
278 end if
279
280#ifdef HAVE_MPI
281 !%Variable ParallelizationOfDerivatives
282 !%Type integer
283 !%Default non_blocking
284 !%Section Execution::Parallelization
285 !%Description
286 !% This option selects how the communication of mesh boundaries is performed.
287 !%Option blocking 1
288 !% Blocking communication.
289 !%Option non_blocking 2
290 !% Communication is based on non-blocking point-to-point communication.
291 !%End
292
293 call parse_variable(namespace, 'ParallelizationOfDerivatives', non_blocking, der%comm_method)
294
295 if (.not. varinfo_valid_option('ParallelizationOfDerivatives', der%comm_method)) then
296 call messages_input_error(namespace, 'ParallelizationOfDerivatives')
297 end if
298
299 call messages_obsolete_variable(namespace, 'OverlapDerivatives', 'ParallelizationOfDerivatives')
300#endif
301
302 !%Variable StencilPrimitiveCoordinates
303 !%Type logical
304 !%Section Mesh::Derivatives
305 !%Description
306 !% This variable controls the method for generating the stencil weights for the Laplacian.
307 !% For the gradient, the weights are always computed for primitive coordinates.
308 !% If set to yes, primitive coordinates are used for the polynomials and the right-hand side
309 !% of the Laplacian is computed using the metric tensor and the trace of the Hessian.
310 !% If set to no, Cartesian coordinates are used for the polynomials and the right-hand side
311 !% of the Laplacian reduces to the Cartesian case.
312 !% For some non-orthogonal grids, using primitve coordinates is necessary becasuse the polynomials
313 !% become linearly dependent, thus the corresponding matrix cannot be inverted. For some curvilinear
314 !% coordinate systems, using Cartesian coordinates is more accurate.
315 !%
316 !% By default, use primitve coordinates except for curvilinear meshes.
317 !%End
318 stencil_primitive_coordinates = .not. coord_system%local_basis
319 call parse_variable(namespace, 'StencilPrimitiveCoordinates', stencil_primitive_coordinates, der%stencil_primitive_coordinates)
320
321 ! if needed, der%masses should be initialized in modelmb_particles_init
322 safe_allocate(der%masses(1:space%dim))
323 der%masses = m_one
324
325 ! construct lapl and grad structures
326 safe_allocate(der%op(1:der%dim + 1))
327 der%grad => der%op
328 der%lapl => der%op(der%dim + 1)
329
330 call derivatives_get_stencil_lapl(der, der%lapl, space, coord_system)
332
333 ! find out how many ghost points we need in each dimension
334 safe_allocate(der%n_ghost(1:der%dim))
335 der%n_ghost(:) = 0
336 do idir = 1, der%dim
337 der%n_ghost(idir) = maxval(abs(der%lapl%stencil%points(idir, :)))
338 end do
339
340 nullify(der%coarser)
341 nullify(der%finer)
342 nullify(der%to_coarser)
343 nullify(der%to_finer)
344
345 if (accel_is_enabled()) then
346 ! Check if we can build the uvw_to_xyz kernel
347 select type (coord_system)
348 type is (cartesian_t)
349 ! In this case one does not need to call the kernel, so all is fine
350 class default
351 if (der%dim > 3) then
352 message(1) = "Calculation of derivatives on the GPU with dimension > 3 are only implemented for Cartesian coordinates."
353 call messages_fatal(1, namespace=namespace)
354 else
355 write(flags, '(A,I1.1)') ' -DDIMENSION=', der%dim
356 call accel_kernel_build(kernel_uvw_xyz, 'uvw_to_xyz.cl', 'uvw_to_xyz', flags)
357 end if
358 end select
359 call accel_kernel_build(kernel_dcurl, 'curl.cl', 'dcurl', flags = '-DRTYPE_DOUBLE')
360 call accel_kernel_build(kernel_zcurl, 'curl.cl', 'zcurl', flags = '-DRTYPE_COMPLEX')
361 end if
362
363 pop_sub(derivatives_init)
364 end subroutine derivatives_init
365
366
367 ! ---------------------------------------------------------
368 subroutine derivatives_end(der)
369 type(derivatives_t), intent(inout) :: der
370
371 integer :: idim
372
373 push_sub(derivatives_end)
374
375 assert(allocated(der%op))
376
377 do idim = 1, der%dim+1
378 call nl_operator_end(der%op(idim))
379 end do
380
381 safe_deallocate_a(der%masses)
382
383 safe_deallocate_a(der%n_ghost)
384
385 safe_deallocate_a(der%op)
386 nullify(der%lapl, der%grad)
387
388 nullify(der%coarser)
389 nullify(der%finer)
390 nullify(der%to_coarser)
391 nullify(der%to_finer)
392
393 call boundaries_end(der%boundaries)
394
395 pop_sub(derivatives_end)
396 end subroutine derivatives_end
397
398
399 ! ---------------------------------------------------------
400 subroutine derivatives_get_stencil_lapl(der, lapl, space, coord_system, name, order)
401 type(derivatives_t), intent(in) :: der
402 type(nl_operator_t), intent(inout) :: lapl
403 class(space_t), intent(in) :: space
404 class(coordinate_system_t), intent(in) :: coord_system
405 character(len=80), optional, intent(in) :: name
406 integer, optional, intent(in) :: order
407
408 character(len=80) :: name_
409 integer :: order_
410
412
413 name_ = optional_default(name, "Laplacian")
414 order_ = optional_default(order, der%order)
415
416 ! initialize nl operator
417 call nl_operator_init(lapl, name_)
418
419 ! create stencil
420 select case (der%stencil_type)
421 case (der_star, der_variational)
422 call stencil_star_get_lapl(lapl%stencil, der%dim, order_)
423 case (der_cube)
424 call stencil_cube_get_lapl(lapl%stencil, der%dim, order_)
425 case (der_starplus)
426 call stencil_starplus_get_lapl(lapl%stencil, der%dim, order_)
427 case (der_stargeneral)
428 call stencil_stargeneral_get_arms(lapl%stencil, space%dim, coord_system)
429 call stencil_stargeneral_get_lapl(lapl%stencil, der%dim, order_)
430 end select
431
433 end subroutine derivatives_get_stencil_lapl
434
435
436 ! ---------------------------------------------------------
438 subroutine derivatives_lapl_diag(der, lapl)
439 type(derivatives_t), intent(in) :: der
440 real(real64), intent(out) :: lapl(:)
442 push_sub(derivatives_lapl_diag)
443
444 assert(ubound(lapl, dim=1) >= der%mesh%np)
445
446 ! the Laplacian is a real operator
447 call dnl_operator_operate_diag(der%lapl, lapl)
448
449 pop_sub(derivatives_lapl_diag)
450
451 end subroutine derivatives_lapl_diag
452
453
454 ! ---------------------------------------------------------
455 subroutine derivatives_get_stencil_grad(der)
456 type(derivatives_t), intent(inout) :: der
457
458
459 integer :: ii
460 character :: dir_label
461
463
464 assert(associated(der%grad))
465
466 ! initialize nl operator
467 do ii = 1, der%dim
468 dir_label = ' '
469 if (ii < 5) dir_label = index2axis(ii)
470
471 call nl_operator_init(der%grad(ii), "Gradient "//dir_label)
472
473 ! create stencil
474 select case (der%stencil_type)
475 case (der_star, der_variational)
476 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
477 case (der_cube)
478 call stencil_cube_get_grad(der%grad(ii)%stencil, der%dim, der%order)
479 case (der_starplus)
480 call stencil_starplus_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
481 case (der_stargeneral)
482 ! use the simple star stencil
483 call stencil_star_get_grad(der%grad(ii)%stencil, der%dim, ii, der%order)
484 end select
485 end do
486
488
489 end subroutine derivatives_get_stencil_grad
490
491 ! ---------------------------------------------------------
537 subroutine derivatives_build(der, namespace, space, mesh, qvector, regenerate, verbose)
538 type(derivatives_t), intent(inout) :: der
539 type(namespace_t), intent(in) :: namespace
540 class(space_t), intent(in) :: space
541 class(mesh_t), target, intent(in) :: mesh
542 real(real64), optional, intent(in) :: qvector(:)
544 logical, optional, intent(in) :: regenerate
545 logical, optional, intent(in) :: verbose
546
547 integer :: i
548 logical :: const_w_
549 integer :: np_zero_bc
550
551 push_sub(derivatives_build)
552
553 if (.not. optional_default(regenerate, .false.)) then
554 call boundaries_init(der%boundaries, namespace, space, mesh, qvector)
555 end if
556
557 assert(allocated(der%op))
558 assert(der%stencil_type >= der_star .and. der%stencil_type <= der_stargeneral)
559 assert(.not.(der%stencil_type == der_variational .and. mesh%use_curvilinear))
560
561 der%mesh => mesh ! make a pointer to the underlying mesh
562
563 const_w_ = .true.
564
565 ! need non-constant weights for curvilinear and scattering meshes
566 if (mesh%use_curvilinear) const_w_ = .false.
567
568 np_zero_bc = 0
569
570 ! build operators
571 do i = 1, der%dim+1
572 if (optional_default(regenerate, .false.)) then
573 safe_deallocate_a(der%op(i)%w)
574 end if
575 call nl_operator_build(space, mesh, der%op(i), der%mesh%np, const_w = const_w_, &
576 regenerate=regenerate)
577 np_zero_bc = max(np_zero_bc, nl_operator_np_zero_bc(der%op(i)))
578 end do
579
580 assert(np_zero_bc > mesh%np .and. np_zero_bc <= mesh%np_part)
581
582 select case (der%stencil_type)
583
584 case (der_star, der_starplus, der_stargeneral) ! Laplacian and gradient have different stencils
585 do i = 1, der%dim + 1
586
587 call derivatives_make_discretization(namespace, der, 1, i, der%op(i:i), verbose=verbose)
588 end do
589
590 case (der_cube)
591 ! gradients have the same stencils, so use one call to derivatives_make_discretization
592 ! to solve the linear equation once for several right-hand sides
593 call derivatives_make_discretization(namespace, der, der%dim, der%dim, der%op(:), verbose=verbose)
594 ! the polynomials are evaluated differently for the Laplacian
595 call derivatives_make_discretization(namespace, der, 1, der%dim+1, der%op(der%dim+1:der%dim+1), verbose=verbose)
596
597 case (der_variational)
598 ! we have the explicit coefficients
599 call stencil_variational_coeff_lapl(der%dim, der%order, mesh%spacing, der%lapl, alpha = der%lapl_cutoff)
600 end select
601
602 pop_sub(derivatives_build)
603
604 end subroutine derivatives_build
605
606 ! ---------------------------------------------------------
607 subroutine stencil_pol_grad(stencil_type, dim, direction, order, polynomials)
608 integer, intent(in) :: stencil_type
609 integer, intent(in) :: dim
610 integer, intent(in) :: direction
611 integer, intent(in) :: order
612 integer, intent(inout) :: polynomials(:, :)
613
614 select case (stencil_type)
615 case (der_star, der_stargeneral)
616 call stencil_star_polynomials_grad(direction, order, polynomials)
617 case (der_starplus)
618 call stencil_starplus_pol_grad(dim, direction, order, polynomials)
619 case (der_cube)
620 ! same stencil for gradient and Laplacian in this case
621 call stencil_cube_polynomials_lapl(dim, order, polynomials)
622 end select
623 end subroutine stencil_pol_grad
624
625 ! ---------------------------------------------------------
626 subroutine stencil_pol_lapl(stencil_type, stencil, dim, order, polynomials)
627 integer, intent(in) :: stencil_type
628 type(stencil_t), intent(in) :: stencil
629 integer, intent(in) :: dim
630 integer, intent(in) :: order
631 integer, intent(inout) :: polynomials(:, :)
632
633 select case (stencil_type)
634 case (der_star)
635 call stencil_star_polynomials_lapl(dim, order, polynomials)
636 case (der_starplus)
637 call stencil_starplus_pol_lapl(dim, order, polynomials)
638 case (der_stargeneral)
639 call stencil_stargeneral_pol_lapl(stencil, dim, order, polynomials)
640 case (der_cube)
641 call stencil_cube_polynomials_lapl(dim, order, polynomials)
642 end select
643 end subroutine stencil_pol_lapl
644
645 ! ---------------------------------------------------------
646 subroutine get_rhs_lapl(coord_system, polynomials, chi, rhs, stencil_primitive_coordinates)
647 class(coordinate_system_t), intent(in) :: coord_system
648 integer, intent(in) :: polynomials(:,:)
649 real(real64), intent(in) :: chi(:)
650 real(real64), intent(out) :: rhs(:)
651 logical, intent(in) :: stencil_primitive_coordinates
652
653 integer :: i, j, k, dim
654 real(real64) :: metric_inverse(1:size(polynomials, dim=1), 1:size(polynomials, dim=1))
655 real(real64) :: hessian_trace(1:size(polynomials, dim=1))
656 integer :: powers(0:2)
657
658 push_sub(get_rhs_lapl)
659
660 dim = size(polynomials, dim=1)
661
662 if (stencil_primitive_coordinates) then
663 ! inverse metric and trace of Hessian in primitive coordinates
664 metric_inverse = coord_system%metric_inverse(chi)
665 hessian_trace = coord_system%trace_hessian(chi)
666 else
667 ! inverse metric and trace of Hessian in Cartesian coordinates
668 metric_inverse = m_zero
669 do i = 1, dim
670 metric_inverse(i, i) = m_one
671 end do
672 hessian_trace = m_zero
673 end if
674
675 ! find right-hand side for operator
676 rhs(:) = m_zero
677 do j = 1, size(polynomials, dim=2)
678 ! count the powers of the polynomials
679 powers = 0
680 do i = 1, dim
681 if (polynomials(i, j) <= 2) then
682 powers(polynomials(i, j)) = powers(polynomials(i, j)) + 1
683 end if
684 end do
685
686 ! find all polynomials for which exactly one term is quadratic
687 ! for these, the Laplacian on the polynomial is 2*metric_inverse(i, i)
688 if (powers(2) == 1 .and. powers(0) == dim - 1) then
689 do i = 1, dim
690 if (polynomials(i, j) == 2) then
691 rhs(j) = m_two*metric_inverse(i, i)
692 end if
693 end do
694 end if
695 ! find all polynomials for which exactly two terms are linear
696 ! for these, the Laplacian on the polynomial is metric_inverse(i, k) + metric_inverse(k, i)
697 if (powers(1) == 2 .and. powers(0) == dim - 2) then
698 do i = 1, dim
699 if (polynomials(i, j) == 1) then
700 do k = i+1, dim
701 if (polynomials(k, j) == 1) then
702 rhs(j) = metric_inverse(i, k) + metric_inverse(k, i)
703 end if
704 end do
705 end if
706 end do
707 end if
708 ! find all polynomials for which exactly one term is linear
709 ! for these, the Laplacian on the polynomial is hessian_trace(i)
710 ! this term is only non-zero for curvilinear coordinates with a varying metric tensor
711 if (powers(1) == 1 .and. powers(0) == dim - 1) then
712 do i = 1, dim
713 if (polynomials(i, j) == 1) then
714 rhs(j) = hessian_trace(i)
715 end if
716 end do
717 end if
718 end do
720 pop_sub(get_rhs_lapl)
721 end subroutine get_rhs_lapl
722
723 ! ---------------------------------------------------------
724 subroutine get_rhs_grad(polynomials, dir, rhs)
725 integer, intent(in) :: polynomials(:,:)
726 integer, intent(in) :: dir
727 real(real64), intent(out) :: rhs(:)
728
729 integer :: j, k, dim
730 logical :: this_one
731
732 push_sub(get_rhs_grad)
733
734 dim = size(polynomials, dim=1)
735
736 ! find right-hand side for operator
737 rhs(:) = m_zero
738 do j = 1, size(polynomials, dim=2)
739 this_one = .true.
740 do k = 1, dim
741 if (k == dir .and. polynomials(k, j) /= 1) this_one = .false.
742 if (k /= dir .and. polynomials(k, j) /= 0) this_one = .false.
743 end do
744 if (this_one) rhs(j) = m_one
745 end do
746
747 pop_sub(get_rhs_grad)
748 end subroutine get_rhs_grad
749
750
751 ! ---------------------------------------------------------
752 subroutine derivatives_make_discretization(namespace, der, nderiv, ideriv, op, name, verbose, order)
753 type(namespace_t), intent(in) :: namespace
754 type(derivatives_t), intent(in) :: der
755 integer, intent(in) :: nderiv
756 integer, intent(in) :: ideriv
757 type(nl_operator_t), intent(inout) :: op(:)
758 character(len=80), optional, intent(in) :: name
759 logical, optional, intent(in) :: verbose
760 integer, optional, intent(in) :: order
761
762 integer :: p, p_max, i, j, k, pow_max, order_
763 real(real64) :: x(der%dim)
764 real(real64), allocatable :: mat(:,:), sol(:,:), powers(:,:)
765 integer, allocatable :: pol(:,:)
766 real(real64), allocatable :: rhs(:,:)
767 character(len=80) :: name_
768
770
771 order_ = optional_default(order, der%order)
772
773 safe_allocate(rhs(1:op(1)%stencil%size, nderiv))
774 safe_allocate(pol(1:der%dim, 1:op(1)%stencil%size))
775 ! get polynomials
776 if (nderiv == 1) then
777 if (ideriv <= der%dim) then ! gradient
778 call stencil_pol_grad(der%stencil_type, der%dim, ideriv, order_, pol)
779 name_ = index2axis(ideriv) // "-gradient"
780 else ! Laplacian
781 call stencil_pol_lapl(der%stencil_type, op(1)%stencil, der%dim, order_, pol)
782 name_ = "Laplacian"
783 end if
784 else if (nderiv == der%dim) then
785 ! in this case, we compute the weights for the gradients at once
786 ! because they have the same stencils
787 ! this is only used for the cube stencil
788 name_ = "gradients"
789 call stencil_pol_grad(der%stencil_type, der%dim, 1, order_, pol)
790 else
791 message(1) = "Error: derivatives_make_discretization can only be called with nderiv = 1 or der%dim."
792 call messages_fatal(1)
793 end if
794
795 safe_allocate(mat(1:op(1)%stencil%size, 1:op(1)%stencil%size))
796 safe_allocate(sol(1:op(1)%stencil%size, 1:nderiv))
798 if (optional_default(verbose, .true.)) then
799 name_ = optional_default(name, name_)
800 message(1) = 'Info: Generating weights for finite-difference discretization of ' // trim(name_)
801 call messages_info(1, namespace=namespace)
802 end if
803
804 ! use to generate power lookup table
805 pow_max = maxval(pol)
806 safe_allocate(powers(1:der%dim, 0:pow_max))
807 powers(:,:) = m_zero
808 powers(:,0) = m_one
809
810 p_max = op(1)%np
811 if (op(1)%const_w) p_max = 1
812
813 do p = 1, p_max
814 ! get polynomials and right-hand side
815 ! we need the current position for the right-hand side for curvilinear coordinates
816 if (nderiv == 1) then
817 if (ideriv <= der%dim) then ! gradient
818 call get_rhs_grad(pol, ideriv, rhs(:,1))
819 name_ = index2axis(ideriv) // "-gradient"
820 else ! Laplacian
821 call get_rhs_lapl(der%mesh%coord_system, pol, der%mesh%chi(:, p), rhs(:,1), der%stencil_primitive_coordinates)
822 end if
823 else if (nderiv == der%dim) then
824 ! in this case, we compute the weights for the gradients at once
825 ! because they have the same stencils
826 do i = 1, der%dim
827 call get_rhs_grad(pol, i, rhs(:,i))
828 end do
829 end if
830
831 ! first polynomial is just a constant
832 mat(1,:) = m_one
833 ! i indexes the point in the stencil
834 do i = 1, op(1)%stencil%size
835 if (ideriv <= der%dim) then
836 ! for gradients, we always need to evaluate the polynomials in primitive coordinates
837 x = real(op(1)%stencil%points(:, i), real64)*der%mesh%spacing
838 else
839 ! for the Laplacian, we can evaluate the polynomials in primitive or Cartesian coordinates
840 if (der%stencil_primitive_coordinates) then
841 x = real(op(1)%stencil%points(:, i), real64)*der%mesh%spacing
842 else
843 x = der%mesh%x(p + op(1)%ri(i, op(1)%rimap(p)), :) - der%mesh%x(p, :)
844 end if
845 end if
846
847 ! NB: these masses are applied on the cartesian directions. Should add a check for non-orthogonal axes
848 x = x*sqrt(der%masses)
849
850 ! calculate powers
851 powers(:, 1) = x
852 do k = 2, pow_max
853 powers(:, k) = x*powers(:, k-1)
854 end do
855
856 ! generate the matrix
857 ! j indexes the polynomial being used
858 do j = 2, op(1)%stencil%size
859 mat(j, i) = powers(1, pol(1, j))
860 do k = 2, der%dim
861 mat(j, i) = mat(j, i)*powers(k, pol(k, j))
862 end do
863 end do
864 end do ! loop over i = point in stencil
865
866 ! linear problem to solve for derivative weights:
867 ! mat * sol = rhs
868 call lalg_linsyssolve(op(1)%stencil%size, nderiv, mat, rhs, sol)
869
870 ! for the cube stencil, all derivatives are calculated at once, so assign
871 ! the correct solution to each operator
872 do i = 1, nderiv
873 op(i)%w(:, p) = sol(:, i)
874 end do
875
876 end do ! loop over points p
877
878 do i = 1, nderiv
880 end do
881
882 ! In case of constant weights, we store the weights of the Laplacian on the GPU, as this
883 ! saves many unecessary transfers
884 do i = 1, nderiv
887 end do
888
889
890 safe_deallocate_a(mat)
891 safe_deallocate_a(sol)
892 safe_deallocate_a(powers)
893 safe_deallocate_a(pol)
894 safe_deallocate_a(rhs)
895
898
899#ifdef HAVE_MPI
900 ! ---------------------------------------------------------
901 logical function derivatives_overlap(this) result(overlap)
902 type(derivatives_t), intent(in) :: this
903
904 push_sub(derivatives_overlap)
905
906 overlap = this%comm_method /= blocking
907
908 pop_sub(derivatives_overlap)
909 end function derivatives_overlap
910#endif
911
912 ! ---------------------------------------------------------
913 subroutine derivatives_get_lapl(this, namespace, op, space, name, order)
914 type(derivatives_t), intent(in) :: this
915 type(namespace_t), intent(in) :: namespace
916 type(nl_operator_t), intent(inout) :: op(:)
917 class(space_t), intent(in) :: space
918 character(len=80), intent(in) :: name
919 integer, intent(in) :: order
920
921 push_sub(derivatives_get_lapl)
922
923 call derivatives_get_stencil_lapl(this, op(1), space, this%mesh%coord_system, name, order)
924 call nl_operator_build(space, this%mesh, op(1), this%mesh%np, const_w = .not. this%mesh%use_curvilinear)
925 call derivatives_make_discretization(namespace, this, 1, this%dim+1, op(1:1), name, order=order)
926
927 pop_sub(derivatives_get_lapl)
928 end subroutine derivatives_get_lapl
929
930 ! ---------------------------------------------------------
943 function derivatives_get_inner_boundary_mask(this) result(mask)
944 type(derivatives_t), intent(in) :: this
945
946 logical :: mask(1:this%mesh%np)
947 integer :: ip, is, index
948
949 mask = .false.
950 ! Loop through all points in the grid
951 do ip = 1, this%mesh%np
952 ! For each of them, loop through all points in the stencil
953 do is = 1, this%lapl%stencil%size
954 ! Get the index of the point obtained as: grid_point + displament_due_to_stencil
955 index = nl_operator_get_index(this%lapl, is, ip)
956 ! Check whether the displaced point if outsude the grid. Is so, it belongs to the mask
957 if (index > this%mesh%np + this%mesh%pv%np_ghost) then
958 mask(ip) = .true.
959 exit
960 end if
961 end do
962 end do
963
965
966 ! ---------------------------------------------------------
971 real(real64) function derivatives_lapl_get_max_eigenvalue(this)
972 type(derivatives_t), intent(in) :: this
974 integer :: i
975
976 push_sub(derivatives_lapl_get_max_eigenvalue)
977
978 derivatives_lapl_get_max_eigenvalue = m_zero
979 if ((this%stencil_type == der_star .or. this%stencil_type == der_stargeneral) &
980 .and. .not. this%mesh%use_curvilinear) then
981 ! use Fourier transform of stencil evaluated at the maximum phase
982 do i = 1, this%lapl%stencil%size
983 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
984 (-1)**maxval(abs(this%lapl%stencil%points(:, i)))*this%lapl%w(i, 1)
985 end do
986 derivatives_lapl_get_max_eigenvalue = abs(derivatives_lapl_get_max_eigenvalue)
987 else
988 ! use upper bound from continuum for other stencils
989 do i = 1, this%dim
990 derivatives_lapl_get_max_eigenvalue = derivatives_lapl_get_max_eigenvalue + &
991 m_pi**2/this%mesh%spacing(i)**2
992 end do
993 end if
994
995 pop_sub(derivatives_lapl_get_max_eigenvalue)
997
998
999#include "undef.F90"
1000#include "real.F90"
1001#include "derivatives_inc.F90"
1002
1003#include "undef.F90"
1004#include "complex.F90"
1005#include "derivatives_inc.F90"
1006
1007end module derivatives_oct_m
1008
1009!! Local Variables:
1010!! mode: f90
1011!! coding: utf-8
1012!! End:
double sqrt(double __x) __attribute__((__nothrow__
subroutine, public accel_kernel_build(this, file_name, kernel_name, flags)
Definition: accel.F90:1340
pure logical function, public accel_is_enabled()
Definition: accel.F90:418
This module implements batches of mesh functions.
Definition: batch.F90:135
This module implements common operations on batches of mesh functions.
Definition: batch_ops.F90:118
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:124
subroutine, public boundaries_end(this)
Definition: boundaries.F90:430
subroutine, public boundaries_init(this, namespace, space, mesh, qvector)
initialize the boundary contitions
Definition: boundaries.F90:229
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:120
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, 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, public dderivatives_batch_grad(der, ffb, opffb, ghost_update, set_bc, to_cartesian, factor)
apply the gradient to a batch of mesh functions
subroutine stencil_pol_grad(stencil_type, dim, direction, order, polynomials)
subroutine stencil_pol_lapl(stencil_type, stencil, dim, order, polynomials)
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 get_rhs_lapl(coord_system, polynomials, chi, rhs, stencil_primitive_coordinates)
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 derivatives_get_stencil_lapl(der, lapl, space, coord_system, name, order)
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 zderivatives_batch_grad(der, ffb, opffb, ghost_update, set_bc, to_cartesian, factor)
apply the gradient to a batch of mesh functions
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, 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 dderivatives_batch_start(op, der, ff, opff, handle, ghost_update, set_bc, factor)
apply a non-local operator to a batch (1st part)
subroutine get_rhs_grad(polynomials, dir, rhs)
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,...
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, 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 derivatives_make_discretization(namespace, der, nderiv, ideriv, op, name, verbose, order)
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:192
real(real64), parameter, public m_zero
Definition: global.F90:190
real(real64), parameter, public m_pi
some mathematical constants
Definition: global.F90:188
real(real64), parameter, public m_one
Definition: global.F90:191
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:117
This module defines various routines, operating on mesh functions.
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:120
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1029
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:416
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:697
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:600
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_output_weights(this)
subroutine, public nl_operator_end(op)
subroutine, public nl_operator_build(space, mesh, op, np, const_w, regenerate)
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:173
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:137
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:120
character pure function, public index2axis(idir)
Definition: utils.F90:205
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:188
data type for non local operators
The class representing the stencil, which is used for non-local mesh operations.
Definition: stencil.F90:165
int true(void)