Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Can call array but not index of an array in subroutine?!

by fraizerangus (Sexton)
on Apr 02, 2009 at 16:17 UTC ( [id://755016]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Perl Monks I am completely stumped by the following bug, I'm trying to return values from this subroutine, but inside the innermost for loop and outside of the triple loop, the @Azcord, @Axcord and @Aycord arrays are empty if you call it by index e.g  $Axcord[$counter] but if you call it by array e.g. @Axcord the entries will appear, which is no good for manipulation and which I can't pass back to the main programme?! does anyone have any idea of whats going on here? Many Thanks in advance! much appreciated! Dan
sub coordinatesorter { local (*Axcoord, *Aycoord, *Azcoord, *Bxcoord, *Bycoord, *Bzcoord, *re +s_to_atom, *natres, $nseg, *beginning, *ending) = @_; my @Axcord; my @Aycord; my @Azcord; my @Bxcord; my @Bycord; my @Bzcord; my $interdomaincounter=1; my $counter = 0; for ($iseg = 1; $iseg <= $nseg; ++$iseg){ for ($ires = $beginning[$iseg]; $ires <= $ending[$iseg]; ++$ires) { for ($iat = 1; $iat <= $natres[$ires]; ++$iat) { $Axcord[$counter] = $Axcoord[$res_to_atom[$ires][$iat]]; $Aycord[$counter] = $Aycoord[$res_to_atom[$ires][$iat]]; $Azcord[$counter] = $Azcoord[$res_to_atom[$ires][$iat]]; $Bxcord[$counter] = $Bxcoord[$res_to_atom[$ires][$iat]]; $Bycord[$counter] = $Bycoord[$res_to_atom[$ires][$iat]]; $Bzcord[$counter] = $Bzcoord[$res_to_atom[$ires][$iat]]; $counter++; } } } return (\@Axcord, \@Aycord, \@Azcord, \@Bxcord, \@Bycord, \@Bzcord); }

Replies are listed 'Best First'.
Re: Can call array but not index of an array in subroutine?!
by almut (Canon) on Apr 02, 2009 at 16:50 UTC
    the @Azcord, @Axcord and @Aycord arrays are empty if you call it by index e.g $Axcord[$counter] but if you call it by array e.g. @Axcord the entries will appear

    How exactly did you verify this? I.e., could you post some complete code that we can run as is, which proves your point?

Re: Can call array but not index of an array in subroutine?!
by jethro (Monsignor) on Apr 02, 2009 at 16:53 UTC

    I first thought the same thing as Ikegami until I saw that Axcoord and Axcord are not the same name. Besides the not recommendable style of array transfer to the subroutine your naming convention in this subroutine is highly error prone and leads to confusion.

    I don't see any problem with the loop itself. Please add your debugging code to it and what that prints. Maybe you just look at the @Axcord arrays at the wrong index. For example after the loops $counter should be at the last index+1, so naturally $Axcord[$counter] is empty. But $Axcord[$counter-1] probably isn't

      Hi everyone, I'm really sorry for my rookie mistakes I've only been programming a few months and am still learning, I've included my entire programme below, isolating areas of it would have made it too difficult to understand, please feel feel to just copy, paste and run, I will add my input word document; I've been using to my next post, you'll need to put it in a text document and then pass it to the perl programme as a command line argument (whatever the txt document is called) for it to run. again many thanks for all your help! regards Dan
      #!C:\Perl\bin $pdbfile=@ARGV[0]; open (PDB,$pdbfile); @pdblines=<PDB>; close (PDB); ($fixed, $moving, $interdomain, *atomcount, *atomtype, *resnum, *Axcoo +rd, *Aycoord, *Azcoord, *Bxcoord, *Bycoord, *Bzcoord, $totalnumber) = + &informationretrieval(\@pdblines); (*beginningfixed, *endingfixed, $nsegF) = &domainprocessing($fixed); (*beginningmoving, *endingmoving, $nsegM) = &domainprocessing($moving) +; (*beginninginterdomain, *endinginterdomain) = &interdomainsort($interd +omain); (*res_to_atom, *natres) = &restoatom(\@resnum, $totalnumber); (*AMxcord, *AMycord, *AMzcord, *BMxcord, *BMycord, *BMzcord) = &coordi +natesorter(\@Axcoord, \@Aycoord, \@Azcoord, \@Bxcoord, \@Bycoord, \@B +zcoord, \@res_to_atom, \@natres, $nsegM, \@beginningmoving, \@endingm +oving); #(*AFxcord, *AFycord, *AFzcord, *BFxcord, *BFxcord, *BFxcord) = &coord +inatesorter(\@Axcoord, \@Aycoord, \@Azcoord, \@Bxcoord, \@Bycoord, \@ +Bzcoord, \@res_to_atom, \@natres, $nsegF, \@beginningfixed, \@endingf +ixed); #($clashcounterA) = &calculation(\@AMxcord, \@AMycord, \@AMzcord, \@AF +xcord, \@AFycord, \@AFzcord); #($clashcounterB) = &calculation(\@BMxcord, \@BMxcord, \@BMxcord, \@BF +xcord, \@BFxcord, \@BFxcord); #print STDOUT $clashcounterA; #print STDOUT $clashcounterB; ##### #SUBROUTINES ##### sub informationretrieval { local ($pdblines) = @_; my @atomcount; my @atomtype; my @resnum; my @chainID; my @Axcoord; my @Aycoord; my @Azcoord; my @Bxcoord; my @Bycoord; my @Bzcoord; #loops through pdb file foreach $pdblines(@pdblines) { #ignores co-ordinate information related to hindge if ($pdblines =~ /TER arrow molecule that represents hinge axi +s for movement from conformer 1 to 2/) { last; } #fixed domain information retrieveal $fixed = $pdblines[7]; #moving domain information retrieveal $moving = $pdblines[10]; #moving domain information retrieveal $interdomainA = $pdblines[19]; $interdomainB = $pdblines[21]; # processing of interdomain information $interdomainA .= ','; $interdomainA =~ s/select//; $interdomainA =~ s/\s//; $interdomainA =~ s/-/,/g; $interdomainA =~ s/A//g; # processing of interdomain information $interdomainB =~ s/select//; $interdomainB =~ s/\s//; $interdomainB =~ s/-/,/g; $interdomainB =~ s/A//g; $interdomain = $interdomainA . $interdomainB; # identifies atom information and saves atom number, residue n +umber, chainID, X,Y,Z coordinates and atom type in separate arrays if ($pdblines =~ /^ATOM/) { $iat++; $atomcount[$iat]=substr($pdblines,7,4); $atomtype[$iat]=substr($pdblines,13,3); $resnum[$iat]=substr($pdblines,22,4); $chainID[$iat]=substr($pdblines,21,1); if ($chainID[$iat] eq 'A') { $Axcoord[$iat] = substr($pdblines,30,8); $Aycoord[$iat] = substr($pdblines,38,8); $Azcoord[$iat] = substr($pdblines,46,8); } elsif ($chainID[$iat] eq 'B') { $Bxcoord[$iat] = substr($pdblines,30,8); $Bycoord[$iat] = substr($pdblines,38,8); $Bzcoord[$iat] = substr($pdblines,46,8); } } } return ($fixed, $moving, $interdomain, \@atomcount, \@atomtype, \@resn +um, \@Axcoord, \@Aycoord, \@Azcoord, \@Bxcoord, \@Bycoord, \@Bzcoord, + $iat); } sub domainprocessing { local ($domain) = @_; my @beginningdomain; my @endingdomain; @domainnumbers; my $nseg; # processing of domain information $domain =~ s/select//; $domain =~ s/\s//; $domain =~ s/-/,/g; $domain =~ s/A//g; # split domain information into an array @domainnumbers = split(/,/, $domain); $nseg = @domainnumbers/2; # divide domain information into beginning and ending regions +of the domains foreach $domainnumbers (@domainnumbers) { # if array entry is divisable by 2 (even numbered) then it + is put in the beginning array if ($i % 2 == 0) { $ibeg++; $beginningdomain[$ibeg] = $domainnumbers[$i]; } # if array entry is not divisable by 2 (odd numbered) then + it is put in the ending array elsif ($i % 2 != 0) { $iend++; $endingdomain[$iend] = $domainnumbers[$i]; } # print error if something goes wrong else { print STDOUT 'Error'; } $i++; } $ibeg = 0; $iend = 0; $i = 0; return (\@beginningdomain, \@endingdomain, $nseg); } sub interdomainsort { local ($interdomain) = @_; my @interdomainnumbers; my @beginninginterdomainunsorted; my @endinginterdomainunsorted; # split interdomain information into an array @interdomainnumbers = split(/,/, $interdomain); # divide domain information into beginning and ending regions of t +he domains foreach $interdomainnumbers (@interdomainnumbers) { # if array entry is divisable by 2 (even numbered) then it is +put in the beginning array if ($e % 2 == 0) { $kbeg++; $beginninginterdomainunsorted[$kbeg]= $interdomainnumbers[$e]; } # if array entry is not divisable by 2 (odd numbered) then it +is put in the ending array elsif ($e % 2 != 0) { $kend++; $endinginterdomainunsorted[$kend]= $interdomainnumbers[$e]; } # print error if something goes wrong else { print STDOUT 'Error'; } $e++; } $kbeg = 0; $kend = 0; $e = 0; @beginninginterdomain = sort @beginninginterdomainunsorted; @endinginterdomain = sort @endinginterdomainunsorted; return (\@beginninginterdomain, \@endinginterdomain); } sub restoatom { local ($resnum, $totalnumber)= @_; my $iatres; my @natres; my @res_to_atom; #sorting residue to atom number $iatres=0; $resnum[0]=$resnum[1]; for ($iat=1; $iat<=$totalnumber; $iat++) { #if atom is in the same amino acid if ($resnum[$iat] == $resnum[$iat-1]) { $iatres++; $res_to_atom[$resnum[$iat]][$iatres] = $iat; } #else if atom is in different amino acid else { $natres[$resnum[$iat-1]] = $iatres; $iatres = 1; $res_to_atom[$resnum[$iat]][$iatres] = $iat; } } return (\@res_to_atom, \@natres); } #Sorts through moving coordinate information for calculation sub coordinatesorter { local (*Axcoord, *Aycoord, *Azcoord, *Bxcoord, *Bycoord, *Bzcoord, *re +s_to_atom, *natres, $nseg, *beginning, *ending) = @_; my @Axcord; my @Aycord; my @Azcord; my @Bxcord; my @Bycord; my @Bzcord; #my $interdomaincounter=1; my $counter = 0; for ($iseg = 1; $iseg <= $nseg; ++$iseg){ for ($ires = $beginning[$iseg]; $ires <= $ending[$iseg]; ++$ir +es) { for ($iat = 1; $iat <= $natres[$ires]; ++$iat) { $Axcord->[$counter] = $Axcoord[$res_to_atom[$ires][$ia +t]]; $Aycord->[$counter] = $Aycoord[$res_to_atom[$ires][$ia +t]]; $Azcord->[$counter] = $Azcoord[$res_to_atom[$ires][$ia +t]]; $Bxcord->[$counter] = $Bxcoord[$res_to_atom[$ires][$ia +t]]; $Bycord->[$counter] = $Bycoord[$res_to_atom[$ires][$ia +t]]; $Bzcord->[$counter] = $Bzcoord[$res_to_atom[$ires][$ia +t]]; print STDOUT $Axcord[$counter]; $counter++; } } } print STDOUT "should print out @Axcord array but does'nt?!", @Axcord; return (\@Axcord, \@Aycord, \@Azcord, \@Bxcord, \@Bycord, \@Bzcord); } #Distance Calculation sub calculation { local ($Mxcoord, $Mycoord, $Mzcoord, $Fxcoord, $Fycoord, $Fzcoord) = @ +_; my $fixedcoordsize = @Fxcoord; my $movingcoordsize = @Mxcoord; my $clashcounter; for($M=1; $M <= $fixedcoordsize; $M++){ for($F=1; $F <= $movingcoordsize; $F++){ $distance[$F] = sqrt(($Mxcoord[$F] - $Fxcoord[$M])**2 + ($Myco +ord[$F] - $Fycoord[$M])**2 + ($Mzcoord[$F] - $Fzcoord[$M])**2); if ($distance[$F] <= 4) { $clashcounter++; #print STDOUT "$atomtype[$F]"; #print STDOUT "$resnum[$F]"; #print STDOUT "$atomcount[$F]\n"; } } } return ($clashcounter); }
      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Can call array but not index of an array in subroutine?!
by kennethk (Abbot) on Apr 02, 2009 at 16:48 UTC

    In this case, it would certainly serve you well to have posted a simplified version of your code - you could certainly remove 5 elements from your call list and have the same structure.

    I cannot replicate your issue. Perhaps if you included a wrapping script that fed your subroutine some sample data and included information on how you were attempting to print out the values from your arrays. Your naming scheme is not great either - it took me a minute to figure out Axcoord and Axcord, etc. were different. And you probably shouldn't be using typeglobs for array passing. The following code should replicate your code's behavior. Note I've swapped to Foreach Loops to prevent syntax traps and all the code conforms to the strict/warnings pragmas. I'd also suggest replacing three independent arrays by hashes of arrays to reduce the number of variables.

    use strict; use warnings; sub coordinatesorter { my ($Ax_ref, $Ay_ref, $Az_ref, $Bx_ref, $By_ref, $Bz_ref, $res_to_atom, $natres, $nseg, $beginning, $ending ) = @_ +; my $interdomaincounter = 1; my $counter = 0; my (@Axcord, @Aycord, @Azcord, @Bxcord, @Bycord, @Bzcord); foreach my $iseg (1 .. $nseg) { foreach my $ires ($beginning->[$iseg] .. $ending->[$iseg]) { foreach my $iat (1 .. $natres->[$ires]) { $Axcord[$counter] = $Ax_ref->[ $res_to_atom->[$ires][$ +iat] ]; $Aycord[$counter] = $Ay_ref->[ $res_to_atom->[$ires][$ +iat] ]; $Azcord[$counter] = $Az_ref->[ $res_to_atom->[$ires][$ +iat] ]; $Bxcord[$counter] = $Bx_ref->[ $res_to_atom->[$ires][$ +iat] ]; $Bycord[$counter] = $By_ref->[ $res_to_atom->[$ires][$ +iat] ]; $Bzcord[$counter] = $Bz_ref->[ $res_to_atom->[$ires][$ +iat] ]; $counter++; } } } return (\@Axcord, \@Aycord, \@Azcord, \@Bxcord, \@Bycord, \@Bzcord +); }

    If this code still doesn't perform to spec, please provide some sample data.

Re: Can call array but not index of an array in subroutine?!
by ikegami (Patriarch) on Apr 02, 2009 at 16:39 UTC
    I don't have time to go into details, but to complete the obsolete style you are using, you would do
    local (*Axcoord, *Aycoord, *Azcoord, *Bxcoord, *Bycoord, *Bzcoord, *re +s_to_atom, *natres, $nseg, *beginning, *ending) = @_; our @Axcord; our @Aycord; our @Azcord; our @Bxcord; our @Bycord; our @Bzcord; ... $Axcord[$counter] ...

    Better way:

    my ($Axcoord, $Aycoord, $Azcoord, $Bxcoord, $Bycoord, $Bzcoord, $res_t +o_atom, $natres, $nseg, $beginning, $ending) = @_; ... $Axcord->[$counter] ...

    Update: I thought I aborted posting this message. It's obviously overly rushed for the amount of problems in the OP.

      Not that I would recommend local (*Axcoord, ..., but I think those are supposed to be different from my @Axcord, ... (note the different number of 'o's)

      hello! thanks for helping me, but I've tried both those solutions and neither of them work?! best wishes Dan

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://755016]
Approved by Old_Gray_Bear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (3)
As of 2024-04-25 07:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found