2

以下のようなテキストファイルがあります。

 CA     21.660  -6.795  11.323 
  C     28.811  -9.801  16.262
  O     23.221  -9.266  13.799
  CB    33.528 -11.934  17.900
  N     21.660  -6.795  11.323
  O     32.410  -8.539  16.566

原子の座標間の距離を計算したい。たとえば、フォルダ内のすべてのファイルを読み取り、1 番目と 2 番目の原子、1 番目と 3 番目、1 番目と 4 番目などの間の距離を計算したいとします。次に、2 番目と 3 番目、2 番目と 4 番目、2 番目と 5 番目などですSQRT ((X1-X2)^2 + (Y1-Y2)^2 + (Z1-Z2)^2) です。各ファイルからの出力を、入力ファイルの名前で別のフォルダーに保存したいと思います。awkでこれを行うにはどうすればよいですか?

希望の出力

CA-C  4.52
CA-O  3.80
CA-CB 5.68
CA-N  8.94
--
--
--
N-O   5.98 

あなたの助けをいただければ幸いです!!

4

5 に答える 5

4

を使用する 1 つの方法を次に示しGNU awkます。

awk 'FNR==NR { a[NR]=$0; next } { for (i=FNR+1;i<=NR-1;i++) { split(a[i],b); print $1 "-" b[1], sqrt(($2-b[2])^2 + ($3-b[3])^2 + ($4-b[4])^2) | "column -t" } NR--}' file file

それはあなたが望むことをしますが、提供したアルゴリズムが必要なものと異なるか、期待される出力が正しく計算されていません (後者が問題であると想定しています)。とにかく、ここに結果があります:

CA-C   9.19601
CA-O   3.83055
CA-CB  14.5092
CA-N   0
CA-O   12.0869
C-O    6.13194
C-CB   5.42981
C-N    9.19601
C-O    3.82595
O-CB   11.4092
O-N    3.83055
O-O    9.62406
CB-N   14.5092
CB-O   3.81517
N-O    12.0869

現在の作業ディレクトリ内の複数のファイルに対してこれを実行する必要があり、このディレクトリに目的のファイルしかないと仮定すると、ステートメントをforループで囲むことができます。明らかに、正しく機能させるためには、選択したパスawkに変更する必要があります。/path/to/folder/

for i in *; do awk 'FNR==NR { a[NR]=$0; next } { for (i=FNR+1;i<=NR-1;i++) { split(a[i],b); print $1 "-" b[1], sqrt(($2-b[2])^2 + ($3-b[3])^2 + ($4-b[4])^2) | "column -t > /path/to/folder/" FILENAME } NR--}' "$i"{,}; done
于 2012-12-04T00:09:41.050 に答える
3

アトムがデータを含むファイルである場合

awk '{ p[NR,0]=$1;p[NR,1]=$2;p[NR,2]=$3;p[NR,3]=$4; for (j=1;j<=NR-1;j++) print p[j,0]"-"$1,sqrt((p[NR,1]-p[j,1])^2+(p[NR,2]-p[j,2])^2+(p[NR,3]-p[j,3])^2) }' atoms 
CA-C 9.19601
CA-O 3.83055
C-O 6.13194
CA-CB 14.5092
C-CB 5.42981
O-CB 11.4092
CA-N 0
C-N 9.19601
O-N 3.83055
CB-N 14.5092
CA-O 12.0869
C-O 3.82595
O-O 9.62406
CB-O 3.81517
N-O 12.0869

問題がある:

  • データには2つの同一のO原子が含まれているため、どちらが出力に含まれているかを判断するのは困難です
于 2012-12-03T16:18:30.580 に答える
1

以下はawkのコードです:

awk '{a[NR]=$0}
     END
     { 
       for(i=1;i<=NR;i++)
        {split(a[i],k);
         for(j=i+1;j<=NR;j++)
          {
           split(a[j],l);
           dist=(k[2]-l[2])*(k[2]-l[2])+(k[3]-l[3])*(k[3]-l[3])+(k[4]-l[4])*(k[4]-l[4]);
           print k[1]"-"l[1],sqrt(dist);
          }
        }
     }' your_file

そして以下はテストです:

> cat temp
 CA     21.660  -6.795  11.323 
  C     28.811  -9.801  16.262
  O     23.221  -9.266  13.799
  CB    33.528 -11.934  17.900
  N     21.660  -6.795  11.323
  O     32.410  -8.539  16.566

実行:

> awk '{a[NR]=$0}END{for(i=1;i<=NR;i++){split(a[i],k);for(j=i+1;j<=NR;j++){split(a[j],l);dist=(k[2]-l[2])*(k[2]-l[2])+(k[3]-l[3])*(k[3]-l[3])+(k[4]-l[4])*(k[4]-l[4]);print k[1]"-"l[1],sqrt(dist);}}}' temp
CA-C 9.19601
CA-O 3.83055
CA-CB 14.5092
CA-N 0
CA-O 12.0869
C-O 6.13194
C-CB 5.42981
C-N 9.19601
C-O 3.82595
O-CB 11.4092
O-N 3.83055
O-O 9.62406
CB-N 14.5092
CB-O 3.81517
N-O 12.0869
> 
于 2012-12-04T05:55:44.777 に答える
1

このようなものはあなたが望むもののように聞こえますが、明らかにどちらの結果もあなたが言うことと一致しないので、アルゴリズムを明確にしてください:

$ awk 'NR>1{print p[1]"-"$1,sqrt((p[2]-$2)^2 + (p[3]-$3)^2 + (p[4]-$4)^2)} {split($0,p) }' file
CA-C 9.19601
C-O 6.13194
O-CB 11.4092
CB-N 14.5092
N-O 12.0869

$ awk 'NR>1{print p[1]"-"$1,sqrt(($2-p[2])^2 + ($3-p[3])^2 + ($4-p[4])^2)} {split($0,p) }' file
CA-C 9.19601
C-O 6.13194
O-CB 11.4092
CB-N 14.5092
N-O 12.0869
于 2012-12-03T15:22:53.347 に答える
0

Perl ソリューションは次のようになります。

#!/usr/bin/perl
use strict;
use warnings;

my @data = map [split], <DATA>;

for (my $i = 0; $i < @data; $i++) {
    for (my $j = $i+1; $j < @data; $j++) {
        my $d = distance( @data[$i, $j]);
        printf("%-6s%7.4f\n",
            join("-", map $_->[0], @data[$i, $j]), $d) if $d <= 6;
    }
}

sub distance {
    my ($coord1, $coord2) = @_;
    my $sum;
    for my $k (1 .. $#$coord1) {
        $sum += ($coord1->[$k] - $coord2->[$k])**2;
    }
    return sqrt $sum;
}

__DATA__
CA     21.660  -6.795  11.323 
C     28.811  -9.801  16.262
O     23.221  -9.266  13.799
CB    33.528 -11.934  17.900
N     21.660  -6.795  11.323
O     32.410  -8.539  16.566
于 2012-12-17T18:45:43.680 に答える