0

I am struggling to come up with an algorithm for outputting a 3D array. I basically have an array of 9 2D arrays that i need to combine into a 3X3 grid and output into a text file as a matrix. So i have:

real:: array3D(9,16,16)

And I need to sequentially(left to right, top to bottom) put these 9, 16x16 arrays together into a 3x3 grid:

real:: array2D(48,48)

Any help would be great.

[Edit: info for comments]: This is part of an MPI program where a 48x48 matrix is being split into 9 16x16 matrices, where each of 9 processes is being assigned to one 'sub-grid' of the larger array. Like a sudoku grid as mentioned in the comments, with each process applying a formula to each element within its own sub-grid. The final values calculated by each process then need to be put back into a 48x48 matrix in order to be displayed in a text file. This currently looks like this:

if(procID.ne.0)then!Send all arrays to root
    call MPI_SEND (array, row*col, MPI_REAL, 0, procID+1000, MPI_COMM_WORLD, ierr)
else
    complete(1,:,:)=array(:,:)
    do i=2, 9
        call MPI_RECV (recvArray, row*col, MPI_REAL, i-1, (i-1)+1000, MPI_COMM_WORLD, status, ierr)
        complete(i,:,:)=recvArray   
    end do

What I am trying to get is an algorithm that I can use to display complete in a text file as a matrix in such a way that it makes sense for me to read. (I know the variables names are different from above but I tried to simplify/ generalise my original problem as much as possible. Here array again has dimensions 48x48 but i am only interested with a 16x16 block within each one(9 sudoku puzzles, only want one sub-grid from each) which 16x16 block i want is defined by the first indices of complete/array3D:1-9, i want to take these sub-blocks and arrange them in another 48x48 array say arrayOut/array2D). I will try and put a graphical explanation of the problem up when i get chance if what i have written doesn't make much sense.

Thanks to @george whose answer is below, to put this in an array you need:

do majorRow=1,3
    do majorCol=1,3
        subBlock=(majorRow-1)*3+majorCol
        do minorRow=majorRow*16-(16-1),majorRow*16
            do minorCol=majorCol*16-(16-1),majorCol*16 
                outArray(minorRow,minorCol)=complete(subBlock,minorRow,minorCol)
            end do
        end do
    end do
    end do
