35     type(model_state_type), 
target, 
intent(inout) :: current_state
 
   37     character(len=STRING_LENGTH) :: method
 
   39     method=options_get_string(current_state%options_database, 
"decomposition_method")
 
   41     if (method .eq. 
"onedim") 
then 
   43     else if (method .eq. 
"twodim") 
then 
   47        if (method .ne. 
"serial") 
call log_log(log_warn, 
"Decomposition method "//trim(method)//&
 
   48             " not recognised so defaulting to serial")
 
   58     type(model_state_type), 
intent(inout) :: current_state
 
   61     integer, 
dimension(2) :: coords, distributed_dims
 
   63     current_state%local_grid%active = current_state%global_grid%active
 
   64     current_state%local_grid%dimensions = current_state%global_grid%dimensions
 
   66     if (current_state%global_grid%dimensions .ne. 3) 
then 
   67        call log_master_log(log_warn, 
"Two dimension decomposition selected with only "// &
 
   68             trim(conv_to_string(current_state%global_grid%dimensions)) //
" so defaulting to one dimension instead")
 
   73     distributed_dims= (/0,0/)
 
   74     call mpi_dims_create(current_state%parallel%processes, 2, distributed_dims, ierr)
 
   76     current_state%parallel%dim_sizes(z_index)=1
 
   77     current_state%parallel%dim_sizes(y_index) = distributed_dims(1)
 
   78     current_state%parallel%dim_sizes(x_index) = distributed_dims(2)
 
   81          current_state%parallel%dim_sizes(x_index))) 
then 
   82        call log_master_log(log_warn, 
"Defaulting to one dimension decomposition due to solution size too small")
 
   87     call mpi_cart_create(current_state%parallel%monc_communicator, 2, (/distributed_dims(1), distributed_dims(2)/),&
 
   88          (/.false., .false./), .false., current_state%parallel%neighbour_comm, ierr)
 
   89     call mpi_cart_coords(current_state%parallel%neighbour_comm, current_state%parallel%my_rank, 2, coords, ierr)
 
   96          current_state%global_grid%active(y_index)), distributed_dims(1), coords(1))
 
   98          current_state%global_grid%active(x_index)), distributed_dims(2), coords(2))
 
  105     if (log_get_logging_level() .ge. log_debug) 
then 
  106        call log_log(log_debug, 
"PID "//trim(conv_to_string(current_state%parallel%my_rank))//
": y="//&
 
  107             trim(conv_to_string(current_state%parallel%my_coords(y_index)))//&
 
  108             " x="//trim(conv_to_string(current_state%parallel%my_coords(x_index)))//
" ny-1="//&
 
  109             trim(conv_to_string(current_state%local_grid%neighbours(y_index,1)))//&
 
  110             " ny+1="//trim(conv_to_string(current_state%local_grid%neighbours(y_index,3)))//
" nx-1="//&
 
  111             trim(conv_to_string(current_state%local_grid%neighbours(x_index,1)))//
" nx+1="//&
 
  112             trim(conv_to_string(current_state%local_grid%neighbours(x_index,3))))
 
  126     type(model_state_type), 
intent(inout) :: current_state
 
  127     integer, 
intent(in) :: y_procs, x_procs, coords(2)
 
  129     integer :: ierr, i, halo_depth
 
  131     current_state%parallel%wrapped_around=.false.
 
  133     call mpi_cart_shift(current_state%parallel%neighbour_comm, 0, 1, current_state%local_grid%neighbours(y_index,1), &
 
  134          current_state%local_grid%neighbours(y_index,3), ierr)
 
  135     if (current_state%local_grid%neighbours(y_index,1) .lt. 0) 
then 
  136       call mpi_cart_rank(current_state%parallel%neighbour_comm,&
 
  137            (/y_procs-1, coords(2)/),  current_state%local_grid%neighbours(y_index,1), ierr)
 
  138       current_state%parallel%wrapped_around(y_index, 1)=.true.
 
  141     if (current_state%local_grid%neighbours(y_index,3) .lt. 0) 
