Skip to content

Commit b7574ac

Browse files
Decompose across panels (#220)
Co-authored-by: Hacka Fett <christophermaynard@users.noreply.github.com>
1 parent d2ebe4a commit b7574ac

22 files changed

Lines changed: 514 additions & 119 deletions

CONTRIBUTORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@
2020
| t00sa | Sam Clarke-Green | Met Office | 2026-01-27 |
2121
| MetBenjaminWent | Benjamin Went | Met Office | 2026-01-30 |
2222
| jcsmeto | James Cunningham-Smith | Met Office | 2026-02-06 |
23+
| thomasmelvin | Thomas Melvin | Met Office | 2026-01-15 |

components/driver/source/mesh/runtime_partition_mod.f90

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,15 @@ subroutine get_partition_strategy( mesh_selection, total_ranks, partitioner_ptr
7676
call log_event( "Using serial cubed sphere partitioner", &
7777
log_level_debug )
7878

79-
else if (mod(total_ranks,6) == 0) then
79+
else if (mod(total_ranks,3) == 0 .or. mod(total_ranks,2) == 0) then
8080
! Paralled run job
8181
partitioner_ptr => partitioner_cubedsphere
8282
call log_event( "Using parallel cubed sphere partitioner", &
8383
log_level_debug )
8484

8585
else
86-
call log_event( "Total number of processors must be 1 (serial) "// &
87-
"or a multiple of 6 for a cubed-sphere domain.", &
86+
call log_event( "Total number of processors must be 1 (serial) "// &
87+
"or a multiple of 2 or 3 for a cubed-sphere domain.", &
8888
log_level_error )
8989
end if
9090

documentation/source/how_to_use_it/technical_articles/lfric_distmem_impl.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,12 @@ supplied to the partitioner through the use of a function passed in via
177177
a function pointer.
178178

179179
For efficiency reasons, the algorithm for partitioning a cubed-sphere
180-
mesh is a specific algorithm that will only work for a cubed-sphere mesh
181-
(each panel of the cubed-sphere is split into rectangular partitions).
180+
mesh is a specific algorithm that will only work for a cubed-sphere mesh.
181+
By default each panel of the cubed-sphere is split into rectangular partitions,
182+
alternatively if the 'custom' decomposition type is used then sets of 2 or 3
183+
cubed-sphere panels can be grouped together before these sets are decomposed into
184+
a number of rectangular panels. These restrictions mean that the total number of
185+
partitions for cubed-sphere meshes needs to be a multiple of 2 or 3.
182186
This specific partitioner could be replaced with a more general
183187
partitioner for use on fully unstructured meshes.
184188

infrastructure/source/mesh/global_mesh_mod.F90

Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,79 +1019,104 @@ end function get_equatorial_latitude
10191019
!>
10201020
!> @note For a cubed -sphere mesh, this will only return correct cell IDs if
10211021
!> the offset cell remains on same the cubed-sphere "face" as the
1022-
!> start cell.
1022+
!> start cell unless check_orientation is specified.
10231023
!>
10241024
!> @param[in] cell_number ID of the anchor element.
10251025
!> @param[in] x_cells Offset in the E/W direction.
10261026
!> @param[in] y_cells Offset in the N/S direction.
1027+
!> @param[in] check_orientation Switch to check for orientation changes
1028+
!! such as when crossing panel boundaries
10271029
!>
10281030
!> @return cell_id ID of the cell at the given offset to the start cell.
10291031
!>
10301032
function get_cell_id( self, cell_number, &
1031-
x_cells, y_cells ) result ( cell_id )
1033+
x_cells, y_cells, &
1034+
check_orientation ) result ( cell_id )
10321035

10331036
use reference_element_mod, only : W, S, E, N
10341037

10351038
implicit none
10361039

10371040
class(global_mesh_type), intent(in) :: self
10381041

1039-
integer(i_def), intent(in) :: cell_number
1040-
integer(i_def), intent(in) :: x_cells, y_cells
1042+
integer(i_def), intent(in) :: cell_number
1043+
integer(i_def), intent(in) :: x_cells, y_cells
1044+
logical(l_def), optional, intent(in) :: check_orientation
10411045

1042-
integer(i_def) :: cell_id
1046+
integer(i_def) :: cell_id, old_cell_id
10431047

1044-
integer(i_def) :: index_x, dist_x
1045-
integer(i_def) :: index_y, dist_y
1046-
integer(i_def) :: i
1048+
integer(i_def) :: x_index, y_index, x_dist, y_dist, i, j
1049+
integer(i_def) :: opposite(4), rotate(4)
10471050

1048-
cell_id = cell_number
1051+
logical(l_def) :: check
10491052

1050-
! Determine march along local x-axis
1051-
if (x_cells > 0) then
1052-
index_x = E
1053-
dist_x = x_cells
1054-
else if (x_cells < 0) then
1055-
index_x = W
1056-
dist_x = abs(x_cells)
1053+
opposite = (/ E, N, W, S /)
1054+
rotate = (/ S, E, N, W /)
1055+
if ( present( check_orientation ) ) then
1056+
check = check_orientation
10571057
else
1058-
index_x = W
1059-
dist_x = 0
1058+
check = .false.
10601059
end if
10611060

1062-
! Determine march along local y-axis
1063-
if (y_cells > 0) then
1064-
index_y = N
1065-
dist_y = y_cells
1066-
else if (y_cells < 0) then
1067-
index_y = S
1068-
dist_y = abs(y_cells)
1061+
cell_id=cell_number
1062+
1063+
if (x_cells >= 0 )then
1064+
x_index = E
1065+
x_dist = x_cells
1066+
else
1067+
x_index = W
1068+
x_dist = abs(x_cells)
1069+
end if
1070+
if (y_cells >= 0 )then
1071+
y_index = N
1072+
y_dist = y_cells
10691073
else
1070-
index_y = S
1071-
dist_y = 0
1074+
y_index = S
1075+
y_dist = abs(y_cells)
10721076
end if
10731077

1074-
!========================================
1075-
! March from anchor along local x/y axes.
1076-
!========================================
1077-
do i=1, dist_x
1078+
! x_dist cells in the x-direction
1079+
do i = 1, x_dist
1080+
old_cell_id = cell_id
1081+
cell_id = self%cell_next_2d(x_index,cell_id)
10781082
if (cell_id == self%void_cell) then
10791083
! The current cell is not on the domain
10801084
write(log_scratch_space,'(A)') &
10811085
'No adjacent cell, the current cell is not on mesh domain'
10821086
call log_event(log_scratch_space, LOG_LEVEL_ERROR)
10831087
end if
1084-
cell_id = self%cell_next_2d(index_x, cell_id)
1088+
! Check if we've changed direction
1089+
if ( check .and. self%cell_next_2d(opposite(x_index),cell_id) /= old_cell_id ) then
1090+
! We have changed direction so we need to find the correct
1091+
! index and reset
1092+
do j = 1,4
1093+
if ( self%cell_next_2d(opposite(j),cell_id) == old_cell_id ) x_index = j
1094+
end do
1095+
end if
10851096
end do
1086-
1087-
do i=1, dist_y
1097+
! y_dist cells in the y-direction
1098+
! Since the direction may have changed we need to recompute
1099+
y_index = rotate(x_index)
1100+
if ( y_cells < 0 ) y_index = opposite(y_index)
1101+
1102+
! y_index and y_dist
1103+
do i = 1,y_dist
1104+
old_cell_id = cell_id
1105+
cell_id = self%cell_next_2d(y_index,cell_id)
10881106
if (cell_id == self%void_cell) then
10891107
! The current cell is not on the domain
10901108
write(log_scratch_space,'(A)') &
10911109
'No adjacent cell, the current cell is not on mesh domain'
10921110
call log_event(log_scratch_space, LOG_LEVEL_ERROR)
10931111
end if
1094-
cell_id = self%cell_next_2d(index_y, cell_id)
1112+
! Check if we've changed direction
1113+
if ( check .and. self%cell_next_2d(opposite(y_index),cell_id) /= old_cell_id ) then
1114+
! We have changed direction so we need to find the correct
1115+
! index and reset
1116+
do j = 1,4
1117+
if ( self%cell_next_2d(opposite(j),cell_id) == old_cell_id ) y_index = j
1118+
end do
1119+
end if
10951120
end do
10961121

10971122
end function get_cell_id

0 commit comments

Comments
 (0)