WireInTheGhost
WireInTheGhost

Reputation: 413

Algorithm for outputting 3D array

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

Upvotes: 0

Views: 283

Answers (2)

agentp
agentp

Reputation: 6989

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.

Upvotes: 1

steabert
steabert

Reputation: 6888

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).

Upvotes: 0

Related Questions