glycoinfo / GlycanBuilder2

7 stars 5 forks source link

A closed-loop is composed in repeating unit. #54

Open e15d5605 opened 2 years ago

e15d5605 commented 2 years ago

繰り返し構造のWURCSを読み込んだ際に生成されるGlycanを描画機能や質量計算機能で処理する際にStackOverFlowを返している。 この原因を調査し、問題のある機能を修正する。

e15d5605 commented 2 years ago

wurcs2image APIでNアセチルノイラミン酸の繰り返し構造を描画した際に、画像が返されていないという報告を受けた。

https://api.glycosmos.org/wurcs2image/latest/png/binary/G39122DY

このAPIはGlycanBuilder2を利用している。報告されている状況の再現が可能か確認するために、v1.18.1のGlycanBuilder2で同様のWURCSを読み込んだ。結果として以下のようなエラーメッセージが出力され、最終的にStackOverFlowが発生して処理を強制終了していた。

at org.eurocarbdb.application.glycanbuilder.util.TextUtils.tokenize(TextUtils.java:184)
    at org.eurocarbdb.application.glycanbuilder.ResidueType.getMinRepetitions(ResidueType.java:468)
    at org.eurocarbdb.application.glycanbuilder.converterGWS.GWSParser.writeResidueType(GWSParser.java:202)
    at org.eurocarbdb.application.glycanbuilder.converterGWS.GWSParser.writeSubtree(GWSParser.java:236)
    at org.eurocarbdb.application.glycanbuilder.converterGWS.GWSParser.writeSubtree(GWSParser.java:284)
    at org.eurocarbdb.application.glycanbuilder.converterGWS.GWSParser.writeSubtree(GWSParser.java:259)

       * これ以降はGWSParser.java:284とGWSParser.java:259の処理を無限に繰り返しているため割愛

GWSParserの該当箇所を確認すると、以下のような処理だった。

GWSParserのwriteSubtreeという関数で問題が発生していた。この関数ではResidueから子ノードを参照することで、再帰的に全ての単糖の情報を描画している。これらの処理が無限に続くことから、本来は単糖の子ノードを参照して糖鎖の葉側に進むはずの処理が、何らかの原因で根側に戻ってしまっているため無限に繰り返されていると考えられる。このことから、繰り返し構造のWURCSから生成されたGlycanのResidueの親子関係を調査した。

e15d5605 commented 2 years ago

エラー報告で提示されていた糖鎖構造のWURCSからGlycanを生成し、全ての単糖の親子関係を確認した。

WURCS=2.0/1,1,1/[Aad21122h-2a_2-6_5*NCC/3=O_7%?%*OCC/3=O_8%?%*OCC/3=O]/1/a2-a9~n

このWURCSから生成されるGlycanの繰り返し構造はStartRep-Monosaccharide-...-EndRepで構成される。Glycanでは単糖だけでなく繰り返し構造のブラケットも糖鎖を構成する要素として扱っているため、ブラケットと単糖間の親子関係も形成する必要がある。今回のケースでは、(親)StartRep-(子)Nアセチルノイラミン酸、(親)Nアセチルノイラミン酸-(子)EndRepの親子関係を形成することで、単糖の繰り返し構造を描画することが可能になる。

しかしながら、末端のEndRepの親子関係を確認すると、(親)EndRep-(子)Nアセチルノイラミン酸になっており、本来の親子関係と逆転していることを確認した。これにより、(親/子)Nアセチルノイラミン酸-(子/親)EndRepとなってしまい、子情報を永久に参照し続けられる構造になっていることが判明した。

e15d5605 commented 2 years ago

TODO: 繰り返しの親子が無限ループになる箇所を特定して整理する

WURCSSequence2の解析処理で参照されるGLIN2Linkageで、親ノードを正しく参照できていない疑いがある。WURCS2からGlycanを生成する処理では、GRES2ResidueでGRESからResidueへ変換し、GLIN2LinkageでLinkageへの変換を行う。この段階では、Glycanを構成するResidueはバラバラの状態である。LinkageConnectorはこれらのバラバラに分断された糖鎖の部品を、GLIN2Linkageで定義した親子関係を参照しながら繋ぐ。しかし、GLIN2LいんかげでGLINを解析した時に定義された親子関係に誤りがあり、以下のように解釈されたと考えられる。

StartRep->Nアセチルノイラミン酸<->EndRep



繰り返し構造は特定の単糖のグループが繰り返し見られる糖鎖構造であり、繰り返しの開始点と終点は親子関係を持つ。そのため、単一の単糖で構成された繰り返し構造の場合は、その単糖の親と子に自分自身を持つということになる。GLIN2Linkageでこのような条件を適切に処理できていないため、クリア返しの終点に位置するNアセチルノイラミン酸が、子を持つ単糖として判断されたと考えられる。また、その子ノードは繰り返しの外の単糖として判断されたため、EndRep->Nアセチルノイラミン酸の親子関係が定義された。

