diff options
Diffstat (limited to 'Carpet/Carpet/src/LoadBalanceReal/carpet_region.F90')
-rw-r--r-- | Carpet/Carpet/src/LoadBalanceReal/carpet_region.F90 | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/Carpet/Carpet/src/LoadBalanceReal/carpet_region.F90 b/Carpet/Carpet/src/LoadBalanceReal/carpet_region.F90 new file mode 100644 index 000000000..60a8f5dca --- /dev/null +++ b/Carpet/Carpet/src/LoadBalanceReal/carpet_region.F90 @@ -0,0 +1,272 @@ +module carpet_region + + implicit none + + integer, parameter :: wp = selected_real_kind(12,99) + + ! These empty arrays are used to initialize variables to either the + ! min or max possible number of kind wp or integer. + real(wp), dimension(2:1) :: empty + integer, dimension(2:1) :: iempty + + + + ! Note that using intent on pointer arguments requires fortran 2003. + ! It is not allowed in fortran 90 or 95. + + ! The basic range structure with lower and upper bounds and the stride + type range + integer :: lower, upper, stride + end type range + + ! The basic box structure: a length 3 vector of ranges. + type bbox + type(range), dimension(3) :: dim + end type bbox + + ! The outer boundary information structure. + type boundary + integer, dimension(3,2) :: obound + end type boundary + +! A super region structure similar to the Carpet tree structure. + type ptr + type(superregion2), pointer :: point + end type ptr + type superregion2 + type(bbox) :: extent + type(boundary) :: outer_boundaries + integer :: map + integer :: processor + real(wp) :: frac + type(ptr), pointer :: children(:) + end type superregion2 + type superregion2slim + type(bbox) :: extent + type(boundary) :: outer_boundaries + integer :: map + integer :: processor + end type superregion2slim + + contains + +! Routine to allocate memory for a super region. Input is the bbox +! structure, outer boundary information structure and map number. +! The processor id is initialized to -1 and the pointer to the children +! is nullified. + subroutine create_sregion ( box, outerbound, map, sregion ) + type(bbox), intent(in) :: box + type(boundary), intent(in) :: outerbound + integer, intent(in) :: map +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(out) :: sregion + type(superregion2), pointer :: sregion +! gfortran dies with an internal compiler error on this initialization. +! type(superregion2), pointer, intent(out) :: sregion => null() + + allocate ( sregion ) + sregion%extent = box + sregion%outer_boundaries = outerbound + sregion%map = map + sregion%processor = -1 + sregion%frac = 0.0_wp + nullify(sregion%children) + + end subroutine create_sregion + + +! Routine to nullify the pointers of the children. This has to be used +! before destroying a temporary super region and assumes another super +! region has children with pointers to these super regions as well. +! The use of intent(in) on the sregion just ensures that sregion itself +! is not modified. Its childrens pointer can be nullified. + subroutine disassociate ( sregion ) +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(in) :: sregion + type(superregion2), pointer :: sregion + integer :: n, i + +! Only do something if the children are associated. + if ( associated(sregion%children) ) then + n = size(sregion%children) + do i = 1, n + nullify ( sregion%children(i)%point ) + end do + end if + end subroutine disassociate + + +! Routine to assign the pointers of the children of sregion1 to the same +! super regions as sregion2. + subroutine point_to_children ( sregion1, sregion2 ) +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(inout) :: sregion1 +! type(superregion2), pointer, intent(in) :: sregion2 + type(superregion2), pointer :: sregion1 + type(superregion2), pointer :: sregion2 + integer :: n1, n2, i + +! Only do something if sregion2 actually has children. + if ( associated(sregion2%children) ) then + n2 = size(sregion2%children) + +! If sregion1 has children as well make sure to deallocate their +! sub tree (this probably shouldn't happen. + if ( associated(sregion1%children) ) then + n1 = size(sregion1%children) + do i = 1, n1 + call destroy_sregion ( sregion1%children(i)%point ) + end do + end if + +! Allocate the children and assign the pointers. + allocate ( sregion1%children(n2) ) + do i = 1, n2 + sregion1%children(i)%point => sregion2%children(i)%point + end do + +! Otherwise print a warning. This should not happen. + else + print*, 'Warning sregion2 has no children' + end if + end subroutine point_to_children + + +! Routine to recursively deallocate memory for a super region. + recursive subroutine destroy_sregion ( sregion ) +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(inout) :: sregion + type(superregion2), pointer :: sregion + integer :: n, i + +! If the super region has children. + if ( associated(sregion%children) ) then + +! Find out how many children. + n = size(sregion%children) + +! Loop over all children. + do i = 1, n + +! If the children has children call recursively. + if ( associated ( sregion%children(i)%point ) ) then + call destroy_sregion ( sregion%children(i)%point ) + end if + end do + +! Then deallocate the storage for the children pointers. + if ( n > 0 ) then + deallocate ( sregion%children ) + end if + end if + +! Finally deallocate storage for the super region itself. + deallocate (sregion) + + end subroutine destroy_sregion + + +! Routine to recursively print all information about a super region tree +! structure to stdout. + recursive subroutine print_tree ( sregion ) +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(in) :: sregion + type(superregion2), pointer :: sregion + integer :: n, i + +! Only do something if the super region pointer is associated with a +! valid target. + if ( associated(sregion) ) then + print*, 'bbox = ', sregion%extent + print*, 'outer_boundaries = ', sregion%outer_boundaries + print*, 'map = ', sregion%map + print*, 'processor = ', sregion%processor + print*, 'fraction = ', sregion%frac + +! If the super region has no children... + if ( .not. associated(sregion%children) ) then + print*, 'No children ' + print* + +! Otherwise call recursively for all the children. + else + n = size(sregion%children) + print*, 'Number of children = ', n + print* + print* + do i = 1, n + call print_tree ( sregion%children(i)%point ) + print* + end do + end if + else + print*, "Pointer to super region not associated" + print* + end if + + end subroutine print_tree + + +! Split a super region into an arbitrary number of pieces in direction dir. +! The number of pieces is size(frac)+1. The integer array frac contains the +! upper boundary of the n first regions to split and has to be ordered with +! the largest element smaller than the size of the super region in direction +! dir. There is currently no check that this is indeed the case. + subroutine split_sregion ( sregion, dir, frac ) +! The intent has been removed to make it compile with gfortran 4.1. +! type(superregion2), pointer, intent(in) :: sregion + type(superregion2), pointer :: sregion + integer, intent(in) :: dir + integer, dimension(:), intent(in) :: frac + type(bbox), dimension(size(frac)+1) :: newboxes + type(boundary), dimension(size(frac)+1) :: newboundaries + integer :: n, i, lo, up, str + +! Determine the size of frac. + n = size(frac) + +! Only do something if n is larger than 0. + if (n>0) then + +! Allocate storage for the the children pointers. + allocate(sregion%children(n+1)) + +! Determine the low and high boundaries and the stride of the super +! region. + lo = sregion%extent%dim(dir)%lower + up = sregion%extent%dim(dir)%upper + str = sregion%extent%dim(dir)%stride + +! copy the bbox and boundary information from the super region. + do i = 1, n+1 + newboxes(i) = sregion%extent + newboundaries(i) = sregion%outer_boundaries + end do + +! Update the lower and upper boundaries of the children regions +! according to the number of points passed in through frac. +! Also set the outer boundary information to 0. + do i = 1, n + newboxes(i)%dim(dir)%upper = lo + ( frac(i) - 1 ) * str + newboxes(i+1)%dim(dir)%lower = newboxes(i)%dim(dir)%upper + str + newboundaries(i)%obound(dir,2) = 0 + newboundaries(i+1)%obound(dir,1) = 0 + end do + +! Allocate memory for the children and copy the bbox and outer boundary +! information in. nullify the pointers of the children to ensure that +! they are correctly disassociated. + do i = 1, n+1 + allocate ( sregion%children(i)%point ) + sregion%children(i)%point%extent = newboxes(i) + sregion%children(i)%point%outer_boundaries = newboundaries(i) + sregion%children(i)%point%map = sregion%map + sregion%children(i)%point%processor = sregion%processor + sregion%children(i)%point%frac = 0.0_wp + nullify(sregion%children(i)%point%children) + end do + end if + + end subroutine split_sregion + +end module carpet_region |