我正在尝试编写一个脚本来计算几个碳氢键的顺序参数并输出这些值。数学是微不足道的,但我得到了一个"使用未初始化的值"我尝试在最后平均值时出错。 我很清楚这个错误是多么常见和容易修复,但是我检查了所有给定的值,所有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";
}
答案 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];
谢谢大家的帮助。