then 
  142       call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  143          (/0, coords(2)/),  current_state%local_grid%neighbours(y_index,3), ierr)
 
  144       current_state%parallel%wrapped_around(y_index, 2)=.true.
 
  148     call mpi_cart_shift(current_state%parallel%neighbour_comm, 1, 1, &
 
  149          current_state%local_grid%neighbours(x_index,1), &
 
  150          current_state%local_grid%neighbours(x_index,3), ierr)
 
  151     if (current_state%local_grid%neighbours(x_index,1) .lt. 0) 
then 
  152       call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  153          (/coords(1), x_procs-1/),  current_state%local_grid%neighbours(x_index,1), ierr)
 
  154       current_state%parallel%wrapped_around(x_index, 1)=.true.
 
  156     if (current_state%local_grid%neighbours(x_index,3) .lt. 0) 
then 
  157       call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  158          (/coords(1), 0/),  current_state%local_grid%neighbours(x_index,3), ierr)
 
  159       current_state%parallel%wrapped_around(x_index, 2)=.true.
 
  163     halo_depth = options_get_integer(current_state%options_database, 
"halo_depth")
 
  165     do i = 1, halo_depth -1
 
  166        current_state%local_grid%neighbours(y_index,i+1) = &
 
  167             current_state%local_grid%neighbours(y_index,i)
 
  168        current_state%local_grid%neighbours(y_index,i+halo_depth + 1) = &
 
  169             current_state%local_grid%neighbours(y_index,i+halo_depth)
 
  170        current_state%local_grid%neighbours(x_index,i+1) = &
 
  171             current_state%local_grid%neighbours(x_index,i)
 
  172        current_state%local_grid%neighbours(x_index,i+halo_depth + 1) = &
 
  173             current_state%local_grid%neighbours(x_index,i+halo_depth)
 
  176     call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  177          (/merge(coords(1)-1, y_procs-1, coords(1) .ge. 1),   &
 
  178          merge(coords(2)-1, x_procs-1, coords(2) .ge. 1)/),   &
 
  179          current_state%local_grid%corner_neighbours(1,1), ierr)
 
  180     call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  181          (/merge(coords(1)-1, y_procs-1, coords(1) .ge. 1),   &
 
  182          merge(coords(2)+1, 0, coords(2) .lt. x_procs-1)/),   &
 
  183          current_state%local_grid%corner_neighbours(2,1), ierr)
 
  184     call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  185          (/merge(coords(1)+1, 0, coords(1) .lt. y_procs-1),   &
 
  186          merge(coords(2)-1, x_procs-1, coords(2) .ge. 1)/),   &
 
  187          current_state%local_grid%corner_neighbours(3,1), ierr)
 
  188     call mpi_cart_rank(current_state%parallel%neighbour_comm, &
 
  189          (/merge(coords(1)+1, 0, coords(1) .lt. y_procs-1),   &
 
  190          merge(coords(2)+1, 0, coords(2) .lt. x_procs-1)/),   &
 
  191          current_state%local_grid%corner_neighbours(4,1), ierr)
 
  194     current_state%local_grid%corner_neighbours(:,2)=current_state%local_grid%corner_neighbours(:,1)
 
  203     type(model_state_type), 
intent(inout) :: current_state
 
  204     integer, 
intent(in) :: y_dims, x_dims
 
  206     if (current_state%global_grid%active(y_index)) 
then 
  207        if (floor(real(current_state%global_grid%size(y_index)) / y_dims) .lt. 2) 
then 
  212     if (current_state%global_grid%active(x_index)) 
then 
  213        if (floor(real(current_state%global_grid%size(x_index)) / x_dims) .lt. 2) 
then 
  228     type(model_state_type), 
intent(inout) :: current_state
 
  229     integer, 