まだ、GLINToLinkageのどこで誤ったGRESが参照されているのかがわからないため、調査を継続する。
 
e15d5605 commented 2 years ago

また、複数の単糖で構成されている繰り返し構造などのいくつか異なる構造を可視化した際の挙動を確認した。

WURCS=2.0/1,4,4/[a2122h-1x_1-5_2*NCC/3=O]/1-1-1-1/a?-b1_b?-c1_c?-d1_b?-c?~n

生成されたイメージ

image

正しいイメージ

image
WURCS=2.0/1,2,2/[a2122h-1x_1-5_2*NCC/3=O]/1-1/a?-b1_a?-b?~n

生成されたイメージ

画像は生成されず、無限ループ発生

正しいイメージ

image

繰り返し構造の外部に単糖が結合している糖鎖構造は、繰り返しの開始地点と終了地点の位置が逆転しており、完全に破綻した構造になっていた。どの単糖が入れ替わっているのかがわからないため、目安としてそれぞれの単糖の結合位置を以下のように変更した。

image

各単糖の結合位置を変更してWURCSを出力し、再度読み込みを行ったところ以下のような画像が出力された。

WURCS=2.0/1,4,4/[a2122h-1b_1-5_2*NCC/3=O]/1-1-1-1/a3-b1_b6-c1_c4-d1_b1-c4~n
image

結合位置が明確な場合は正しい繰り返し構造が出力されていた。ただし、StartRep側の結合位置が3から4へ変更しているため適切ではない。この件に関しては、繰り返し構造編集のWURCSを可視化した際の問題として報告を受けている。

また、単糖がどのように入れ替わるのかを確認するために、全て異なる単糖で繰り返し構造を編集した。

image
WURCS=2.0/4,4,4/[a1122h-1x_1-5][a2122h-1x_1-5][a2112h-1x_1-5][a2122h-1x_1-5_2*NCC/3=O]/1-2-3-4/a?-b1_b?-c1_c?-d1_b?-c?~n
image

繰り返し構造の前後が入れ替わっていた。

繰り返し構造だけで構成されている単糖は、Nアセチルノイラミン酸の繰り返し構造のように無限ループを生じていた。今回の場合は、2糖で構成されている繰り返し構造のため、終点側の単糖が開始側の単糖と親子関係を形成し、GlcNAc->GlcNAc->GlcNAc...のように無限ループを生じている。\ 単糖の結合位置を設定した場合でも同様の問題が生じていることを確認している(参考)。このことから、繰り返しの外部に単糖が結合していない繰り返し構造と、結合位置が不明確な繰り返し構造のWURCSを描画する際に問題があることがわかった。

e15d5605 commented 2 years ago

GLINToLinkageにはanalyzeAcceptorGLINanalyzeDonorGLINという関数が実装されている。これらの関数では繰り返し構造の解析を行っており、以下のような名称の関数を参照している。

これらは、繰り返し構造の開始点・終点の単糖のGLINを解析して結合位置を取り出すための関数である。analyzeRepeatingGLINforChildでは、StartMonosaccharide-StartRepの間の結合位置を取り出しをした後に、繰り返し構造のStartMonosaccharideを参照している。一方で、this.analyzeRepeatingGLINforParent(a_oDGLIN);では、EndRep-EndMonosaccharideの結合位置を取り出している。

前者の処理を確認したところ、繰り返し構造の開始地点と終了地点の前後関係を適切に扱うことができていなかった。開始地点->終了地点と親子関係が定義されていたのに対し、使用する関数を間違えていたため親の開始地点ではなく、子の終了地点を参照していた。取り出した単糖のIDを確認することで、繰り返し構造の開始単糖が適切なものかを判断することができると考えられる。WURCSの読み込み機能で利用しているWURCSSequence2では、単糖や結合にIDが割り当てられている。単糖のIDはルートに近いほど若くなるため、終了地点>開始地点となる。

以上のことから、GLINの繰り返し構造の解析時に以下のような条件で確認する必要がある

  1. GLINToLinkageで複数の単糖の繰り返し構造の前後関係を参照した時にGRESのIDが若い方が開始単糖になっているか
  2. GLINToLinkageでAcceptor側のGRESを参照した時に、同じGRESを取り出していないか
  3. LinkageConnectorで繰り返し構造をつなぐ時、親子の単糖が同じものでないか

さらに、analyzeRepeatingGLINforChildの開始単糖を参照する処理を以下のように書き換える。

誤り

this.startGRES = _acceptorGLIN.getDonor().get(0);

改定案

this.startGRES = _acceptorGLIN.getAcceptor().get(0);
e15d5605 commented 2 years ago

繰り返し構造で無限ループになる結合が形成されていた原因は、WURCSSequence2の解析処理で繰り返し構造を構成する親子の単糖の参照方法に問題があるためだった。この問題の解決手段として、単独の単糖の繰り返し構造から親・子の単糖を参照しない方法を考えられる。しかし、これらは後のLinkageConnectorで必要な要素である。今回の問題は繰り返し構造を構成する単糖と子ノードとの結合を定義する処理で発生している。そこで、LinkageConnectorで繰り返し構造の単糖の結合を確認する時に、親子が同じ単糖であるかを確認するようにした。

