Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
scratch_registry.f90
Go to the documentation of this file.
1! Copyright (c) 2025-2026, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
38 use num_types, only : rp
40 use host_array, only : host_array_t
42 use field, only : field_t
43 use vector, only : vector_t
44 use matrix, only : matrix_t
45 use tensor3, only : tensor3_t
46 use tensor4, only : tensor4_t
47
48 use math, only : rzero
49 use device_math, only : device_rzero
50 use field_math, only : field_rzero
51 use vector_math, only : vector_rzero
52 use matrix_math, only : matrix_rzero
53
54 use dofmap, only : dofmap_t
55 use utils, only : neko_error
57 use, intrinsic :: iso_c_binding, only : c_ptr
58 implicit none
59 private
60
73 type, public :: scratch_registry_t
75 type(registry_entry_t), private, allocatable :: entries(:)
77 logical, private, allocatable :: inuse(:)
79 integer, private :: n_entries = 0
81 integer, private :: expansion_size = 10
83 type(dofmap_t), private, pointer :: dof => null()
84 contains
85
86 ! ----------------------------------------------------------------------- !
87 ! Public generic procedures for the scratch registry
88
90 procedure, pass(this) :: init => scratch_registry_init
92 procedure, pass(this) :: free => scratch_registry_free
93
95 procedure, pass(this) :: set_dofmap => scratch_registry_set_dofmap
97 procedure, pass(this) :: set_expansion_size => &
99
101 procedure, pass(this) :: get_n_entries
103 procedure, pass(this) :: get_n_inuse
105 procedure, pass(this) :: get_expansion_size
107 procedure, pass(this) :: get_size
109 procedure, pass(this) :: get_inuse
110
111 ! ----------------------------------------------------------------------- !
112 ! Type specific procedures for the scratch registry
113
115 procedure, pass(this) :: request_host_array
116 procedure, pass(this) :: relinquish_host_array_single
117 procedure, pass(this) :: relinquish_host_array_multiple
119 generic :: relinquish_host_array => relinquish_host_array_single, &
121
123 procedure, pass(this) :: request_device_array
124 procedure, pass(this) :: relinquish_device_array_single
125 procedure, pass(this) :: relinquish_device_array_multiple
127 generic :: relinquish_device_array => relinquish_device_array_single, &
129
131 procedure, pass(this) :: request_vector
132 procedure, pass(this) :: relinquish_vector_single
133 procedure, pass(this) :: relinquish_vector_multiple
135 generic :: relinquish_vector => relinquish_vector_single, &
137
139 procedure, pass(this) :: request_matrix
140 procedure, pass(this) :: relinquish_matrix_single
141 procedure, pass(this) :: relinquish_matrix_multiple
143 generic :: relinquish_matrix => relinquish_matrix_single, &
145
147 procedure, pass(this) :: request_tensor3
148 procedure, pass(this) :: relinquish_tensor3_single
149 procedure, pass(this) :: relinquish_tensor3_multiple
151 generic :: relinquish_tensor3 => relinquish_tensor3_single, &
153
155 procedure, pass(this) :: request_tensor4
156 procedure, pass(this) :: relinquish_tensor4_single
157 procedure, pass(this) :: relinquish_tensor4_multiple
159 generic :: relinquish_tensor4 => relinquish_tensor4_single, &
161
163 procedure, pass(this) :: request_field_stored_dof
165 procedure, pass(this) :: request_field_free_dof
166 procedure, pass(this) :: relinquish_field_single
167 procedure, pass(this) :: relinquish_field_multiple
169 generic :: request_field => request_field_stored_dof, &
172 generic :: relinquish_field => relinquish_field_single, &
174
175 ! ----------------------------------------------------------------------- !
176 ! Type generic procedures for the scratch registry
177
179 generic :: request => request_host_array, request_device_array, &
182
184 procedure, pass(this) :: relinquish_single
186 procedure, pass(this) :: relinquish_multiple
188 generic :: relinquish => relinquish_single, relinquish_multiple
189
190 ! ----------------------------------------------------------------------- !
191 ! Private helper procedures
192
194 procedure, pass(this), private :: relinquish_type
196 procedure, private, pass(this) :: expand
197
198 end type scratch_registry_t
199
202
203contains
204
205 ! -------------------------------------------------------------------------- !
206 ! Public generic procedures for the scratch registry
207
217 subroutine scratch_registry_init(this, size, expansion_size, dof)
218 class(scratch_registry_t), intent(inout) :: this
219 integer, optional, intent(in) :: size
220 integer, optional, intent(in) :: expansion_size
221 type(dofmap_t), target, intent(in), optional :: dof
222 integer :: initial_size
223
224 call this%free()
225
226 ! Assign the dofmap and expansion size if provided
227 if (present(dof)) this%dof => dof
228 if (present(expansion_size)) this%expansion_size = expansion_size
229
230 ! Allocate the entries and inuse arrays with the initial size
231 initial_size = this%expansion_size
232 if (present(size)) initial_size = size
233
234 if (initial_size .lt. 0) then
235 call neko_error("scratch_registry::init: " // &
236 "Initial size must be non-negative.")
237 end if
238
239 if (this%expansion_size .le. 0) then
240 call neko_error("scratch_registry::init: " // &
241 "Expansion size must be positive.")
242 end if
243
244 allocate(this%entries(initial_size))
245 allocate(this%inuse(initial_size), source = .false.)
246
247 end subroutine scratch_registry_init
248
250 subroutine scratch_registry_free(this)
251 class(scratch_registry_t), intent(inout):: this
252 integer :: i
253
254 if (this%get_n_inuse() .ne. 0) then
255 call neko_error("scratch_registry::free: " // &
256 "Cannot free scratch registry with entries still in use.")
257 end if
258
259 if (allocated(this%entries)) then
260 do i = 1, this%n_entries
261 call this%entries(i)%free()
262 end do
263 deallocate(this%entries)
264 end if
265
266 if (allocated(this%inuse)) deallocate(this%inuse)
267 if (associated(this%dof)) nullify(this%dof)
268
269 ! Reset to default values
270 this%n_entries = 0
271 this%expansion_size = 10
272
273 end subroutine scratch_registry_free
274
279 subroutine scratch_registry_set_dofmap(this, dof)
280 class(scratch_registry_t), intent(inout) :: this
281 type(dofmap_t), target, intent(in) :: dof
282
283 if (associated(this%dof, dof)) then
284 return
285 else if (associated(this%dof)) then
286 call neko_error("scratch_registry::set_dofmap: "&
287 // "Dofmap is already assigned to scratch registry.")
288 end if
289
290 this%dof => dof
291 end subroutine scratch_registry_set_dofmap
292
295 subroutine scratch_registry_set_expansion_size(this, expansion_size)
296 class(scratch_registry_t), intent(inout) :: this
297 integer, intent(in) :: expansion_size
298
299 if (expansion_size .le. 0) then
300 call neko_error("scratch_registry::set_expansion_size: "&
301 // "Expansion size must be positive.")
302 end if
303
304 this%expansion_size = expansion_size
306
308 function get_n_entries(this) result(n)
309 class(scratch_registry_t), intent(in) :: this
310 integer :: n
311
312 !$omp critical (SCRATCH_OMP_LOCK)
313 n = this%n_entries
314 !$omp end critical (SCRATCH_OMP_LOCK)
315 end function get_n_entries
316
318 function get_n_inuse(this) result(n)
319 class(scratch_registry_t), intent(in) :: this
320 integer :: n
321
322 !$omp critical (SCRATCH_OMP_LOCK)
323 if (allocated(this%inuse)) then
324 n = count(this%inuse)
325 else
326 n = 0
327 end if
328 !$omp end critical (SCRATCH_OMP_LOCK)
329 end function get_n_inuse
330
332 function get_size(this) result(n)
333 class(scratch_registry_t), intent(in) :: this
334 integer :: n
335
336 !$omp critical (SCRATCH_OMP_LOCK)
337 if (allocated(this%entries)) then
338 n = size(this%entries)
339 else
340 n = 0
341 end if
342 !$omp end critical (SCRATCH_OMP_LOCK)
343 end function get_size
344
346 pure function get_expansion_size(this) result(n)
347 class(scratch_registry_t), intent(in) :: this
348 integer :: n
349
350 n = this%expansion_size
351 end function get_expansion_size
352
354 logical function get_inuse(this, index)
355 class(scratch_registry_t), target, intent(in) :: this
356 integer, intent(in) :: index
357
358 !$omp critical (SCRATCH_OMP_LOCK)
359 get_inuse = this%inuse(index)
360 !$omp end critical (SCRATCH_OMP_LOCK)
361 end function get_inuse
362
363 ! -------------------------------------------------------------------------- !
364 ! Type specific procedures for the scratch registry
365
372 subroutine request_host_array(this, scratch_entry, index, n, clear)
373 class(scratch_registry_t), target, intent(inout) :: this
374 real(kind=rp), pointer, dimension(:), intent(inout) :: scratch_entry
375 integer, intent(inout) :: index
376 integer, intent(in) :: n
377 logical, intent(in) :: clear
378 type(host_array_t), pointer :: ptr
379
380 ptr => null()
381
382 ! Look for a compatible, unused object in the registry.
383 !$omp critical (SCRATCH_OMP_LOCK)
384 do index = 1, this%n_entries
385
386 ! Find an unused object of the correct type.
387 if (this%inuse(index)) cycle
388 if (.not. this%entries(index)%is_type('host_array')) cycle
389
390 ! Check compatibility of the object size.
391 ptr => this%entries(index)%get_host_array()
392 if (ptr%size() .eq. n) then
393 this%inuse(index) = .true.
394 exit
395 end if
396 nullify(ptr)
397 end do
398
399 ! If no compatible, unused objects are found, expand and create a new one.
400 if (index .gt. this%n_entries) then
401 this%n_entries = this%n_entries + 1
402
403 if (this%n_entries .gt. size(this%entries)) call this%expand()
404 call this%entries(this%n_entries)%init_host_array(n)
405 ptr => this%entries(this%n_entries)%get_host_array()
406
407 this%inuse(this%n_entries) = .true.
408 end if
409 !$omp end critical (SCRATCH_OMP_LOCK)
410
411 ! Assign the pointer to the entry and clear the values if requested.
412 scratch_entry => ptr%x
413 if (clear) call rzero(scratch_entry, n)
414 nullify(ptr)
415
416 end subroutine request_host_array
417
420 subroutine relinquish_host_array_single(this, index)
421 class(scratch_registry_t), intent(inout) :: this
422 integer, intent(in) :: index
423
424 call this%relinquish_type(index, 'host_array')
425 end subroutine relinquish_host_array_single
426
429 subroutine relinquish_host_array_multiple(this, indices)
430 class(scratch_registry_t), intent(inout) :: this
431 integer, intent(in) :: indices(:)
432 integer :: i
433
434 do i = 1, size(indices)
435 call this%relinquish_type(indices(i), 'host_array')
436 end do
437 end subroutine relinquish_host_array_multiple
438
445 subroutine request_device_array(this, scratch_entry, index, n, clear)
446 class(scratch_registry_t), target, intent(inout) :: this
447 type(c_ptr), intent(inout) :: scratch_entry
448 integer, intent(inout) :: index
449 integer, intent(in) :: n
450 logical, intent(in) :: clear
451 type(device_array_t), pointer :: ptr
452
453 ptr => null()
454
455 ! Look for a compatible, unused object in the registry.
456 !$omp critical (SCRATCH_OMP_LOCK)
457 do index = 1, this%n_entries
458
459 ! Find an unused object of the correct type.
460 if (this%inuse(index)) cycle
461 if (.not. this%entries(index)%is_type('device_array')) cycle
462
463 ! Check compatibility of the object size.
464 ptr => this%entries(index)%get_device_array()
465 if (ptr%size() .eq. n) then
466 this%inuse(index) = .true.
467 exit
468 end if
469 nullify(ptr)
470 end do
471
472 ! If no compatible, unused objects are found, expand and create a new one.
473 if (index .gt. this%n_entries) then
474 this%n_entries = this%n_entries + 1
475
476 if (this%n_entries .gt. size(this%entries)) call this%expand()
477 call this%entries(this%n_entries)%init_device_array(n)
478 ptr => this%entries(this%n_entries)%get_device_array()
479
480 this%inuse(this%n_entries) = .true.
481 end if
482 !$omp end critical (SCRATCH_OMP_LOCK)
483
484 ! Assign the pointer to the entry and clear the values if requested.
485 scratch_entry = ptr%x_d
486 if (clear) call device_rzero(scratch_entry, n)
487 nullify(ptr)
488
489 end subroutine request_device_array
490
493 subroutine relinquish_device_array_single(this, index)
494 class(scratch_registry_t), intent(inout) :: this
495 integer, intent(in) :: index
496
497 call this%relinquish_type(index, 'device_array')
498 end subroutine relinquish_device_array_single
499
502 subroutine relinquish_device_array_multiple(this, indices)
503 class(scratch_registry_t), intent(inout) :: this
504 integer, intent(in) :: indices(:)
505 integer :: i
506
507 do i = 1, size(indices)
508 call this%relinquish_type(indices(i), 'device_array')
509 end do
511
517 subroutine request_vector(this, scratch_entry, index, n, clear)
518 class(scratch_registry_t), target, intent(inout) :: this
519 type(vector_t), pointer, intent(inout) :: scratch_entry
520 integer, intent(inout) :: index
521 integer, intent(in) :: n
522 logical, intent(in) :: clear
523
524 ! Look for a compatible, unused object in the registry.
525 !$omp critical (SCRATCH_OMP_LOCK)
526 do index = 1, this%n_entries
527
528 ! Find an unused object of the correct type.
529 if (this%inuse(index)) cycle
530 if (.not. this%entries(index)%is_type('vector')) cycle
531
532 ! Check compatibility of the object size.
533 scratch_entry => this%entries(index)%get_vector()
534 if (scratch_entry%size() .eq. n) then
535 this%inuse(index) = .true.
536 exit
537 end if
538 nullify(scratch_entry)
539 end do
540
541 ! If no compatible, unused objects are found, expand and create a new one.
542 if (index .gt. this%n_entries) then
543 this%n_entries = this%n_entries + 1
544
545 if (this%n_entries .gt. size(this%entries)) call this%expand()
546 call this%entries(this%n_entries)%init_vector(n)
547 scratch_entry => this%entries(this%n_entries)%get_vector()
548
549 this%inuse(this%n_entries) = .true.
550 end if
551 !$omp end critical (SCRATCH_OMP_LOCK)
552
553 ! Assign the pointer to the entry and clear the values if requested.
554 if (clear) call vector_rzero(scratch_entry)
555
556 end subroutine request_vector
557
560 subroutine relinquish_vector_single(this, index)
561 class(scratch_registry_t), intent(inout) :: this
562 integer, intent(in) :: index
563
564 call this%relinquish_type(index, 'vector')
565 end subroutine relinquish_vector_single
566
569 subroutine relinquish_vector_multiple(this, indices)
570 class(scratch_registry_t), intent(inout) :: this
571 integer, intent(in) :: indices(:)
572 integer :: i
573
574 do i = 1, size(indices)
575 call this%relinquish_type(indices(i), 'vector')
576 end do
577 end subroutine relinquish_vector_multiple
578
585 subroutine request_matrix(this, scratch_entry, index, nrows, ncols, clear)
586 class(scratch_registry_t), target, intent(inout) :: this
587 type(matrix_t), pointer, intent(inout) :: scratch_entry
588 integer, intent(inout) :: index
589 integer, intent(in) :: nrows, ncols
590 logical, intent(in) :: clear
591
592 ! Look for a compatible, unused object in the registry.
593 !$omp critical (SCRATCH_OMP_LOCK)
594 do index = 1, this%n_entries
595
596 ! Find an unused object of the correct type.
597 if (this%inuse(index)) cycle
598 if (.not. this%entries(index)%is_type('matrix')) cycle
599
600 ! Check compatibility of the object size.
601 scratch_entry => this%entries(index)%get_matrix()
602 if (all(scratch_entry%get_dims() .eq. [nrows, ncols])) then
603 this%inuse(index) = .true.
604 exit
605 end if
606 nullify(scratch_entry)
607 end do
608
609 ! If no compatible, unused objects are found, expand and create a new one.
610 if (index .gt. this%n_entries) then
611 this%n_entries = this%n_entries + 1
612
613 if (this%n_entries .gt. size(this%entries)) call this%expand()
614 call this%entries(this%n_entries)%init_matrix(nrows, ncols)
615 scratch_entry => this%entries(this%n_entries)%get_matrix()
616
617 this%inuse(this%n_entries) = .true.
618 end if
619 !$omp end critical (SCRATCH_OMP_LOCK)
620
621 ! Assign the pointer to the entry and clear the values if requested.
622 if (clear) call matrix_rzero(scratch_entry)
623
624 end subroutine request_matrix
625
628 subroutine relinquish_matrix_single(this, index)
629 class(scratch_registry_t), intent(inout) :: this
630 integer, intent(in) :: index
631
632 call this%relinquish_type(index, 'matrix')
633 end subroutine relinquish_matrix_single
634
637 subroutine relinquish_matrix_multiple(this, indices)
638 class(scratch_registry_t), intent(inout) :: this
639 integer, intent(in) :: indices(:)
640 integer :: i
641
642 do i = 1, size(indices)
643 call this%relinquish_type(indices(i), 'matrix')
644 end do
645 end subroutine relinquish_matrix_multiple
646
654 subroutine request_tensor3(this, scratch_entry, index, n, m, l, clear)
655 class(scratch_registry_t), target, intent(inout) :: this
656 type(tensor3_t), pointer, intent(inout) :: scratch_entry
657 integer, intent(inout) :: index
658 integer, intent(in) :: n, m, l
659 logical, intent(in) :: clear
660
661 ! Look for a compatible, unused object in the registry.
662 !$omp critical (SCRATCH_OMP_LOCK)
663 do index = 1, this%n_entries
664
665 ! Find an unused object of the correct type.
666 if (this%inuse(index)) cycle
667 if (.not. this%entries(index)%is_type('tensor3')) cycle
668
669 ! Check compatibility of the object size.
670 scratch_entry => this%entries(index)%get_tensor3()
671 if (all(scratch_entry%get_dims() .eq. [n, m, l])) then
672 this%inuse(index) = .true.
673 exit
674 end if
675 nullify(scratch_entry)
676 end do
677
678 ! If no compatible, unused objects are found, expand and create a new one.
679 if (index .gt. this%n_entries) then
680 this%n_entries = this%n_entries + 1
681
682 if (this%n_entries .gt. size(this%entries)) call this%expand()
683 call this%entries(this%n_entries)%init_tensor3(n, m, l)
684 scratch_entry => this%entries(this%n_entries)%get_tensor3()
685
686 this%inuse(this%n_entries) = .true.
687 end if
688 !$omp end critical (SCRATCH_OMP_LOCK)
689
690 ! Assign the pointer to the entry and clear the values if requested.
691 if (clear) then
692 if (neko_bcknd_device .eq. 1) then
693 call device_rzero(scratch_entry%x_d, scratch_entry%size())
694 else
695 call rzero(scratch_entry%x, scratch_entry%size())
696 end if
697 end if
698
699 end subroutine request_tensor3
700
703 subroutine relinquish_tensor3_single(this, index)
704 class(scratch_registry_t), intent(inout) :: this
705 integer, intent(in) :: index
706
707 call this%relinquish_type(index, 'tensor3')
708 end subroutine relinquish_tensor3_single
709
712 subroutine relinquish_tensor3_multiple(this, indices)
713 class(scratch_registry_t), intent(inout) :: this
714 integer, intent(in) :: indices(:)
715 integer :: i
716
717 do i = 1, size(indices)
718 call this%relinquish_type(indices(i), 'tensor3')
719 end do
720 end subroutine relinquish_tensor3_multiple
721
730 subroutine request_tensor4(this, scratch_entry, index, n, m, l, k, clear)
731 class(scratch_registry_t), target, intent(inout) :: this
732 type(tensor4_t), pointer, intent(inout) :: scratch_entry
733 integer, intent(inout) :: index
734 integer, intent(in) :: n, m, l, k
735 logical, intent(in) :: clear
736
737 ! Look for a compatible, unused object in the registry.
738 !$omp critical (SCRATCH_OMP_LOCK)
739 do index = 1, this%n_entries
740
741 ! Find an unused object of the correct type.
742 if (this%inuse(index)) cycle
743 if (.not. this%entries(index)%is_type('tensor4')) cycle
744
745 ! Check compatibility of the object size.
746 scratch_entry => this%entries(index)%get_tensor4()
747 if (all(scratch_entry%get_dims() .eq. [n, m, l, k])) then
748 this%inuse(index) = .true.
749 exit
750 end if
751 nullify(scratch_entry)
752 end do
753
754 ! If no compatible, unused objects are found, expand and create a new one.
755 if (index .gt. this%n_entries) then
756 this%n_entries = this%n_entries + 1
757
758 if (this%n_entries .gt. size(this%entries)) call this%expand()
759 call this%entries(this%n_entries)%init_tensor4(n, m, l, k)
760 scratch_entry => this%entries(this%n_entries)%get_tensor4()
761
762 this%inuse(this%n_entries) = .true.
763 end if
764 !$omp end critical (SCRATCH_OMP_LOCK)
765
766 ! Assign the pointer to the entry and clear the values if requested.
767 if (clear) then
768 if (neko_bcknd_device .eq. 1) then
769 call device_rzero(scratch_entry%x_d, scratch_entry%size())
770 else
771 call rzero(scratch_entry%x, scratch_entry%size())
772 end if
773 end if
774
775 end subroutine request_tensor4
776
779 subroutine relinquish_tensor4_single(this, index)
780 class(scratch_registry_t), intent(inout) :: this
781 integer, intent(in) :: index
782
783 call this%relinquish_type(index, 'tensor4')
784 end subroutine relinquish_tensor4_single
785
788 subroutine relinquish_tensor4_multiple(this, indices)
789 class(scratch_registry_t), intent(inout) :: this
790 integer, intent(in) :: indices(:)
791 integer :: i
792
793 do i = 1, size(indices)
794 call this%relinquish_type(indices(i), 'tensor4')
795 end do
796 end subroutine relinquish_tensor4_multiple
797
802 subroutine request_field_stored_dof(this, scratch_entry, index, clear)
803 class(scratch_registry_t), target, intent(inout) :: this
804 type(field_t), pointer, intent(inout) :: scratch_entry
805 integer, intent(inout) :: index
806 logical, intent(in) :: clear
807 character(len=10) :: name
808
809 if (.not. associated(this%dof)) then
810 call neko_error("scratch_registry::request_field_stored_dof: " &
811 // "No dofmap assigned to scratch registry.")
812 end if
813
814 ! Look for a compatible, unused object in the registry.
815 !$omp critical (SCRATCH_OMP_LOCK)
816 do index = 1, this%n_entries
817
818 ! Find an unused object of the correct type.
819 if (this%inuse(index)) cycle
820 if (.not. this%entries(index)%is_type('field')) cycle
821
822 ! Check compatibility of the object size.
823 scratch_entry => this%entries(index)%get_field()
824 if (associated(scratch_entry%dof, this%dof)) then
825 this%inuse(index) = .true.
826 exit
827 end if
828 nullify(scratch_entry)
829 end do
830
831 ! If no compatible, unused objects are found, expand and create a new one.
832 if (index .gt. this%n_entries) then
833 this%n_entries = this%n_entries + 1
834
835 if (this%n_entries .gt. size(this%entries)) call this%expand()
836 write(name, "(A3,I0.3)") "wrk", this%n_entries
837 call this%entries(this%n_entries)%init_field(this%dof, name)
838 scratch_entry => this%entries(this%n_entries)%get_field()
839
840 this%inuse(this%n_entries) = .true.
841 end if
842 !$omp end critical (SCRATCH_OMP_LOCK)
843
844 ! Assign the pointer to the entry and clear the values if requested.
845 if (clear) call field_rzero(scratch_entry)
846
847 end subroutine request_field_stored_dof
848
854 subroutine request_field_free_dof(this, scratch_entry, index, dof, clear)
855 class(scratch_registry_t), target, intent(inout) :: this
856 type(field_t), pointer, intent(inout) :: scratch_entry
857 integer, intent(inout) :: index
858 type(dofmap_t), target, intent(in) :: dof
859 logical, intent(in) :: clear
860 character(len=10) :: name
861
862 ! Look for a compatible, unused object in the registry.
863 !$omp critical (SCRATCH_OMP_LOCK)
864 do index = 1, this%n_entries
865
866 ! Find an unused object of the correct type.
867 if (this%inuse(index)) cycle
868 if (.not. this%entries(index)%is_type('field')) cycle
869
870 ! Check compatibility of the object size.
871 scratch_entry => this%entries(index)%get_field()
872 if (associated(scratch_entry%dof, dof)) then
873 this%inuse(index) = .true.
874 exit
875 end if
876 nullify(scratch_entry)
877 end do
878
879 ! If no compatible, unused objects are found, expand and create a new one.
880 if (index .gt. this%n_entries) then
881 this%n_entries = this%n_entries + 1
882
883 if (this%n_entries .gt. size(this%entries)) call this%expand()
884 write(name, "(A3,I0.3)") "wrk", this%n_entries
885 call this%entries(this%n_entries)%init_field(dof, name)
886 scratch_entry => this%entries(this%n_entries)%get_field()
887
888 this%inuse(this%n_entries) = .true.
889 end if
890 !$omp end critical (SCRATCH_OMP_LOCK)
891
892 ! Assign the pointer to the entry and clear the values if requested.
893 if (clear) call field_rzero(scratch_entry)
894 end subroutine request_field_free_dof
895
898 subroutine relinquish_field_single(this, index)
899 class(scratch_registry_t), intent(inout) :: this
900 integer, intent(in) :: index
901
902 call this%relinquish_type(index, 'field')
903 end subroutine relinquish_field_single
904
907 subroutine relinquish_field_multiple(this, indices)
908 class(scratch_registry_t), intent(inout) :: this
909 integer, intent(in) :: indices(:)
910 integer :: i
911
912 do i = 1, size(indices)
913 call this%relinquish_type(indices(i), 'field')
914 end do
915 end subroutine relinquish_field_multiple
916
917 ! -------------------------------------------------------------------------- !
918 ! Type generic procedures for the scratch registry
919
922 subroutine relinquish_single(this, index)
923 class(scratch_registry_t), intent(inout) :: this
924 integer, intent(in) :: index
925
926 !$omp critical (SCRATCH_OMP_LOCK)
927 this%inuse(index) = .false.
928 !$omp end critical (SCRATCH_OMP_LOCK)
929
930 end subroutine relinquish_single
931
934 subroutine relinquish_multiple(this, indices)
935 class(scratch_registry_t), intent(inout) :: this
936 integer, intent(in) :: indices(:)
937 integer :: i
938
939 do i = 1, size(indices)
940 call this%relinquish_single(indices(i))
941 end do
942 end subroutine relinquish_multiple
943
944 ! -------------------------------------------------------------------------- !
945 ! Private helper procedures
946
950 subroutine relinquish_type(this, index, type)
951 class(scratch_registry_t), intent(inout) :: this
952 integer, intent(in) :: index
953 character(len=*), intent(in) :: type
954 character(len=256) :: msg
955
956 !$omp critical (SCRATCH_OMP_LOCK)
957 if (trim(this%entries(index)%get_type()) .ne. type) then
958 write(msg, "(A,1X,A,1X,A,A)") "scratch_registry::relinquish:", &
959 "Entry is not a", trim(type), "."
960 call neko_error(trim(msg))
961 end if
962
963 this%inuse(index) = .false.
964 !$omp end critical (SCRATCH_OMP_LOCK)
965 end subroutine relinquish_type
966
968 subroutine expand(this)
969 class(scratch_registry_t), intent(inout) :: this
970 type(registry_entry_t), allocatable :: temp(:)
971 logical, allocatable :: temp2(:)
972 integer :: i, n
973
974 n = size(this%entries)
975 if (n .gt. 0) then
976 call move_alloc(this%entries, temp)
977 call move_alloc(this%inuse, temp2)
978 end if
979
980 allocate(this%entries(n + this%expansion_size))
981 allocate(this%inuse(n + this%expansion_size), source = .false.)
982
983 if (n .gt. 0) then
984 do i = 1, n
985 call this%entries(i)%move_from(temp(i))
986 this%inuse(i) = temp2(i)
987 call temp(i)%free()
988 end do
989 end if
990
991 if (allocated(temp)) deallocate(temp)
992 if (allocated(temp2)) deallocate(temp2)
993
994 end subroutine expand
995
996end module scratch_registry
Module containing device only array type.
subroutine, public device_rzero(a_d, n, strm)
Zero a real vector.
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
subroutine, public field_rzero(a, n)
Zero a real vector.
Defines a field.
Definition field.f90:34
Module containing host-only array type.
Definition math.f90:60
subroutine, public rzero(a, n)
Zero a real vector.
Definition math.f90:239
subroutine, public matrix_rzero(a, n)
Zero a real matrix .
Defines a matrix.
Definition matrix.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a registry entry for storing and requesting temporary objects This is used in the registries ...
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
logical function get_inuse(this, index)
Get the inuse status for a given index.
subroutine relinquish_matrix_single(this, index)
Relinquish the use of a matrix in the registry.
subroutine scratch_registry_free(this)
Destructor.
subroutine request_tensor3(this, scratch_entry, index, n, m, l, clear)
Get a tensor3 from the registry by assigning it to a pointer.
subroutine relinquish_matrix_multiple(this, indices)
Relinquish the use of multiple matrices in the registry.
subroutine request_vector(this, scratch_entry, index, n, clear)
Get a vector from the registry by assigning it to a pointer.
subroutine relinquish_host_array_single(this, index)
Relinquish the use of a host_array in the registry.
subroutine request_field_free_dof(this, scratch_entry, index, dof, clear)
Get a field from the registry by assigning it to a pointer.
subroutine relinquish_device_array_multiple(this, indices)
Relinquish the use of multiple device_arrays in the registry.
subroutine relinquish_tensor3_single(this, index)
Relinquish the use of a tensor3 in the registry.
integer function get_n_entries(this)
Get the number of objects stored in the registry.
subroutine request_device_array(this, scratch_entry, index, n, clear)
Get a device array from the registry by assigning it to a pointer.
subroutine relinquish_field_single(this, index)
Relinquish the use of a field in the registry.
subroutine relinquish_host_array_multiple(this, indices)
Relinquish the use of multiple host_arrays in the registry.
subroutine relinquish_tensor3_multiple(this, indices)
Relinquish the use of multiple tensor3s in the registry.
subroutine scratch_registry_set_dofmap(this, dof)
Assign a dofmap to the scratch registry.
subroutine relinquish_field_multiple(this, indices)
Relinquish the use of multiple fields in the registry.
subroutine request_host_array(this, scratch_entry, index, n, clear)
Get a host array from the registry by assigning it to a pointer.
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
subroutine relinquish_vector_multiple(this, indices)
Relinquish the use of multiple vectors in the registry.
integer function get_size(this)
Get the size of the objects array.
subroutine request_tensor4(this, scratch_entry, index, n, m, l, k, clear)
Get a tensor4 from the registry by assigning it to a pointer.
subroutine scratch_registry_set_expansion_size(this, expansion_size)
Assign a new expansion size to the scratch registry.
subroutine expand(this)
Expand the registry by expansion_size.
subroutine request_matrix(this, scratch_entry, index, nrows, ncols, clear)
Get a matrix from the registry by assigning it to a pointer.
subroutine relinquish_device_array_single(this, index)
Relinquish the use of a device_array in the registry.
integer function get_n_inuse(this)
Get the number of objects currently in use.
subroutine relinquish_tensor4_single(this, index)
Relinquish the use of a tensor4 in the registry.
subroutine request_field_stored_dof(this, scratch_entry, index, clear)
Get a field from the registry by assigning it to a pointer.
subroutine relinquish_vector_single(this, index)
Relinquish the use of a vector in the registry.
subroutine scratch_registry_init(this, size, expansion_size, dof)
Constructor, optionally taking initial registry and expansion size as argument.
subroutine relinquish_type(this, index, type)
Relinquish a single index based on a specified type.
subroutine relinquish_multiple(this, indices)
Relinquish the use of multiple objects in the registry.
subroutine relinquish_single(this, index)
Relinquish the use of an object in the registry.
subroutine relinquish_tensor4_multiple(this, indices)
Relinquish the use of multiple tensor4s in the registry.
pure integer function get_expansion_size(this)
Get the expansion size.
Defines a rank-3 tensor.
Definition tensor3.f90:34
Defines a rank-4 tensor.
Definition tensor4.f90:34
Utilities.
Definition utils.f90:35
subroutine, public vector_rzero(a, n)
Zero a real vector.
Defines a vector.
Definition vector.f90:34
Device-only temporary array.
Host-only temporary array.