Perl在初始化所有值时使用未初始化的值

时间:2016-05-27 00:47:56

标签: perl

我正在尝试编写一个脚本来计算几个碳氢键的顺序参数并输出这些值。数学是微不足道的,但我得到了一个"使用未初始化的值"我尝试在最后平均值时出错。 我很清楚这个错误是多么常见和容易修复,但是我检查了所有给定的值,所有9212值都有一个值(我通过打印每个值进行检查,将其放入excel文档并搜索空单元格)。我很茫然,我不知道如何进一步调试。

我的脚本采用输入文件,逐行进行,如果存在某些字符串则采用x,y,z坐标,对这些坐标进行数学运算(找到两个向量和z轴之间的角度),应该是将每个$ integer整数段平均(所有2&#s的平均值等)。它为3个段(2-8,9-10和11-18)执行此操作,将它们保存到两个数组(@theta_values和@theta2_values),最后它应平均每个"整数"一起找到矢量和z轴之间的平均角度。 总共应该有34个值输出,这确实会发生但是每个值都有一个"另外使用未初始化的值(+)在angle_checker_v3.pl第334行,第34303行。"错误,除了第一个以外的所有平均值都太小。

作为参考,第334行是我的平均值,第34303行是文件的最后一行。

一些样本数据将是:

ATOM   2199  C22 POPC    1      -9.427  11.863  11.706  1.00  0.00      MEMB
ATOM   2200  H2R POPC    1     -10.347  11.662  12.293  1.00  0.00      MEMB
ATOM   2201  H2S POPC    1      -8.968  10.895  11.443  1.00  0.00      MEMB
ATOM   2211  C23 POPC    1      -9.801  12.641  10.423  1.00  0.00      MEMB
ATOM   2212  H3R POPC    1     -10.136  13.667  10.696  1.00  0.00      MEMB
ATOM   2213  H3S POPC    1     -10.658  12.124   9.934  1.00  0.00      MEMB
ATOM   2214  C24 POPC    1      -8.663  12.751   9.396  1.00  0.00      MEMB
ATOM   2215  H4R POPC    1      -7.763  13.166   9.894  1.00  0.00      MEMB
ATOM   2216  H4S POPC    1      -8.961  13.479   8.607  1.00  0.00      MEMB

*我故意跳过10个无关紧要的原子

按顺序列表示:物质(不相关),原子序数,原子类型,残基数/分子类型,残基数,x-coord,y-coord,z-coord,alpha数(不相关), β柱(不相关)和整体分子类型。

TLDR; 我的平均脚本:

#Averaging theta values
for (my $t=2; ($t <= 18); $t++) {
    for (my $j=1; ($j <= $lipid_num); $j++) {
            $sum[$t]= $theta_values[$t][$j] + $sum[$t];
    }
    $average[$t]= $sum[$t] / $lipid_num;
    print "Average theta for carbon $t is $average[$t]\n";
}

#Averaging Theta2 values
for (my $q=2; ($q <= 18); $q++) {
        for (my $b=1; ($b <= $lipid_num); $b++) {
                $sum2[$q]= $theta2_values[$q][$b] + $sum2[$q];
        }
        $average2[$q]= $sum2[$q] / $lipid_num;
        print "Average theta2 for carbon $q is $average2[$q]\n";
}

即使我已经确认所有位置都有值,但在所有位置都找不到值。

这是完整的脚本,我意识到它有多大。

        #Usage:                                                                      #
# perl angle_checker.pl [granuphilin_prot-memb_system].pdb 
#!/usr/bin/perl 

use strict;
use warnings;
use Math::Trig;

my $inputfile = $ARGV[0];

open (INPUTFILE, "<", $inputfile) or die $!;

my @data = <INPUTFILE>;

#Quick Change Variables

my $lipid_num = 256;

#Library
my @sum;
my @average;
my @sum2;
my @average2;
my @x1;
my @y1;
my @z1;
my $R = 'R';
my $S = 'S';
my $one = '1';
my @theta_values;
my @theta2_values;
my @vectorCtoHR;
my @vectorCtoHS;
my @normal;

#Start for lipid count
for (my $lipid=1; ($lipid <= $lipid_num); $lipid++) {
    # First Carbon/Integer counter
    for (my $integer= 2; ($integer <= 8); $integer++) {
            #Split line 1
            for (my $line = 0; $line <= $#data; ++$line) {
                    #Search 1.1
                    if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            chomp $data[$line];
                            my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[0]= $splitline[5];
                                    $y1[0]= $splitline[6];
                                    $z1[0]= $splitline[7];
                            }
                    }
                    #Search 1.2
                        if(($data[$line] =~ m/\s+H$integer$R\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[1]= $splitline[5];
                                        $y1[1]= $splitline[6];
                                        $z1[1]= $splitline[7];
                            }
                    }
                    #Search 1.3
                        if(($data[$line] =~ m/\s+H$integer$S\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[2]= $splitline[5];
                                        $y1[2]= $splitline[6];
                                        $z1[2]= $splitline[7];
                            }
                    }
            }



    #Z-axis
    $normal[0]= 0;
    $normal[1]= 0;
    $normal[2]= 100;

    #Vector 1
    $vectorCtoHR[0]=($x1[0] - ($x1[1]));
    $vectorCtoHR[1]=($y1[0] - ($y1[1]));
    $vectorCtoHR[2]=($z1[0] - ($z1[1]));

    #Vector 2
    $vectorCtoHS[0]=($x1[0] - ($x1[2]));
        $vectorCtoHS[1]=($y1[0] - ($y1[2]));
        $vectorCtoHS[2]=($z1[0] - ($z1[2]));

    #First Angle

    my $x1mag = sqrt(($vectorCtoHS[0]**2)+($vectorCtoHS[1]**2)+($vectorCtoHS[2]**2));
    my $x2mag = sqrt(($normal[0]**2)+($normal[1]**2)+($normal[2]**2));

    #Dot product 
    my $dotproduct = (($vectorCtoHS[0]*$normal[0])+($vectorCtoHS[1]*$normal[1])+($vectorCtoHS[2]*$normal[2]));

    my $theta = acos($dotproduct/($x1mag*$x2mag));
    $theta_values[$integer][$lipid]= $theta;

    # Second Angle  
        my $x3mag = sqrt(($vectorCtoHR[0]**2)+($vectorCtoHR[1]**2)+($vectorCtoHR[2]**2));

        my $dotproduct2 = (($vectorCtoHR[0]*$normal[0])+($vectorCtoHR[1]*$normal[1])+($vectorCtoHR[2]*$normal[2]));

        my $theta2 = acos($dotproduct2/($x3mag*$x2mag));
        $theta2_values[$integer][$lipid]= $theta2;
    }
    #Section 2 Search These only have one hydrogen to search for, hence 1 less search
    for (my $integer = 9; ($integer <= 10); $integer++) {
                for (my $line = 0; $line <= $#data; ++$line) {
                        if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                chomp $data[$line];
                                my @splitline = (split /\s+/, $data[$line]);
                                foreach (@splitline) {
                                        $x1[0]= $splitline[5];
                                        $y1[0]= $splitline[6];
                                        $z1[0]= $splitline[7];
                                }
                        }
                    if(($data[$line] =~ m/\s+H$integer$one\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                my @splitline = (split /\s+/, $data[$line]);
                                foreach (@splitline) {
                                        $x1[1]= $splitline[5];
                                        $y1[1]= $splitline[6];
                                        $z1[1]= $splitline[7];
                                }
                        }
                }
    $normal[0]= 0;
    $normal[1]= 0;
    $normal[2]= 100;
    $vectorCtoHR[0]=($x1[0] - ($x1[1]));
    $vectorCtoHR[1]=($y1[0] - ($y1[1]));
    $vectorCtoHR[2]=($z1[0] - ($z1[1]));

    my $x1mag = sqrt(($vectorCtoHR[0]**2)+($vectorCtoHR[1]**2)+($vectorCtoHR[2]**2));
    my $x2mag = sqrt(($normal[0]**2)+($normal[1]**2)+($normal[2]**2));

    #Dot product 
    my $dotproduct = (($vectorCtoHR[0]*$normal[0])+($vectorCtoHR[1]*$normal[1])+($vectorCtoHR[2]*$normal[2]));

    my $theta = acos($dotproduct/($x1mag*$x2mag));
    $theta_values[$integer][$lipid]= $theta;
    $theta2_values[$integer][$lipid]= $theta;
    }

    #Effectively the same as section 1
    for (my $integer= 11; ($integer <= 18); $integer++) {
            for (my $line = 0; $line <= $#data; ++$line) {
                    if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            chomp $data[$line];
                            my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[0]= $splitline[5];
                                    $y1[0]= $splitline[6];
                                    $z1[0]= $splitline[7];
                            }
                    }
                        if(($data[$line] =~ m/\s+H$integer$R\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[1]= $splitline[5];
                                        $y1[1]= $splitline[6];
                                        $z1[1]= $splitline[7];
                            }
                    }
                        if(($data[$line] =~ m/\s+H$integer$S\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                                my @splitline = (split /\s+/, $data[$line]);
                            foreach (@splitline) {
                                    $x1[2]= $splitline[5];
                                        $y1[2]= $splitline[6];
                                        $z1[2]= $splitline[7];
                            }
                    }
            }
    $normal[0]= 0;
    $normal[1]= 0;
    $normal[2]= 100;

    $vectorCtoHR[0]=($x1[0] - ($x1[1]));
    $vectorCtoHR[1]=($y1[0] - ($y1[1]));
    $vectorCtoHR[2]=($z1[0] - ($z1[1]));

    $vectorCtoHS[0]=($x1[0] - ($x1[2]));
        $vectorCtoHS[1]=($y1[0] - ($y1[2]));
        $vectorCtoHS[2]=($z1[0] - ($z1[2]));

    #First Angle

    my $x1mag = sqrt(($vectorCtoHS[0]**2)+($vectorCtoHS[1]**2)+($vectorCtoHS[2]**2));
    my $x2mag = sqrt(($normal[0]**2)+($normal[1]**2)+($normal[2]**2));

    #Dot product 
    my $dotproduct = (($vectorCtoHS[0]*$normal[0])+($vectorCtoHS[1]*$normal[1])+($vectorCtoHS[2]*$normal[2]));

    my $theta = acos($dotproduct/($x1mag*$x2mag));
    $theta_values[$integer][$lipid]= $theta;
    }