この状態で描画時に無限ループが発生していたWURCSを入力した

WURCS=2.0/1,1,1/[Aad21122h-2a_2-6_5*NCC/3=O_7%?%*OCC/3=O_8%?%*OCC/3=O]/1/a2-a9~n
image

また、繰り返し内部の単糖を増やした。

WURCS=2.0/1,2,2/[a2122h-1x_1-5_2*NCC/3=O]/1-1/a?-b1_a?-b?~n
image

無限ループは避けられているが、StartRep側の結合関係をうまく定義できていないため、引き続き対応を行う。

WURCSSequence2から変換したGlycanのルートノード解析処理で、繰り返し構造や環状構造の開始位置を持つ場合にうまく対応できていなかったためである。Glycanのルートノードを定義する処理で、これらの構造の特徴を持つ場合に対応するための条件を追加した。

e15d5605 commented 2 years ago

無限ループと直接関している内容では無いが、繰り返し構造のGLINを解析する際にDonor/Acceptorの向きが異なることを確認した。 置換基を挟む場合と、そうでない場合とで開始単糖/終了単糖の参照方法が異なっている。これに気がつかないまま両方の繰り返し構造を解析していたため、正しく糖鎖構造を描画することができなくなっていたと考えられる。

この問題を解決するために、繰り返し構造のAcceptor/Donor GLINが保持しているGRESのIDを確認し、繰り返し構造の開始単糖/終了単糖を定義するようにした。従来の使用では、AcceptorGLINの繰り返し構造をEndRep、DonorGLINの繰り返し構造をStartRepと固定して対応していたが、今回のようにGRESのIDで判断することで柔軟に対応することが可能となる。

e15d5605 commented 2 years ago

検証用繰り返し構造のWURCS

WURCS=2.0/1,4,4/[a2122h-1a_1-5]/1-1-1-1/a4-b1_b4-c1_c4-d1_a1-d4~n
WURCS=2.0/1,4,4/[a2122h-1a_1-5]/1-1-1-1/a4-b1_b4-c1_c4-d1_a1-d4*OSO*/3=O/3=O~n
WURCS=2.0/1,5,5/[a2122h-1a_1-5]/1-1-1-1-1/a4-b1_b4-c1_c4-d1_d6-e1_a?-d4~n
WURCS=2.0/2,6,7/[a2122h-1b_1-5_2*NCC/3=O][a2112h-1b_1-5_2*NCC/3=O]/1-1-2-2-1-1/a4-b1_b4-c1_c4-d1_d4-e1_e4-f1_b?-e4~n_c?-d4~n
WURCS=2.0/1,6,7/[a2122h-1a_1-5]/1-1-1-1-1-1/a4-b1_b4-c1_c4-d1_d4-e1_e4-f1_a1-f?_a1-f4~n
e15d5605 commented 1 year ago

ImageMagickを用いた画像比較

GB2から出力される糖鎖構造の画像を検証するために、ImageMagicの利用を検討している。具体的には、異なるバージョンのGB2を利用してGlyTouCanに登録されている糖鎖構造のイメージを出力し、ImageMagicで比較を行う。ここでは、ImageMagicの使い方について調べ、実際に糖鎖構造の画像を用いて動作確認を行い、得られた結果について記載する。

上記のコマンドを実行すると、以下のような結果が返される。

画像が完全一致する場合は0が出力され、一致しなかった場合はそれ以外の数字が出力される。

また、画像比較を実行して異なっていた箇所を強調表示した画像を出力することもできる。第一引数と第二引数に比較用の画像を入力し、第三引数に差分を強調した画像の名前を入力する。

compare -metric AE <Image A> <Image B> <DifferenceImage> ;

diffrence

ルートノードのグルコースがD/Lで異なっているため、Lが赤色で表示されている。

単糖数や結合情報のフォントが異なる場合は、以下のように表示される。今回の検証は、同じWURCSを使用して生成した糖鎖のイメージを比較する。そのため、実際にこのような比較パターンが出ることは少ないと考えられるが、参考として提示する。

0 8 0 glycanimage

diffrence

また、単糖の色が異なる場合も正しく判定してくれるようだ。

yamadaissaku commented 1 year ago

ImageMagickを用いた画像比較は、どのように行われているのかわかりますか?

e15d5605 commented 1 year ago

@yamadaissaku 上のサンプルで示した比較は-metric AEというオプションを利用しています。これは、画像間のピクセル単位のズレを比較するというオプションです。 また、他にも多くの比較用オプションが実装されていることを確認しています。比較の詳細については、ImageMagickのアルゴリズムに関して調べきれていないのでわかりません。今のところわかっている情報として、オプションでピクセルの比較方法が異なっていることは確認できています。ImageMagickのオプションを記載したドキュメントを共有させていただきます。