intent(in) :: dim, dim_size, dim_my_rank, dim_processes
 
  231     integer :: dimension_division, dimension_extra
 
  233     dimension_division = dim_size / dim_processes
 
  234     dimension_extra = dim_size - (dimension_division * dim_processes)
 
  236     current_state%local_grid%start(dim) = dimension_division*dim_my_rank + merge(dimension_extra, dim_my_rank, &
 
  237          dimension_extra .lt. dim_my_rank) + 1
 
  238     current_state%local_grid%end(dim) = (current_state%local_grid%start(dim)-1) + dimension_division + &
 
  239          merge(1, 0, dim_my_rank .lt. dimension_extra)
 
  240     current_state%local_grid%size(dim)=(current_state%local_grid%end(dim) - current_state%local_grid%start(dim)) + 1
 
  241     current_state%parallel%my_coords(dim) = dim_my_rank
 
  248     type(model_state_type), 
intent(inout) :: current_state
 
  250     current_state%local_grid%start(z_index) = 1
 
  251     current_state%local_grid%end(z_index) = current_state%global_grid%size(z_index)
 
  252     current_state%local_grid%size(z_index) = current_state%global_grid%size(z_index)
 
  253     current_state%parallel%my_coords(z_index) = 0
 
  254     current_state%parallel%dim_sizes(z_index) = 1
 
  263     type(model_state_type), 
intent(inout) :: current_state
 
  265     integer :: x_size, y_size, split_size, dimension_division, dimension_extra
 
  269     current_state%parallel%wrapped_around=.false.
 
  271     x_size = merge(current_state%global_grid%size(x_index), 1, current_state%global_grid%active(x_index))
 
  272     y_size = merge(current_state%global_grid%size(y_index), 1, current_state%global_grid%active(y_index))
 
  274     split_size = merge(x_size, y_size, x_size .gt. y_size)
 
  275     dimension_division = split_size / current_state%parallel%processes
 
  276     dimension_extra = split_size - (dimension_division * current_state%parallel%processes)
 
  278     current_state%local_grid%active = current_state%global_grid%active
 
  279     current_state%local_grid%dimensions = current_state%global_grid%dimensions
 
  280     current_state%parallel%neighbour_comm = current_state%parallel%monc_communicator
 
  283     if (x_size .gt. y_size) 
