2016-05-27 4 views
2

いくつかの炭素 - 水素結合の順序パラメータを計算し、それらの値を出力するスクリプトを作成しようとしています。数学は簡単ですが、最後に値を平均化しようとすると「初期化されていない値を使用する」エラーが表示されます。 私はこのエラーがどのくらい一般的で簡単に修正されているのかよく知っていますが、すべての値をチェックしました。すべての9212の値があります(それぞれを印刷してExcel文書に入れ、空のセルを検索します)。私は紛失しており、さらにデバッグする方法がわかりません。Perlすべての値が初期化されたときに加えて初期化されていない値の使用

スクリプトは入力ファイルを受け取り、行単位で移動し、特定の文字列がある場合はx、y、z座標をとり、これらの座標(2つのベクトルとz軸の間の角度を求めます)それぞれの$整数部分を平均しているので(すべての2の平均など)これは3つのセグメント(2-8,9-10、および11-18)に対して行い、2つの配列(@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座標、y座標、z座標、アルファ番号(関連性がない)、ベータ列(関連性がない)、および全体的な分子タイプを含む。

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

入力データファイルをどこかに投稿することはできますか?これがなければ、問題を局所的に再現することができず、デバッグが難しくなります。 – Marty

+0

'@ sum'と' @ sum2'配列をすべてゼロに初期化しようとしますか? – xxfelixxx

+0

また、 '$ q'を2から18まで繰り返します。' @ sum'と '@ sum2'配列の0と1の位置をスキップすることを意味しますか?あなたが何かをしない限り、これらは初期化されません。 – xxfelixxx

答えて

0

私は$ sum [$ t]を値を持たないものに加えていましたが、これはエラーを出していました。

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

:この問題を解決するために、私はから変更

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

ヘルプありがとうございました。

3

入力データがなければ、ローカルで問題を再現することは不可能で、デバッグにはほとんど不可能です。しかし、あなたのコードを見て、私はコードを簡素化し、うまくいけば問題を見つけるのを簡単にすることができるいくつかのことを提案することができます。

まず、ほぼすべてのループが、Cスタイルの2つの値の間の整数変数に対してループします(forループ)。その形のforは絶対必要ですが、perlははるかに表現力があり、したがってforループの作者の意図の形を読んで理解するのがずっと簡単です。

単純に整数の範囲が必要です。たとえば

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

あなたは単純に「$整数が2から8になるようにしたい」と言うことができます。

あなたが内容を取得するために戻って配列にインデックス付けの目的のためだけに整数を使用している
for my $integer (2 .. 8) 

、あなたは単にあなたが配列の内容を反復処理したいのperl伝えることができます - すなわちの代わりに、

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

より簡単に指定できます。

第2に、いくつかの正規表現を使用している場合は、その定義を使用から切り離すことができます。これは、(後で)どのように/なぜそれが適用されているかを見ることとは別に、正規表現自体を消費し理解することを可能にします。また、 'extended mode' regexは、正規表現定義の空白を許可します。 regexes(regexen?)を空白で読み取るのがどれほど簡単であるかは驚くばかりです。ちょうどちょうど/xを使うというルールにすることを検討すべきです。 Togeather、我々は置き換えることができます。

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

- おそらく最もimprtantly私は、その潜在的にバグだと思うので - あなたが持っているあなたの内側のループのいくつかの範囲内。

my @splitline = (split /\s+/, $data[$line]); 
foreach (@splitline) { 
    $x1[0]= $splitline[5]; 
    $y1[0]= $splitline[6]; 
    $z1[0]= $splitline[7]; 
} 

入力データがないため、確認できませんが、これはほとんど間違いです。あなたは空白に線を分割しています - 議論のために、10ピースがあるとしましょう。これらの部分を繰り返し(デフ​​ォルトのトピック$_に入れて)、トピックピース自体は参照しません。すなわち、$_を使用していません。したがって、このコードでは、x1、y1 & z1に断片5,6、& 7を入れています - それぞれ10倍以上です。今、それおそらくは問題ではありませんが、私が言ったように、ほとんどあなたが望んでいないので、バグが起こるのを待っている。 may(敏感さと読みやすさのバランスの問題)は、3つの割り当てをリスト形式に統合し、一時変数を削除することもできます(@splitline)。

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

これを置き換えることができます。

#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]; 
         } 
       } 
     } 

と;

my $has_POPC = qr/ \s+ POPC \s+ /x; 
#Start for lipid count 
for my $lipid (1 .. $lipid_num) { 
    my $has_lipid = qr/ \s+ $lipid \s+ /x; 

    # First Carbon/Integer counter 
    for my $integer (2 .. 8) { 
     my $has_C2_integer = qr/ \s+ C2 $integer \s+ /x; 
     my $has_H_integer_R = qr/ \s+ H $integer R \s+ /x; 
     my $has_H_integer_S = qr/ \s+ H $integer S \s+ /x; 

     #Split line 1 
     for my $line (@data) { 
      chomp $line; 

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

      #Search 1.2 
      if ($line =~ $has_H_integer_R && $line =~ $has_lipid && $line =~ $has_POPC) { 
       ($x1[1], $y1[1], $z1[1]) = (split /\s+/ $line)[ 5, 6, 7 ]; 
      } 

      #Search 1.3 
      if ($line =~ $has_H_integer_S && $line =~ $has_lipid && $line =~ $has_POPC) { 
       ($x1[2], $y1[2], $z1[2]) = (split /\s+/ $line)[ 5, 6, 7 ]; 
      } 
     } 
    } 
} 

...これは、行数を約3分の1に減らした(間違いなく)読みやすいです。プログラムの後半で、構造はほぼそのまま繰り返されるので、同じ減少をもう一度得ることができます。これは私がすることができないコースの厳密なチェックをしなければなりません。最後に、Perl debuggerをよく見てください。基本を乗り越えるのに約15分しかかからず、10倍以上(少なくとも)返済されます。

関連する問題