unsigned int row_size = atoi(argv[1]);
unsigned int col_size = atoi(argv[2]);

// Use cartesian coordinates
MPI_Comm comm_cart, comm_row, comm_col;
int coords[2];
int dims[2] = {row_size, col_size};
int dims_row[2] = {0, 1};
int dims_col[2] = {1, 0};
int periods[2] = {0, 0};
// row-major ordering
MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, 0, &comm_cart);
MPI_Cart_sub(comm_cart, dims_row, &comm_row);
MPI_Cart_sub(comm_cart, dims_col, &comm_col);
MPI_Cart_coords(comm_cart, rank, 2, coords);

int crank, rowrank, colrank;
MPI_Comm_rank(comm_cart, &crank);
MPI_Comm_rank(comm_row, &rowrank);
MPI_Comm_rank(comm_col, &colrank);
printf("[%d] cart %d row %d col %d coords (%d, %d)\\n", rank, crank, rowrank, colrank, coords[0], coords[1]);
$ mpirun -np 16 ./a.out 2 8
[4] cart 4 row 4 col 0 coords (0, 4)
[6] cart 6 row 6 col 0 coords (0, 6)
[7] cart 7 row 7 col 0 coords (0, 7)
[1] cart 1 row 1 col 0 coords (0, 1)
[9] cart 9 row 1 col 1 coords (1, 1)
[5] cart 5 row 5 col 0 coords (0, 5)
[0] cart 0 row 0 col 0 coords (0, 0)
[13] cart 13 row 5 col 1 coords (1, 5)
[12] cart 12 row 4 col 1 coords (1, 4)
[3] cart 3 row 3 col 0 coords (0, 3)
[8] cart 8 row 0 col 1 coords (1, 0)
[2] cart 2 row 2 col 0 coords (0, 2)
[10] cart 10 row 2 col 1 coords (1, 2)
[11] cart 11 row 3 col 1 coords (1, 3)
[15] cart 15 row 7 col 1 coords (1, 7)
[14] cart 14 row 6 col 1 coords (1, 6)