print "done with $lipid\n";
#End of lipid search
}
#Averaging starts now

#Averaging theta values
for (my $t=2; ($t <= 18); $t++) {
    for (my $j=1; ($j <= $lipid_num); $j++) {
            $sum[$t]= $theta_values[$t][$j] + $sum[$t];
    }
    $average[$t]= $sum[$t] / $lipid_num;
    print "Average theta for carbon $t is $average[$t]\n";
}

#Averaging Theta2 values
for (my $q=2; ($q <= 18); $q++) {
        for (my $b=1; ($b <= $lipid_num); $b++) {
                $sum2[$q]= $theta2_values[$q][$b] + $sum2[$q];
        }
        $average2[$q]= $sum2[$q] / $lipid_num;
        print "Average theta2 for carbon $q is $average2[$q]\n";
}

2 个答案:

答案 0 :(得分:3)

如果没有输入数据,就无法在本地重现问题,因此几乎无法帮助调试。看了你的代码之后,我可以建议一些简化代码的东西,希望能更容易找到问题。

首先,几乎所有的循环都在C风格的for循环中迭代两个值之间的整数变量。如果你绝对需要它,for就是那种形式,但perl具有更强的表现力 - 因此更容易阅读和理解作者意图 - for循环的形式。

你只需要一个整数范围;例如