then 
  285       current_state%local_grid%start(y_index)=1
 
  286       current_state%local_grid%end(y_index)=y_size
 
  287       current_state%local_grid%size(y_index)=y_size
 
  288       current_state%parallel%my_coords(y_index)=0
 
  289       current_state%parallel%dim_sizes(y_index)=1
 
  290       current_state%local_grid%start(x_index)=dimension_division*current_state%parallel%my_rank+merge(&
 
  291            dimension_extra, current_state%parallel%my_rank, dimension_extra .lt. current_state%parallel%my_rank) + 1
 
  292       current_state%local_grid%end(x_index)=(current_state%local_grid%start(x_index)-1) + dimension_division + merge(&
 
  293            1, 0, current_state%parallel%my_rank .lt. dimension_extra)
 
  294       current_state%local_grid%size(x_index)=(current_state%local_grid%end(x_index) - current_state%local_grid%start(x_index)) + 1
 
  295       current_state%parallel%my_coords(x_index) = current_state%parallel%my_rank
 
  296       current_state%parallel%dim_sizes(x_index) = current_state%parallel%processes
 
  297       current_state%local_grid%neighbours(y_index,:) = current_state%parallel%my_rank
 
  299       current_state%local_grid%neighbours(x_index,1:2) = merge(current_state%parallel%my_rank, current_state%parallel%processes, &
 
  300            current_state%parallel%my_rank .gt. 0) - 1
 
  301       current_state%parallel%wrapped_around(x_index, 1)=&
 
  302            current_state%local_grid%neighbours(x_index,1)==current_state%parallel%processes-1
 
  303       current_state%local_grid%neighbours(x_index,3:4) = merge(current_state%parallel%my_rank+1, 0, &
 
  304            current_state%parallel%my_rank .lt. current_state%parallel%processes-1)
 
  305       current_state%parallel%wrapped_around(x_index, 2)=current_state%local_grid%neighbours(x_index,3)==0
 
  306       current_state%local_grid%corner_neighbours(1,:)=current_state%local_grid%neighbours(x_index,1)
 
  307       current_state%local_grid%corner_neighbours(3,:)=current_state%local_grid%neighbours(x_index,1)
 
  308       current_state%local_grid%corner_neighbours(2,:)=current_state%local_grid%neighbours(x_index,3)
 
  309       current_state%local_grid%corner_neighbours(4,:)=current_state%local_grid%neighbours(x_index,3)
 
  310       current_state%parallel%wrapped_around(y_index, :)=.true.
 
  313       current_state%local_grid%start(x_index)=1
 
  314       current_state%local_grid%end(x_index)=x_size
 
  315       current_state%local_grid%size(x_index)=x_size
 
  316       current_state%parallel%my_coords(x_index)=0
 
  317       current_state%parallel%dim_sizes(x_index)=1
 
  318       current_state%local_grid%start(y_index)=dimension_division*current_state%parallel%my_rank+merge(&
 
  319            dimension_extra, current_state%parallel%my_rank, dimension_extra .lt. current_state%parallel%my_rank) + 1
 
  320       current_state%local_grid%end(y_index)=(current_state%local_grid%start(y_index)-1) + dimension_division + merge(&
 
  321            1, 0, current_state%parallel%my_rank .lt. dimension_extra)
 
  322       current_state%local_grid%size(y_index)=(current_state%local_grid%end(y_index) - current_state%local_grid%start(y_index)) + 1
 
  323       current_state%parallel%my_coords(y_index)=current_state%parallel%my_rank
 
  324       current_state%parallel%dim_sizes(y_index) = current_state%parallel%processes
 
  325       current_state%local_grid%neighbours(x_index,:) = current_state%parallel%my_rank
 
  326       current_state%local_grid%neighbours(y_index,1:2) = merge(current_state%parallel%my_rank, current_state%parallel%processes, &
 
  327            current_state%parallel%my_rank .gt. 0) - 1
 
  328       current_state%parallel%wrapped_around(y_index, 1)=&
 
  329            current_state%local_grid%neighbours(y_index,1)==current_state%parallel%processes-1
 
  330       current_state%local_grid%neighbours(y_index,3:4) = merge(current_state%parallel%my_rank+1, 0, &
 
  331            current_state%parallel%my_rank .lt. current_state%parallel%processes-1)
 
  332       current_state%parallel%wrapped_around(y_index, 2)=current_state%local_grid%neighbours(y_index,3)==0
 
  333       current_state%local_grid%corner_neighbours(1:2,:)=current_state%local_grid%neighbours(y_index,1)
 
  334       current_state%local_grid%corner_neighbours(3:4,:)=current_state%local_grid%neighbours(y_index,3)
 
  335       current_state%parallel%wrapped_around(x_index, :)=.true.
 
  347     type(model_state_type), 
intent(inout) :: current_state
 
  351     current_state%local_grid%active = current_state%global_grid%active
 
  352     current_state%local_grid%dimensions = current_state%global_grid%dimensions
 
  353     current_state%parallel%neighbour_comm = current_state%parallel%monc_communicator
 
  356     current_state%local_grid%start(y_index)=1
 
  357     current_state%local_grid%start(x_index)=1
 
  358     current_state%parallel%my_coords(y_index)=0
 
  359     current_state%parallel%my_coords(x_index)=0
 
  360     current_state%parallel%dim_sizes(y_index)=0
 
  361     current_state%parallel%dim_sizes(x_index)=0
 
  363     current_state%local_grid%end(x_index)= &
 
  364          merge(current_state%global_grid%size(x_index), 1, current_state%global_grid%active(x_index))
 
  365     current_state%local_grid%size(x_index)=current_state%local_grid%end(x_index)
 
  367     current_state%local_grid%end(y_index)=&
 
  368          merge(current_state%global_grid%size(y_index), 1, current_state%global_grid%active(y_index))
 
  369     current_state%local_grid%size(y_index)=current_state%local_grid%end(y_index)
 
  371     current_state%local_grid%neighbours(x_index,:) = current_state%parallel%my_rank
 
  372     current_state%local_grid%neighbours(y_index,:) = current_state%parallel%my_rank
 
  373     current_state%local_grid%corner_neighbours=current_state%parallel%my_rank
 
  375     current_state%parallel%wrapped_around=.true.
 
  385     type(model_state_type), 
