Octopus
nl_operator.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
24 use accel_oct_m
25 use batch_oct_m
27 use debug_oct_m
28 use global_oct_m
29 use index_oct_m
30 use iso_c_binding
31 use math_oct_m
32 use mesh_oct_m
34 use mpi_oct_m
39 use parser_oct_m
41 use space_oct_m
43 use types_oct_m
45
46 implicit none
47
48 private
49 public :: &
71
77 private
78 integer :: nri = 0
79 integer, allocatable :: imin(:)
80 integer, allocatable :: imax(:)
81 integer, allocatable :: ri(:, :)
82 end type nl_operator_index_t
83
85 type nl_operator_t
86 private
87 type(stencil_t), public :: stencil
88 type(mesh_t), pointer :: mesh => null()
89 integer, allocatable :: nn(:)
90 integer, public :: np = 0
91 ! When running in parallel mode, the next three arrays are unique on each node.
92 real(real64), allocatable, public :: w(:,:)
93
94 logical, public :: const_w = .true.
95
96 type(accel_mem_t), public :: buff_weights
97 type(accel_mem_t), public :: buff_half_weights
98
99 character(len=40) :: label
100
102 integer, public :: nri = 0
103 integer, allocatable, public :: ri(:,:)
104 integer, allocatable, public :: rimap(:)
105 integer, allocatable, public :: rimap_inv(:)
106
107 integer :: ninner = 0
108 integer :: nouter = 0
109
110 type(nl_operator_index_t) :: inner
111 type(nl_operator_index_t) :: outer
112
113 type(accel_kernel_t) :: kernel
114 type(accel_mem_t) :: buff_imin
115 type(accel_mem_t) :: buff_imax
116 type(accel_mem_t) :: buff_ri
117 type(accel_mem_t) :: buff_map
118 type(accel_mem_t) :: buff_all
119 type(accel_mem_t) :: buff_inner
120 type(accel_mem_t) :: buff_outer
121 type(accel_mem_t) :: buff_stencil
122 type(accel_mem_t) :: buff_ip_to_xyz
123 type(accel_mem_t) :: buff_xyz_to_ip
124
125 ! For multigrid solvers
126 type(nl_operator_t), public, pointer :: coarser => null()
127
128 end type nl_operator_t
129
130 integer, parameter :: &
131 OP_FORTRAN = 0, &
132 op_vec = 1, &
133 op_min = op_fortran, &
134 op_max = op_vec
135
136 integer, parameter :: &
137 OP_INVMAP = 1, &
138 op_map = 2, &
139 op_nomap = 3
140
141 integer, public, parameter :: OP_ALL = 3, op_inner = 1, op_outer = 2
142
143 logical :: compact_boundaries
144
145 interface
146 integer function op_is_available(opid, type)
147 implicit none
148 integer, intent(in) :: opid, type
149 end function op_is_available
150 end interface
151
152 integer :: dfunction_global = -1
153 integer :: zfunction_global = -1
154 integer :: function_opencl
155
156contains
157
158 ! ---------------------------------------------------------
161 subroutine nl_operator_global_init(namespace)
162 type(namespace_t), intent(in) :: namespace
163
164 integer :: default
165
167
168 !%Variable OperateDouble
169 !%Type integer
170 !%Section Execution::Optimization
171 !%Default optimized
172 !%Description
173 !% This variable selects the subroutine used to apply non-local
174 !% operators over the grid for real functions.
175 !%Option fortran 0
176 !% The standard Fortran function.
177 !%Option optimized 1
178 !% This version is optimized using vector primitives (if available).
179 !%End
181 !%Variable OperateComplex
182 !%Type integer
183 !%Section Execution::Optimization
184 !%Default optimized
185 !%Description
186 !% This variable selects the subroutine used to apply non-local
187 !% operators over the grid for complex functions.
188 !%Option fortran 0
189 !% The standard Fortran function.
190 !%Option optimized 1
191 !% This version is optimized using vector primitives (if available).
192 !%End
193
194 default = op_vec
196 call parse_variable(namespace, 'OperateDouble', default, dfunction_global)
197 if (.not. varinfo_valid_option('OperateDouble', dfunction_global)) call messages_input_error(namespace, 'OperateDouble')
199 call parse_variable(namespace, 'OperateComplex', default, zfunction_global)
200 if (.not. varinfo_valid_option('OperateComplex', zfunction_global)) call messages_input_error(namespace, 'OperateComplex')
202
205 !%Variable OperateAccel
206 !%Type integer
207 !%Default map
208 !%Section Execution::Optimization
209 !%Description
210 !% This variable selects the subroutine used to apply non-local
211 !% operators over the grid when an accelerator device is used.
212 !%Option invmap 1
213 !% The standard implementation ported to OpenCL.
214 !%Option map 2
215 !% A different version, more suitable for GPUs.
216 !%End
217 call parse_variable(namespace, 'OperateAccel', op_map, function_opencl)
218
219 call messages_obsolete_variable(namespace, 'OperateOpenCL', 'OperateAccel')
220
221 end if
222
223 !%Variable NLOperatorCompactBoundaries
224 !%Type logical
225 !%Default no
226 !%Section Execution::Optimization
227 !%Description
228 !% (Experimental) When set to yes, for finite systems Octopus will
229 !% map boundary points for finite-differences operators to a few
230 !% memory locations. This increases performance, however it is
231 !% experimental and has not been thoroughly tested.
232 !%End
233
234 call parse_variable(namespace, 'NLOperatorCompactBoundaries', .false., compact_boundaries)
235
236 if (compact_boundaries) then
237 call messages_experimental('NLOperatorCompactBoundaries')
238 end if
241 end subroutine nl_operator_global_init
242
243 ! ---------------------------------------------------------
244
249 end subroutine nl_operator_global_end
250
251 ! ---------------------------------------------------------
255 subroutine nl_operator_init(op, label)
256 type(nl_operator_t), intent(inout) :: op
257 character(len=*), intent(in) :: label
258
259 push_sub(nl_operator_init)
260
261 op%label = label
262
263 pop_sub(nl_operator_init)
264 end subroutine nl_operator_init
265
266
267 ! ---------------------------------------------------------
268 subroutine nl_operator_copy(opo, opi)
269 type(nl_operator_t), intent(inout) :: opo
270 type(nl_operator_t), target, intent(in) :: opi
271
272 push_sub(nl_operator_copy)
273
274 ! We cannot currently copy the GPU kernel for the nl_operator
275 assert(.not. accel_is_enabled())
276
277 call nl_operator_end(opo)
278 call nl_operator_init(opo, opi%label)
279
280 call stencil_copy(opi%stencil, opo%stencil)
281
282 opo%np = opi%np
283 opo%mesh => opi%mesh
284
285 safe_allocate_source_a(opo%nn, opi%nn)
286 safe_allocate_source_a(opo%w, opi%w)
287
288 opo%const_w = opi%const_w
289
290 opo%nri = opi%nri
291 assert(allocated(opi%ri))
292
293 safe_allocate_source_a(opo%ri, opi%ri)
294 safe_allocate_source_a(opo%rimap, opi%rimap)
295 safe_allocate_source_a(opo%rimap_inv, opi%rimap_inv)
296
297 if (opi%mesh%parallel_in_domains) then
298 opo%inner%nri = opi%inner%nri
299 safe_allocate_source_a(opo%inner%imin, opi%inner%imin)
300 safe_allocate_source_a(opo%inner%imax, opi%inner%imax)
301 safe_allocate_source_a(opo%inner%ri, opi%inner%ri)
302
303 opo%outer%nri = opi%outer%nri
304 safe_allocate_source_a(opo%outer%imin, opi%outer%imin)
305 safe_allocate_source_a(opo%outer%imax, opi%outer%imax)
306 safe_allocate_source_a(opo%outer%ri, opi%outer%ri)
307 end if
308
309 ! We create the corresponding GPU buffers
310 if (accel_is_enabled() .and. opo%const_w) then
311 call accel_create_buffer(opo%buff_weights, accel_mem_read_only, type_float, opo%stencil%size)
312 call accel_write_buffer(opo%buff_weights, opo%stencil%size, opo%w(:, 1))
313 call accel_create_buffer(opo%buff_half_weights, accel_mem_read_only, type_float, opo%stencil%size)
314 call accel_write_buffer(opo%buff_half_weights, opo%stencil%size, -m_half*opo%w(:, 1))
315 end if
316
317
318 pop_sub(nl_operator_copy)
319 end subroutine nl_operator_copy
320
321
322 ! ---------------------------------------------------------
323 subroutine nl_operator_build(space, mesh, op, np, const_w, regenerate)
324 class(space_t), intent(in) :: space
325 type(mesh_t), target, intent(in) :: mesh
326 type(nl_operator_t), intent(inout) :: op
327 integer, intent(in) :: np
328 logical, optional, intent(in) :: const_w
329 logical, optional, intent(in) :: regenerate
330
331 integer :: ii, jj, p1(space%dim), time, current
332 integer, allocatable :: st1(:), st2(:), st1r(:)
333 integer :: nn
334 integer :: ir, maxp, iinner, iouter
335 logical :: change, force_change
336 character(len=200) :: flags
337 integer, allocatable :: inner_points(:), outer_points(:), all_points(:)
339 push_sub(nl_operator_build)
340
341 if (mesh%parallel_in_domains .and. .not. const_w) then
342 call messages_experimental('Domain parallelization with curvilinear coordinates')
343 end if
344
345 assert(np > 0)
346
347 ! store values in structure
348 op%np = np
349 op%mesh => mesh
350 op%const_w = .false.
351 if (present(const_w)) op%const_w = const_w
352
353 ! allocate weights op%w
354 if (op%const_w) then
355 safe_allocate(op%w(1:op%stencil%size, 1))
356 message(1) = 'Debug: nl_operator_build: working with constant weights.'
357 call messages_info(1, debug_only=.true.)
358 else
359 safe_allocate(op%w(1:op%stencil%size, 1:op%np))
360 message(1) = 'Debug: nl_operator_build: working with non-constant weights.'
361 call messages_info(1, debug_only=.true.)
362 end if
363
364 ! set initially to zero
365 op%w = m_zero
366
367 ! Build lookup table
368 safe_allocate(st1(1:op%stencil%size))
369 safe_allocate(st1r(1:op%stencil%size))
370 safe_allocate(st2(1:op%stencil%size))
371
372 op%nri = 0
373 do time = 1, 2
374 st2 = 0
375 do ii = 1, np
376 p1 = 0
377 call mesh_local_index_to_coords(mesh, ii, p1)
378
379 do jj = 1, op%stencil%size
380 ! Get local index of p1 plus current stencil point.
381 st1(jj) = mesh_local_index_from_coords(mesh, p1 + op%stencil%points(:, jj))
382
383 ! if boundary conditions are zero, we can remap boundary
384 ! points to reduce memory accesses. We cannot do this for the
385 ! first point, since it is used to build the weights, so it
386 ! has to have the positions right
387 if (ii > 1 .and. compact_boundaries .and. mesh_compact_boundaries(mesh) .and. .not. space%is_periodic()) then
388 st1(jj) = min(st1(jj), mesh%np + 1)
389 end if
390 assert(st1(jj) > 0)
391 end do
392
393 st1(1:op%stencil%size) = st1(1:op%stencil%size) - ii
394
395 change = any(st1 /= st2)
396
397 !the next is to detect when we move from a point that does not
398 !have boundary points as neighbours to one that has
399 force_change = any(st1 + ii > mesh%np) .and. all(st2 + ii - 1 <= mesh%np)
400
401 if (change .and. compact_boundaries .and. mesh_compact_boundaries(mesh) .and. .not. space%is_periodic()) then
402 !try to repair it by changing the boundary points
403 do jj = 1, op%stencil%size
404 if (st1(jj) + ii > mesh%np .and. st2(jj) + ii - 1 > mesh%np .and. st2(jj) + ii <= mesh%np_part) then
405 st1r(jj) = st2(jj)
406 else
407 st1r(jj) = st1(jj)
408 end if
409 end do
410
411 change = any(st1r /= st2)
412
413 if (.not. change) st1 = st1r
414 end if
415
416 ! if the stencil changes
417 if (change .or. force_change) then
418 !store it
419 st2 = st1
420
421 !first time, just count
422 if (time == 1) op%nri = op%nri + 1
423
424 !second time, store
425 if (time == 2) then
426 current = current + 1
427 op%ri(1:op%stencil%size, current) = st1(1:op%stencil%size)
428 end if
429 end if
430
431 if (time == 2) op%rimap(ii) = current
432
433 end do
434
435 !after counting, allocate
436 if (time == 1) then
437 safe_deallocate_a(op%ri)
438 safe_deallocate_a(op%rimap)
439 safe_deallocate_a(op%rimap_inv)
440
441 safe_allocate(op%ri(1:op%stencil%size, 1:op%nri))
442 safe_allocate(op%rimap(1:op%np))
443 safe_allocate(op%rimap_inv(1:op%nri + 1))
444 op%ri = 0
445 op%rimap = 0
446 op%rimap_inv = 0
447 current = 0
448
449 ! the sizes
450 if (mesh%use_curvilinear) then
451 safe_allocate(op%nn(1:op%nri))
452 ! for the moment all the sizes are the same
453 op%nn = op%stencil%size
454 end if
455 end if
456
457 end do
458
459 !the inverse mapping
460 op%rimap_inv(1) = 0
461 do jj = 1, op%np
462 op%rimap_inv(op%rimap(jj) + 1) = jj
463 end do
464 op%rimap_inv(op%nri + 1) = op%np
465
466 safe_deallocate_a(st1)
467 safe_deallocate_a(st1r)
468 safe_deallocate_a(st2)
469
470 do jj = 1, op%nri
471 nn = op%rimap_inv(jj + 1) - op%rimap_inv(jj)
472 end do
473
474 if (op%mesh%parallel_in_domains) then
475 !now build the arrays required to apply the nl_operator by parts
476
477 !count points
478 op%inner%nri = 0
479 op%outer%nri = 0
480 do ir = 1, op%nri
481 maxp = op%rimap_inv(ir + 1) + maxval(op%ri(1:op%stencil%size, ir))
482 if (maxp <= np) then
483 !inner point
484 op%inner%nri = op%inner%nri + 1
485 assert(op%inner%nri <= op%nri)
486 else
487 !outer point
488 op%outer%nri = op%outer%nri + 1
489 assert(op%outer%nri <= op%nri)
490 end if
491 end do
492
493 assert(op%inner%nri + op%outer%nri == op%nri)
494
495 if (optional_default(regenerate, .false.)) then
496 safe_deallocate_a(op%inner%imin)
497 safe_deallocate_a(op%inner%imax)
498 safe_deallocate_a(op%inner%ri)
499 safe_deallocate_a(op%outer%imin)
500 safe_deallocate_a(op%outer%imax)
501 safe_deallocate_a(op%outer%ri)
502 end if
503 safe_allocate(op%inner%imin(1:op%inner%nri + 1))
504 safe_allocate(op%inner%imax(1:op%inner%nri))
505 safe_allocate(op%inner%ri(1:op%stencil%size, 1:op%inner%nri))
506
507 safe_allocate(op%outer%imin(1:op%outer%nri + 1))
508 safe_allocate(op%outer%imax(1:op%outer%nri))
509 safe_allocate(op%outer%ri(1:op%stencil%size, 1:op%outer%nri))
510
511 !now populate the arrays
512 iinner = 0
513 iouter = 0
514 do ir = 1, op%nri
515 maxp = op%rimap_inv(ir + 1) + maxval(op%ri(1:op%stencil%size, ir))
516 if (maxp <= np) then
517 !inner point
518 iinner = iinner + 1
519 op%inner%imin(iinner) = op%rimap_inv(ir)
520 op%inner%imax(iinner) = op%rimap_inv(ir + 1)
521 op%inner%ri(1:op%stencil%size, iinner) = op%ri(1:op%stencil%size, ir)
522 else
523 !outer point
524 iouter = iouter + 1
525 op%outer%imin(iouter) = op%rimap_inv(ir)
526 op%outer%imax(iouter) = op%rimap_inv(ir + 1)
527 op%outer%ri(1:op%stencil%size, iouter) = op%ri(1:op%stencil%size, ir)
528 end if
529 end do
530
531 !verify that all points in the inner operator are actually inner
532 do ir = 1, op%inner%nri
533 do ii = op%inner%imin(ir) + 1, op%inner%imax(ir)
534 assert(all(ii + op%inner%ri(1:op%stencil%size, ir) <= mesh%np))
535 end do
536 end do
537
538 end if
539
540 if (accel_is_enabled() .and. op%const_w) then
541
542 write(flags, '(i5)') op%stencil%size
543 flags='-DNDIM=3 -DSTENCIL_SIZE='//trim(adjustl(flags))
544
545 if (op%mesh%parallel_in_domains) flags = '-DINDIRECT '//trim(flags)
546
547 select case (function_opencl)
548 case (op_invmap)
549 call accel_kernel_build(op%kernel, 'operate.cl', 'operate', flags)
550 case (op_map)
551 call accel_kernel_build(op%kernel, 'operate.cl', 'operate_map', flags)
552 end select
553
554 ! conversion to i8 needed to avoid integer overflow
555 call accel_create_buffer(op%buff_ri, accel_mem_read_only, type_integer, int(op%nri, int64)*op%stencil%size)
556 call accel_write_buffer(op%buff_ri, int(op%nri, int64)*op%stencil%size, op%ri)
557
558 select case (function_opencl)
559 case (op_invmap)
560 call accel_create_buffer(op%buff_imin, accel_mem_read_only, type_integer, op%nri)
561 call accel_write_buffer(op%buff_imin, op%nri, op%rimap_inv(1:))
562 call accel_create_buffer(op%buff_imax, accel_mem_read_only, type_integer, op%nri)
563 call accel_write_buffer(op%buff_imax, op%nri, op%rimap_inv(2:))
564
565 case (op_map)
566
568 call accel_write_buffer(op%buff_map, op%mesh%np, (op%rimap - 1)*op%stencil%size)
569
570 if (op%mesh%parallel_in_domains) then
571
572 safe_allocate(inner_points(1:op%mesh%np))
573 safe_allocate(outer_points(1:op%mesh%np))
574 safe_allocate(all_points(1:op%mesh%np))
575
576 op%ninner = 0
577 op%nouter = 0
578
579 do ii = 1, op%mesh%np
580 all_points(ii) = ii - 1
581 maxp = ii + maxval(op%ri(1:op%stencil%size, op%rimap(ii)))
582 if (maxp <= op%mesh%np) then
583 op%ninner = op%ninner + 1
584 inner_points(op%ninner) = ii - 1
585 else
586 op%nouter = op%nouter + 1
587 outer_points(op%nouter) = ii - 1
588 end if
589 end do
590
592 call accel_write_buffer(op%buff_all, op%mesh%np, all_points)
593
595 call accel_write_buffer(op%buff_inner, op%ninner, inner_points)
596
598 call accel_write_buffer(op%buff_outer, op%nouter, outer_points)
599
600 safe_deallocate_a(inner_points)
601 safe_deallocate_a(outer_points)
602 safe_deallocate_a(all_points)
603
604 end if
605 end select
606 end if
607
608 pop_sub(nl_operator_build)
609
610 end subroutine nl_operator_build
611
612 ! ---------------------------------------------------------
613 subroutine nl_operator_output_weights(this)
614 type(nl_operator_t), intent(inout) :: this
615
616 integer :: istencil, idir
617
619
620 write(message(1), '(3a)') 'Debug info: Finite difference weights for ', trim(this%label), '.'
621 write(message(2), '(a)') ' Spacing:'
622 do idir = 1, this%mesh%box%dim
623 write(message(2), '(a,f16.8)') trim(message(2)), this%mesh%spacing(idir)
624 end do
625 call messages_info(2, debug_only=.true.)
626
627 do istencil = 1, this%stencil%size
628 select case(this%mesh%box%dim)
629 case(1)
630 write(message(1), '(a,i3,1i4,f25.10)') ' ', istencil, this%stencil%points(1:1, istencil), this%w(istencil, 1)
631 case(2)
632 write(message(1), '(a,i3,2i4,f25.10)') ' ', istencil, this%stencil%points(1:2, istencil), this%w(istencil, 1)
633 case(3)
634 write(message(1), '(a,i3,3i4,f25.10)') ' ', istencil, this%stencil%points(1:3, istencil), this%w(istencil, 1)
635 end select
636 call messages_info(1, debug_only=.true.)
637 end do
638
640
641 end subroutine nl_operator_output_weights
642
643 ! ---------------------------------------------------------
645 subroutine nl_operator_adjoint(op, opt, mesh, self_adjoint)
646 type(nl_operator_t), target, intent(in) :: op
647 type(nl_operator_t), target, intent(out) :: opt
648 type(mesh_t), target, intent(in) :: mesh
649 logical, intent(in) :: self_adjoint
650
651 integer :: ip, jp, kp, lp, index, ii, p1(1:mesh%box%dim)
652 real(real64), pointer, contiguous :: vol_pp(:), weights(:, :), tmp(:)
653 real(real64) :: factor
654
655 push_sub(nl_operator_adjoint)
656
657 if (self_adjoint) then
658 ! make operator self-adjoint
659 factor = m_one
660 else
661 ! make operator skew-adjoint
662 factor = -m_one
663 end if
664
665 call nl_operator_copy(opt, op)
666
667 if (mesh%parallel_in_domains) then
668 ! get ghost point values
669 safe_allocate(vol_pp(1:mesh%np_part))
670 vol_pp(1:mesh%np) = mesh%vol_pp(1:mesh%np)
671 call dpar_vec_ghost_update(mesh%pv, vol_pp)
672
673 if (.not.op%const_w) then
674 safe_allocate(weights(1:op%stencil%size, 1:mesh%np_part))
675 safe_allocate(tmp(1:mesh%np_part))
676 do ii = 1, op%stencil%size
677 tmp(1:mesh%np) = op%w(ii, 1:mesh%np)
678 call dpar_vec_ghost_update(mesh%pv, tmp)
679 weights(ii, 1:mesh%np_part) = tmp(1:mesh%np_part)
680 end do
681 safe_deallocate_p(tmp)
682 end if
683 else
684 vol_pp => mesh%vol_pp
685 weights => op%w
686 end if
687
688 if (.not.op%const_w) then
689 opt%w = m_zero
690 do ip = 1, mesh%np
691 do jp = 1, op%stencil%size
692 index = nl_operator_get_index(op, jp, ip)
693 if (index <= mesh%np) then
694 ! point is in the mesh
695 do lp = 1, op%stencil%size
696 kp = nl_operator_get_index(op, lp, index)
697 if (kp == ip) then
698 opt%w(jp, ip) = m_half*weights(jp, ip) + factor*m_half*(vol_pp(index)/vol_pp(ip))*weights(lp, index)
699 end if
700 end do
701 else if (index <= mesh%np + mesh%pv%np_ghost) then
702 ! point is in the ghost layer
703 call mesh_local_index_to_coords(mesh, index, p1)
704 do lp = 1, op%stencil%size
705 kp = mesh_local_index_from_coords(mesh, p1(1:mesh%box%dim) + &
706 op%stencil%points(1:mesh%box%dim, lp))
707 if (kp == ip) then
708 opt%w(jp, ip) = m_half*weights(jp, ip) + factor*m_half*(vol_pp(index)/vol_pp(ip))*weights(lp, index)
709 end if
710 end do
711 end if
712 end do
713 end do
714 else
715 opt%w(1:op%stencil%size, 1) = op%w(1:op%stencil%size, 1)
716 end if
717
719
720 if (mesh%parallel_in_domains) then
721 safe_deallocate_p(vol_pp)
722 safe_deallocate_p(weights)
723 end if
724
725 pop_sub(nl_operator_adjoint)
726 end subroutine nl_operator_adjoint
727
728 ! ---------------------------------------------------------
729 subroutine nl_operator_end(op)
730 type(nl_operator_t), intent(inout) :: op
731
732 push_sub(nl_operator_end)
733
734 if (accel_is_enabled() .and. op%const_w) then
735
736 call accel_release_buffer(op%buff_ri)
737 select case (function_opencl)
738 case (op_invmap)
739 call accel_release_buffer(op%buff_imin)
740 call accel_release_buffer(op%buff_imax)
741
742 case (op_map)
743 call accel_release_buffer(op%buff_map)
744 if (op%mesh%parallel_in_domains) then
745 call accel_release_buffer(op%buff_all)
746 call accel_release_buffer(op%buff_inner)
747 call accel_release_buffer(op%buff_outer)
748 end if
749
750 case (op_nomap)
751 call accel_release_buffer(op%buff_map)
752 call accel_release_buffer(op%buff_stencil)
753 call accel_release_buffer(op%buff_xyz_to_ip)
754 call accel_release_buffer(op%buff_ip_to_xyz)
755 end select
756
757 call accel_release_buffer(op%buff_weights)
758 call accel_release_buffer(op%buff_half_weights)
759 end if
760
761 safe_deallocate_a(op%inner%imin)
762 safe_deallocate_a(op%inner%imax)
763 safe_deallocate_a(op%inner%ri)
764 safe_deallocate_a(op%outer%imin)
765 safe_deallocate_a(op%outer%imax)
766 safe_deallocate_a(op%outer%ri)
767
768 safe_deallocate_a(op%w)
769
770 safe_deallocate_a(op%ri)
771 safe_deallocate_a(op%rimap)
772 safe_deallocate_a(op%rimap_inv)
773 safe_deallocate_a(op%nn)
774
775 call stencil_end(op%stencil)
776
777 pop_sub(nl_operator_end)
778 end subroutine nl_operator_end
779
780
781 ! ---------------------------------------------------------
782 integer pure function nl_operator_get_index(op, is, ip) result(res)
783 type(nl_operator_t), intent(in) :: op
784 integer, intent(in) :: is
785 integer, intent(in) :: ip
786
787 res = ip + op%ri(is, op%rimap(ip))
788 end function nl_operator_get_index
789
790 ! ---------------------------------------------------------
791
793 type(nl_operator_t), intent(inout) :: op
794
796
797 ! Update the GPU weights
798 if (accel_is_enabled() .and. op%const_w) then
799 call accel_create_buffer(op%buff_weights, accel_mem_read_only, type_float, op%stencil%size)
800 call accel_create_buffer(op%buff_half_weights, accel_mem_read_only, type_float, op%stencil%size)
801 end if
802
805
806
807 ! ---------------------------------------------------------
808
809 subroutine nl_operator_update_gpu_buffers(op)
810 type(nl_operator_t), intent(inout) :: op
811
813
814 ! Update the GPU weights
815 if (accel_is_enabled() .and. op%const_w) then
816 call accel_write_buffer(op%buff_weights, op%stencil%size, op%w(:, 1))
817 call accel_write_buffer(op%buff_half_weights, op%stencil%size, -m_half*op%w(:, 1))
818 end if
819
821 end subroutine nl_operator_update_gpu_buffers
823 ! ---------------------------------------------------------
824
825 integer pure function nl_operator_np_zero_bc(op) result(np_bc)
826 type(nl_operator_t), intent(in) :: op
827
828 integer :: jj, ii
829
830 np_bc = 0
831 do jj = 1, op%nri
832 ii = op%rimap_inv(jj + 1) + maxval(op%ri(1:op%stencil%size, jj))
833 np_bc = max(np_bc, ii)
834 end do
835
836 end function nl_operator_np_zero_bc
837
838 ! ------------------------------------------------------
839
840 logical pure function nl_operator_compact_boundaries()
841
844
845
846#include "undef.F90"
847#include "real.F90"
848#include "nl_operator_inc.F90"
849
850#include "undef.F90"
851#include "complex.F90"
852#include "nl_operator_inc.F90"
853
854end module nl_operator_oct_m
855
856!! Local Variables:
857!! mode: f90
858!! coding: utf-8
859!! End:
subroutine, public accel_release_buffer(this)
Definition: accel.F90:1246
subroutine, public accel_kernel_build(this, file_name, kernel_name, flags)
Definition: accel.F90:2063
pure logical function, public accel_is_enabled()
Definition: accel.F90:400
integer, parameter, public accel_mem_read_only
Definition: accel.F90:183
integer pure function, public accel_max_workgroup_size()
Definition: accel.F90:1472
This module implements batches of mesh functions.
Definition: batch.F90:133
Module implementing boundary conditions in Octopus.
Definition: boundaries.F90:122
subroutine, public dpar_vec_ghost_update(pv, v_local)
Updates ghost points of every node.
real(real64), parameter, public m_zero
Definition: global.F90:187
real(real64), parameter, public m_half
Definition: global.F90:193
real(real64), parameter, public m_one
Definition: global.F90:188
This module implements the index, used for the mesh points.
Definition: index.F90:122
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
subroutine, public weights(N, M, cc, side)
Compute the weights for finite-difference calculations:
Definition: math.F90:522
This module defines the meshes, which are used in Octopus.
Definition: mesh.F90:118
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
Definition: mesh.F90:935
subroutine, public mesh_local_index_to_coords(mesh, ip, ix)
Given a local point index, this function returns the set of integer coordinates of the point.
Definition: mesh.F90:947
logical pure function, public mesh_compact_boundaries(mesh)
Definition: mesh.F90:822
subroutine, public messages_obsolete_variable(namespace, name, rep)
Definition: messages.F90:1057
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_input_error(namespace, var, details, row, column)
Definition: messages.F90:723
subroutine, public messages_experimental(name, namespace)
Definition: messages.F90:1097
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:624
This module handles the communicators for the various parallelization strategies.
Definition: multicomm.F90:145
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
integer, parameter op_map
integer, parameter op_max
integer, parameter op_vec
subroutine, public dnl_operator_operate_batch(op, fi, fo, ghost_update, profile, points, factor, async)
subroutine, public dnl_operator_operate(op, fi, fo, ghost_update, profile, points)
subroutine, public nl_operator_update_gpu_buffers(op)
subroutine, public nl_operator_global_init(namespace)
initialize global settings for non-local operators
subroutine, public nl_operator_copy(opo, opi)
subroutine, public nl_operator_output_weights(this)
subroutine, public nl_operator_end(op)
integer, parameter, public op_inner
subroutine, public znl_operator_operate(op, fi, fo, ghost_update, profile, points)
logical pure function, public nl_operator_compact_boundaries()
subroutine, public nl_operator_global_end()
integer, parameter, public op_outer
subroutine, public nl_operator_build(space, mesh, op, np, const_w, regenerate)
logical compact_boundaries
subroutine, public znl_operator_operate_batch(op, fi, fo, ghost_update, profile, points, factor, async)
integer, parameter op_nomap
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)
subroutine, public znl_operator_operate_diag(op, fo)
integer pure function, public nl_operator_get_index(op, is, ip)
subroutine, public nl_operator_allocate_gpu_buffers(op)
integer, parameter op_min
This module contains interfaces for routines in operate.c.
Definition: operate_f.F90:117
Some general things and nomenclature:
Definition: par_vec.F90:171
This module defines stencils used in Octopus.
Definition: stencil.F90:135
subroutine, public stencil_end(this)
Definition: stencil.F90:214
subroutine, public stencil_copy(input, output)
Definition: stencil.F90:196
type(type_t), public type_float
Definition: types.F90:133
type(type_t), public type_integer
Definition: types.F90:135
Describes mesh distribution to nodes.
Definition: mesh.F90:186
index type for non-local operators
data type for non local operators
int true(void)