WireInTheGhost
  • 373
  • 5
  • 11
  • Look into fortran's "do loop". – mbeckish Jan 09 '14 at 19:02
  • I know it needs a loop, most likely a triple nested one. Its the loop boundary conditions i am struggling with. – WireInTheGhost Jan 09 '14 at 19:09
  • The boundary conditions depend on how your 3x3 is organised and whether the 48 in your target array is organised row-wise (3x16) or columns-wise(16x3). You can then either loop over the three dimensions of the original array and put the elements in place in the target matrix or you can loop over the two dimensions of the target matrix and get the elements from the source. How indices are calculated depends on the layout you want. – M Oehm Jan 09 '14 at 19:28
  • `array2d(1:16,1:16)=array3d(1,1:16,1:16)` then `array2d(1:16,17:32)=array3d(2,1:16,1:16)` and so on. – Kyle Kanos Jan 09 '14 at 19:30
  • Thanks @KyleKanos thats what i currently have, but is their anyway to generalise it? – WireInTheGhost Jan 09 '14 at 19:42
  • You can use integer division and the remainder function `mod` to split your 9 dimension into 3x3 chunks. Or you cound use a lookup array for the new row and column coordinates. – M Oehm Jan 09 '14 at 19:48
  • `1+(n-1)*16:16+(n-1)*16` where `n` is the first index in `array3d` will work for the first three, you'll probably have to use `mod` to get the next three. – Kyle Kanos Jan 09 '14 at 19:51
  • @MOehm: the `3x3` he mentioned appears to be a **separate** variable from the `9x16x16` and `48x48` arrays. – Kyle Kanos Jan 09 '14 at 19:52
  • @KyleKanos: I imagine the 3D array like a large Sudoku grid addressed by cell and local row and columns and the 2D array as the same data addressed as global row and column. So the 9 dimension is a linear representation of 3x3 that shows up in the (3*16 x 3*16) 2D array. – M Oehm Jan 09 '14 at 19:57
  • @MOehm: Aha, that makes sense. – Kyle Kanos Jan 09 '14 at 20:00
  • @user2538235 - Please show the code that you have, so we can know what you know and what else you need. – mbeckish Jan 09 '14 at 20:18
  • Since arrays allow random access, you can fill the elements in any order you want. For example, you could have just two nested loops from 0..47,and inside the innermost loop figure out how to map array2D's coordinates to array3D's coordinates. Or you could do 3 nested loops to iterate through array3D's coordinates, and map those to array2D's coordinates. Or you could break it out into even more nested loops - it's up to you. Do you have a preference? – mbeckish Jan 09 '14 at 20:24
  • I have added some info above. The comment about the sudoku grid is pretty much spot on. I have an array of 9, `16x16` arrays that I would like to arrange in order 1 to 9 as they would appear in a sudoku puzzle and then output the now 2D array into a text file. The less loops the better I guess but as long as the result is correct at this stage I dont mind :) – WireInTheGhost Jan 09 '14 at 22:34
  • Your original question left out the key information that you are working on an MPI program. I think that you need to investigate `mpi_scatterv` and `mpi_gatherv` It's too late here for me to provide any more help than that but look at Jonathan Dursi's answer here: http://stackoverflow.com/questions/9269399/sending-blocks-of-2d-array-in-c-using-mpi – High Performance Mark Jan 09 '14 at 22:35
  • Isn't the fact that its an MPI program more or less irrelevant to my question? All info has been sent and gathered the problem is in displaying the data, or is their something more fundamental wrong with what i have written? I have been staring at this for day and am willing to try anything :) – WireInTheGhost Jan 09 '14 at 22:52

2 Answers2

1

no need to copy to a new array just to output.

pseudocode: (I may have transposed rows/columns but thats easily fixed)

do majorrow=1,3
 do minorrow=1,16
   do majorcol=1,3
    subblock=(majorrow-1)*3+majorcol
    do minorcol=1,16 
           write(advance=no)array3D(subblock,minorrow,minorcol)
    enddo
   enddo !end of row
   write() ! to advance line at end of row.
enddo
enddo

note the innermost loop can be replaced by

 write(advance=no)array3D(subblock,minorrow,:)

you still need no advance since you have three writes per line.

agentp
  • 6,849
  • 2
  • 19
  • 37
  • I can see and understand how this works, and thanks it is what i was asking for. But if i did want to put it into an array in order to make other manipulations, how would i get it to work. Simply changing line 6 to `outArray(minorRow,minorCol)=complete(subBlock,minorRow,minorCol)` just puts everything in the 1st subblock. – WireInTheGhost Jan 13 '14 at 14:11
  • I have now done this, ill add the code in the post. Thanks again – WireInTheGhost Jan 13 '14 at 21:59
0

If you resort to simple do-loop constructs, you just need to loop over the large 2d array in a block-wise fashion, then store the corresponding elements from the 3d array in the correct block of the 2d array.

BLKSZ=16
NBLOCK=3
DO IB=1,NBLOCK
  ISTA=BLKSZ*(IB-1)+1
  IEND=ISTA+BLKSZ-1
  DO JB=1,NBLOCK
    JSTA=BLKSZ*(JB-1)+1
    JEND=JSTA+BLKSZ-1
    array2D(ISTA:IEND,JSTA:JEND)=array3D(JB+NBLOCK*(IB-1),:,:)
  END DO
END DO

Note that the 3d array isn't very efficiently ordered, since the block index is the fastest index. Preferably, it should be the last index (avoiding cache misses).

steabert
  • 6,540
  • 2
  • 26
  • 32