for (my $integer= 2; ($integer <= 8); $integer++) { 

你可以简单地陈述&#34;我希望$ integer从2到8&#34 ;;

for my $integer (2 .. 8)

如果您只是为了索引回到数组中来获取内容而使用整数,那么您可以简单地告诉Perl您想迭代数组内容 - 即代替;

for (my $line = 0; $line <= $#data; ++$line) {
    if(($data[$line] =~ ... etc ...
    chomp $data[$line];

你可以更简单;

for my $line (@data) {
    if(($line =~ ... etc ...
    chomp $line;

其次,如果您在游戏中有多个正则表达式,则有助于将其定义与其使用区分开来。它允许读者单独使用和理解正则表达式本身(稍后)查看它的应用方式/原因。此外,&#39;扩展模式&#39;正则表达式允许正则表达式定义中的空格。用空格读取正则表达式(regexen?)是多么容易,这简直太令人惊讶了 - 人们应该考虑将其作为一个规则,只需始终使用{{1} }。 Togeather,我们可以替换;

/x

用;

if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {

第三 - 也许是最不重要的,因为我认为它可能是一个错误 - 在你的几个内循环中;

my $has_POPC        = qr/ \s+  POPC        \s+ /x;
my $has_lipid       = qr/ \s+  $lipid      \s+ /x;
my $has_C2_integer  = qr/ \s+  C2 $integer \s+ /x;

if( $line =~ $has_C2_integer  &&  $line =~ $has_lipid  &&  $line =~ $has_POPC) {

再次 - 我没有输入数据因此无法检查 - 但这几乎肯定是一个错误。你在空格上划分界限 - 为了讨论起见,假设它有10个&#34;件&#34;。然后,您迭代这些部分(将它们放入默认主题my @splitline = (split /\s+/, $data[$line]); foreach (@splitline) { $x1[0]= $splitline[5]; $y1[0]= $splitline[6]; $z1[0]= $splitline[7]; } ),但不要引用主题部分本身 - 即,您没有使用$_。因此,代码正在放置第5,6和6部分。 7成x1,y1&amp; z1(分别) - 10次以上。现在,可能并不重要但正如我所说,它几乎肯定不是你想要的,因此是一个等待发生的错误。你可能(它是简洁性与可读性之间的平衡)想要将三个赋值合并为列表形式,并且(再次,可选地)消除临时变量$_;

@splitline

将这些想法转换为togeather可以替换它;

if( $line =~ $has_C2_integer  &&  $line =~ $has_lipid  &&  $line =~ $has_POPC) {
    ( $x1[0], $y1[0], $z1[0] ) = (split /\s+/ $line)[ 5, 6, 7 ];
}

with;

#Start for lipid count
for (my $lipid=1; ($lipid <= $lipid_num); $lipid++) {
    # First Carbon/Integer counter
    for (my $integer= 2; ($integer <= 8); $integer++) {
        #Split line 1
        for (my $line = 0; $line <= $#data; ++$line) {
                #Search 1.1
                if(($data[$line] =~ m/\s+C2$integer\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                        chomp $data[$line];
                        my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[0]= $splitline[5];
                                $y1[0]= $splitline[6];
                                $z1[0]= $splitline[7];
                        }
                }
                #Search 1.2
                    if(($data[$line] =~ m/\s+H$integer$R\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[1]= $splitline[5];
                                    $y1[1]= $splitline[6];
                                    $z1[1]= $splitline[7];
                        }
                }
                #Search 1.3
                    if(($data[$line] =~ m/\s+H$integer$S\s+/)&&($data[$line] =~ m/\s+$lipid\s+/)&&($data[$line] =~ m/\s+POPC\s+/)) {
                            my @splitline = (split /\s+/, $data[$line]);
                        foreach (@splitline) {
                                $x1[2]= $splitline[5];
                                    $y1[2]= $splitline[6];
                                    $z1[2]= $splitline[7];
                        }
                }
        }

......将行数减少了大约三分之一,并且(可以说)更具可读性。在程序的后期,结构几乎逐字重复,因此您应该能够再次获得相同的减少量。当然必须严格检查,我无法做到。最后,好好看看Perl debugger。只需大约15分钟即可完成基础知识,并且至少可以回报10次(至少)。

答案 1 :(得分:0)

事实证明我正在添加我的$ sum [$ t],它没有值,而是做了一些事情,这就是错误。为了解决这个问题,我改变了:

$sum[$t]= $theta_values[$t][$j] + $sum[$t];

要:

$sum[$t]+= $theta_values[$t][$j];

谢谢大家的帮助。