MKevin has asked for the wisdom of the Perl Monks concerning the following question:

I need your help with indexing (I know this is fortran, but I have been beating my head at this all day): In short I am converting a 1d array with dimensions nx*ny*nz to a 3d array with dimensions nx,ny,nz.
do k = 0, nz - 1, 1 do j = 0, ny - 1, 1 do i = 1, nx, 1 x = i + (nx)*j + ((nx)*(ny+1))*k threeDarray(i,(j + 1),(k + 1))=oneDarray(x) enddo enddo enddo
I need an x that works at converting this correctly. Help me..... SLN: After playing around with it:                 x = i + (nx)*j + ((nx)*(ny))*k

Replies are listed 'Best First'.
Re: 1d array into 3d
by GrandFather (Saint) on Mar 31, 2009 at 04:52 UTC

    If you are using the arrays in two different subs in FORTRAN you can use COMMON blocks to do the magic:

    COMMON oneDarray(1000)

    for the sub accessing the 1d array and

    COMMON threeDarray(10, 10, 10)

    where you need 3d access. With an unnamed COMMON block you don't even have to worry about them being different lengths! ;-)


    True laziness is hard work
Re: 1d array into 3d
by BrowserUk (Patriarch) on Mar 31, 2009 at 04:12 UTC

    Whether this will work correctly will depend upon how you are constructing your 1D array. Or rather, the source from which you are constructing it. Ie. If you are reading the data in from a file dumped from FORTRAN, you may need to invert the X and Z dimensions of the data.

    I vaguely remember from my FORTRAN days, that the ordering of multi-dimensional array elements in FORTRAN is different from that in C. And I have no idea how that will translate to Perl's arrays.

    #! perl -slw use strict; use Data::Dump qw[ pp ]; my @D1 = split ' ', do{ local $/; <DATA> }; pp \@D1; my @D3 = map{ my $z = $_; [ map{ my $y = $_; [ @D1[ $z*9 + $y*3 .. $z*9 + $y*3 + 2 ] ] } 0 .. 2 ] } 0 .. 2; pp \@D3; __DATA__ z0y0x0 z0y0x1 z0y0x2 z0y1x0 z0y1x1 z0y1x2 z0y2x0 z0y2x1 z0y2x2 z1y0x0 z1y0x1 z1y0x2 z1y1x0 z1y1x1 z1y1x2 z1y2x0 z1y2z1 z1y2x2 z2y0x0 z1y0x1 z2y0x2 z2y1x0 z2y1x1 z2y1x2 z2y2x0 z2y2x1 z2y2x2

    Output:

    c:\test>754307.pl [ "z0y0x0", "z0y0x1", "z0y0x2", "z0y1x0", "z0y1x1", "z0y1x2", "z0y2x0", "z0y2x1", "z0y2x2", "z1y0x0", "z1y0x1", "z1y0x2", "z1y1x0", "z1y1x1", "z1y1x2", "z1y2x0", "z1y2z1", "z1y2x2", "z2y0x0", "z1y0x1", "z2y0x2", "z2y1x0", "z2y1x1", "z2y1x2", "z2y2x0", "z2y2x1", "z2y2x2", ] [ [ ["z0y0x0", "z0y0x1", "z0y0x2"], ["z0y1x0", "z0y1x1", "z0y1x2"], ["z0y2x0", "z0y2x1", "z0y2x2"], ], [ ["z1y0x0", "z1y0x1", "z1y0x2"], ["z1y1x0", "z1y1x1", "z1y1x2"], ["z1y2x0", "z1y2z1", "z1y2x2"], ], [ ["z2y0x0", "z1y0x1", "z2y0x2"], ["z2y1x0", "z2y1x1", "z2y1x2"], ["z2y2x0", "z2y2x1", "z2y2x2"], ], ]

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: 1d array into 3d
by ikegami (Patriarch) on Mar 31, 2009 at 03:00 UTC
    That's overly complicated.
    my $i = 0; for my $x (0..$nx-1) { for my $y (0..$ny-1) { for my $z (0..$nz-1) { $dst[$x][$y][$z] = $src[$i++]; }}}
Re: 1d array into 3d
by $self (Friar) on Mar 31, 2009 at 09:40 UTC

    The solution you've added to the end of your post is correct. To avoid making it seem (slightly) more complicated than it is, I'd just start counting at 1 in all the for-loops (not tested):

    do k = 1, nz, 1 do j = 1, ny, 1 do i = 1, nx, 1 x = i + nx * (j - 1) + (nx*ny) * (k - 1) threeDarray(i,j,k) = oneDarray(x) enddo enddo enddo

    The way you're varying the leftmost index fastest, goes well with Fortran's column-major order for storing multidimensional arrays.

Re: 1d array into 3d
by juster (Friar) on Mar 31, 2009 at 04:59 UTC

    I had fun with this:

    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; my @flat = ( 1 .. 9 ) x 3; sub make_matrix { my ($dims_ref, $flat_ref) = @_; my @dims = @$dims_ref; my $current_dim = shift @dims; my $result = []; return [ splice @$flat_ref, 0, $current_dim ] unless @dims; for ( 1 .. $current_dim ) { push @$result, make_matrix( \@dims, $flat_ref ); } return $result; } # @flat is spliced to itty bits :( my $matrix = make_matrix( [ 3, 3, 3 ], \@flat ); print Dumper($matrix); printf "%d x %d x %d\n", scalar @$matrix, scalar @{$matrix->[0]}, scalar @{$matrix->[0][0]} +;
Re: 1d array into 3d
by kyle (Abbot) on Mar 31, 2009 at 03:03 UTC

    I can't deduce what you're trying to do from code that doesn't work in a language I don't use. If you can explain what you want, there may be a monk willing to write a Perl solution that you can translate into Fortran. An example input with desired output would go a long way too.

Re: 1d array into 3d
by Anonymous Monk on Oct 12, 2011 at 14:28 UTC


    I dint properly understand the question. For whatever i have understood i am answering.

     Converting 3d to 1d:
     --------------------
     3d dimension is nx,ny,nz
     then for i,j,k
     1d_index = (k.nx.ny) + (j.nx) + i
    
     Converting back 1d to 3d:
     -------------------------
     k = 1d_index / (nx.ny)
     j = (1d_index - k.nx.ny) / nx
     i = 1d_index - k.nx.ny - j.nx
    

    Hope it works!!!