intent(inout) :: current_state
 
  386     character(len=*), 
intent(in) :: decomp_name
 
  388     if (log_get_logging_level() .le. log_debug) 
then 
  389        call log_log(log_debug, decomp_name//
" rank="//trim(conv_to_string(current_state%parallel%my_rank))//&
 
  390             ": W=("//trim(conv_to_string(current_state%local_grid%start(z_index)))//
"->"&
 
  391             //trim(conv_to_string(current_state%local_grid%end(z_index)))//
") V=("//trim(conv_to_string(&
 
  392             current_state%local_grid%start(y_index)))//
"->"//trim(conv_to_string(current_state%local_grid%end(&
 
  393             y_index)))//
") U=("//trim(conv_to_string(current_state%local_grid%start(x_index)))//&
 
  394             "->"//trim(conv_to_string(current_state%local_grid%end(x_index)))//
")")
 
  395        call log_log(log_debug, 
"Neighbours of "//trim(conv_to_string(current_state%parallel%my_rank))//
": y=(["//&
 
  396             trim(conv_to_string(current_state%local_grid%neighbours(y_index,1)))//
"],["//&
 
  397             trim(conv_to_string(current_state%local_grid%neighbours(y_index,2)))//
"]) x=(["//&
 
  398             trim(conv_to_string(current_state%local_grid%neighbours(x_index,1)))//
","//&
 
  399             trim(conv_to_string(current_state%local_grid%neighbours(x_index,2)))//
"],["//&
 
  400             trim(conv_to_string(current_state%local_grid%neighbours(x_index,3)))//
","//&
 
  401             trim(conv_to_string(current_state%local_grid%neighbours(x_index,4)))//
"])")
 
  402        call log_master_log(log_debug, 
"Halo size z="//&
 
  403             trim(conv_to_string(current_state%local_grid%halo_size(z_index)))//&
 
  404             " y="//trim(conv_to_string(current_state%local_grid%halo_size(y_index)))//
" x="//&
 
  405             trim(conv_to_string(current_state%local_grid%halo_size(x_index))))
 
  407     call log_master_log(log_info, 
"Decomposed "//trim(conv_to_string(current_state%parallel%processes))//&
 
  408          " processes via '"//decomp_name// 
"' into z="//trim(conv_to_string(current_state%parallel%dim_sizes(&
 
  409          z_index)))//
" y="//trim(conv_to_string(current_state%parallel%dim_sizes(y_index)))//
" x="//&
 
  410          trim(conv_to_string(current_state%parallel%dim_sizes(x_index))))
 
  417     type(local_grid_type), 
intent(inout) :: local_grid
 
  425        local_grid%local_domain_start_index(i) = local_grid%halo_size(i) + 1
 
  426        local_grid%local_domain_end_index(i) = local_grid%halo_size(i) + local_grid%size(i)
 
  441     type(model_state_type), 
target, 
intent(inout) :: current_state
 
  442     integer :: n_dim, n_corners,total_halo_size_XY_dim
 
  443     integer :: halo_depth
 
  446     halo_depth = options_get_integer(current_state%options_database, 
"halo_depth")
 
  449     current_state%local_grid%halo_size(z_index) = 0
 
  450     current_state%local_grid%halo_size(y_index) = halo_depth
 
  451     current_state%local_grid%halo_size(x_index) = halo_depth
 
  454     total_halo_size_xy_dim  = current_state%local_grid%halo_size(x_index)*2
 
  459     allocate(current_state%local_grid%neighbours(n_dim,total_halo_size_xy_dim), &
 
  460          current_state%local_grid%corner_neighbours(n_corners,halo_depth))