• R/O
  • SSH
  • HTTPS

gsltools: コミット


コミットメタ情報

リビジョン1 (tree)
日時2009-11-01 22:45:04
作者zuhito

ログメッセージ

(メッセージはありません)

変更サマリ

差分

--- jp/ac/ritsumei/is/infobio/Prediction.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/Prediction.java (revision 1)
@@ -0,0 +1,1111 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.text.*;
3+import java.awt.*;
4+import java.awt.event.*;
5+import javax.swing.*;
6+import java.util.*;
7+import javax.swing.table.*;
8+import java.util.concurrent.*;
9+import java.lang.management.*;
10+
11+/**
12+ * 候補構造を表すクラスです.
13+ * @author 横井一仁
14+ * @version 20081221
15+ */
16+class Candidate extends Glycan
17+{
18+ java.util.List<Composition> frags_t; // 理論上のフラグメント組成
19+ double[] masses_t; // 理論上のフラグメントの分子量
20+ static double[] masses_a; // 実測フラグメントの分子量(インスタンス間で共有)
21+ static double[] freq; // 出現確率を格納した配列(インスタンス間で共有)
22+ static String adduct = MassCalc.Na_ION; // 付加イオン(デフォルトはNa+)
23+ static boolean monoavg = MassCalc.MONO_MASS; // Monoisotopic(ture),Averaget(false)
24+ static double tolerance_psd = 1.0; // 実測値と理論値の許容誤差(PSD)
25+ Fragmentation fg = new Fragmentation(); // フラグメント化するクラス
26+
27+ static int window = 1; // 出現確率の区分け幅(Da)
28+ static final int POSITIVE_SCORING = 0; // ポジティブなフラグメントのみしか考えないスコアリング
29+ static final int TFIDF_SCORING = 1; // tf-idfのスコアリング
30+ static final int PENALTY01_SCORING = 2; // ペナルティに係数0.1をかけたスコアリング
31+ static final int PENALTY001_SCORING = 3; // ペナルティに係数0.01をかけたスコアリング
32+ static final int PMF_SCORING = 4; // 主にPMF法に用いられているスコアリング
33+ static final int GEOMETRICAVG_SCORING = 5; // 確率の相乗平均を用いたスコアリング
34+ static int formula = TFIDF_SCORING; // 予測に用いるスコア式(デフォルトはTFIDF_SCORING)
35+
36+ public Candidate()
37+ {
38+ // 現在のところ継承に必要である以外,処理は何もしない.
39+ }
40+
41+ public Candidate(Glycan gc) throws Exception
42+ {
43+ this.setNode(gc.getNode()); // 構造を登録する.
44+ this.setEdge(gc.getEdge());
45+ this.setChildren(gc.getChildren());
46+
47+ Glycan temp_gc = new Glycan(gc);
48+ temp_gc.toHexose(); // "Glc", "Gal"などを"Hex"に変換
49+ fg.setGlycan(temp_gc);
50+ this.frags_t = fg.getComposition(); // それぞれのフラグメントを取得する.
51+ this.masses_t = new double[this.frags_t.size()]; // フラグメント数と同じサイズの配列を用意
52+
53+ int i = 0;
54+ for (Composition temp_cp : this.frags_t)
55+ masses_t[i++] = temp_cp.getMass(monoavg, adduct); // フラグメントの分子量を計算しておく
56+ }
57+
58+ /**
59+ * 実測フラグメントの値を登録します.
60+ * @param temp_freq 実測フラグメントの値を格納した配列
61+ */
62+ public synchronized static void setMasses_a(double[] masses_a)
63+ {
64+ Candidate.masses_a = masses_a;
65+ }
66+
67+ /**
68+ * 出現確率を格納した配列を登録します.
69+ * @param freq 出現確率を格納した配列
70+ */
71+ public synchronized static void setFreq(double[] freq)
72+ {
73+ Candidate.freq = freq;
74+ }
75+
76+ /**
77+ * 出現確率を格納した配列を返します.
78+ * @return 出現確率を格納した配列
79+ */
80+ public synchronized static double[] getFreq()
81+ {
82+ return Candidate.freq;
83+ }
84+
85+ /**
86+ * モノアイソトープ,またはアベレージで計算するかを設定します.
87+ * @param monoavg モノアイソトピックまたはアベレージ
88+ */
89+ public synchronized static void setMonoavg(boolean monoavg) throws Exception
90+ {
91+ Candidate.monoavg = monoavg; // クラスメンバとする.
92+ }
93+
94+ /**
95+ * 予測に用いる付加イオンを指定します.
96+ * @param adduct 付加イオン(デフォルトはNa+)
97+ */
98+ public synchronized static void setAdduct(String adduct)
99+ {
100+ Candidate.adduct = adduct; // クラスメンバとする.
101+ }
102+
103+ /**
104+ * 予測に用いる付加イオンを指定します.
105+ * @param adduct 付加イオン(デフォルトはNa+)
106+ */
107+ public synchronized static void setPsdTolerance(double tolerance_psd)
108+ {
109+ Candidate.tolerance_psd = tolerance_psd; // クラスメンバとする.
110+ }
111+
112+ /**
113+ * 予測に用いるスコア式を指定します.
114+ * @param formula スコア式
115+ */
116+ public synchronized static void setScoringFormula(int formula)
117+ {
118+ Candidate.formula = formula; // クラスメンバとする.
119+ }
120+
121+ /**
122+ * 予測に用いるスコア式を返します.
123+ * @return 指定されたスコア式を表す数字
124+ */
125+ public synchronized static int getScoringFormula()
126+ {
127+ return Candidate.formula;
128+ }
129+
130+ /**
131+ * 出現確率分布のウィンドウサイズを指定します.
132+ * @param window ウィンドウサイズ
133+ */
134+ public synchronized static void setWindowSize(int window)
135+ {
136+ Candidate.window = window; // クラスメンバとする.
137+ }
138+
139+ /**
140+ * 現在登録されている出現確率分布のウィンドウサイズを取得します.
141+ * @return ウィンドウサイズ
142+ */
143+ public synchronized static int getWindowSize()
144+ {
145+ return window; // Candidateクラスのstatic変数を呼び出す.
146+ }
147+
148+ // 実測値と出現頻度値より,糖鎖構造のスコアを計算します.
149+ public synchronized double getScore() throws Exception
150+ {
151+ double score = 0.0;
152+ double penalty = 0.0;
153+ boolean[] check = new boolean[freq.length]; // 再度利用しないようにフラッグを立てる.
154+ int count_posi = 0, count_nega = 0; // ペナルティに用いる.
155+
156+ for (double mass_t : masses_t) // 糖鎖のフラグメント分子量を取得する.
157+ for (double mass_a : masses_a) // 実測値と理論値とのマッチング
158+ if (!check[(int)(mass_t/window)] && Math.abs(mass_a - mass_t) < tolerance_psd)
159+ {
160+ score += -Math.log(freq[(int)(mass_t/window)]);
161+ check[(int)(mass_t/window)] = true; // 再度利用しないようにフラッグを立てる.
162+ count_posi++;
163+ }
164+ else
165+ {
166+ penalty += -Math.log(1.1 - freq[(int)(mass_t/window)]);
167+ count_nega++; // マッチしなかった実測値の個数を数える
168+ }
169+
170+ if (formula == Candidate.POSITIVE_SCORING) // ポジティブなフラグメントのみしか考えないスコアリング
171+ return score; // 出現確率が低い,珍しいものの値を上げる.
172+ else if (formula == Candidate.TFIDF_SCORING) // tf-idfのスコアリング
173+ return (score + 1.0) * count_posi / masses_t.length;
174+ else if (formula == Candidate.PENALTY01_SCORING) // ペナルティに係数0.1をかけたスコアリング
175+ return score - 0.1 * penalty;
176+ else if (formula == Candidate.PENALTY001_SCORING) // ペナルティに係数0.01をかけたスコアリング
177+ return score - 0.01 * penalty;
178+ else if (formula == Candidate.PMF_SCORING) // 主にPMF法に用いられているスコアリング
179+ return score + penalty;
180+ else if (formula == Candidate.GEOMETRICAVG_SCORING) // 確率の相乗平均を用いたスコアリング
181+ return (score + penalty) / masses_t.length;
182+ else
183+ throw new Exception("unknown scoring formula number: " + formula);
184+ }
185+
186+ /**
187+ * 候補構造のフラグメントが実測フラグメントと何個一致したかを返します.
188+ * @return マッチしたフラグメント数
189+ */
190+ public int countMatch()
191+ {
192+ int count = 0;
193+ for (double mass : this.masses_t)
194+ {
195+ boolean check = false;
196+ for (int i = 0; i < masses_a.length && !check; i++)
197+ if (mass - 1.0 < masses_a[i] && masses_a[i] < mass + 1.0)
198+ {
199+ count++; // 実測値と理論値がいくつマッチするか数える.
200+ check = true; // 同じフラグメントで2回数えないようにする.
201+ }
202+ }
203+
204+ return count;
205+ }
206+
207+ /**
208+ * 候補構造のフラグメントの何%が実測フラグメントと一致したかを返します.
209+ * @return 理論上のフラグメント数に対するマッチしたフラグメントの割合
210+ */
211+ public double getOccupancy()
212+ {
213+ return 100.0 * this.countMatch() / this.masses_t.length; // (100 * 一致数 / 理論フラグメント数)
214+ }
215+
216+ /**
217+ * 候補構造のフラグメントのm/zを返します.
218+ * @return フラグメントのm/zの配列
219+ */
220+ public double[] getFragMasses()
221+ {
222+ return this.masses_t;
223+ }
224+}
225+
226+/**
227+ * フラグメントイオンから糖鎖構造を予測するクラスです.
228+ * @author 横井一仁
229+ * @version 20080425
230+ */
231+public class Prediction extends Observable // 進行状況の監視を可能とする.
232+{
233+ CompositionTools cp_agg = new CompositionTools(); // 継承の代わりに集約を用いる.
234+ double precursor = 0.0; // プレカーサーイオンの実測値
235+ double[] masses_a; // フラグメント分子量の実測値
236+ double tolerance_psd; // 実測値と理論値の許容誤差(PSD)
237+ double tolerance_ms = 1.0; // 指定がなければ,1.0とする.
238+ Glycan known_gc; // 既知構造
239+ Composition known_cp; // 既知組成
240+ int percent; // 進捗情報表示するために用いる.
241+ boolean flag = true; // キャンセルされた時に断片化処理を抜けるためのフラッグ
242+
243+ /**
244+ * モノアイソトープ,またはアベレージで計算するかを設定します.
245+ * @param monoavg モノアイソトピックまたはアベレージ.
246+ */
247+ public void setMonoavg(boolean monoavg) throws Exception
248+ {
249+ Candidate.setMonoavg(monoavg); // Candidateクラスのstatic変数として登録する.
250+ cp_agg.setMonoavg(monoavg); // 組成を予測するクラスのメソッドを利用して登録する.
251+ }
252+
253+ /**
254+ * 予測に用いる付加イオンを指定します.
255+ * @param adduct 付加イオン(デフォルトはNa+)
256+ */
257+ public void setAdduct(String adduct) throws Exception
258+ {
259+ Candidate.setAdduct(adduct); // Candidateクラスのstatic変数として登録する.
260+ cp_agg.setAdduct(adduct); // 組成を予測するクラスのメソッドを利用して登録する.
261+ }
262+
263+ /**
264+ * PSDスペクトルの実測値と理論値の許容誤差を登録します.
265+ * @param tolerance_psd 実測値と理論値の許容誤差
266+ */
267+ public void setPsdTolerance(double tolerance_psd) throws Exception
268+ {
269+ this.tolerance_psd = tolerance_psd; // クラスメンバとする.
270+ Candidate.setPsdTolerance(tolerance_psd); // Candidateクラスのstatic変数として登録する.
271+ }
272+
273+ /**
274+ * フラグメントにおける実測の<I>m/z</I> を登録します.
275+ * @param masses_a フラグメントにおける実測の<I>m/z</I>
276+ */
277+ public void setFragments(double[] masses_a)
278+ {
279+ this.masses_a = masses_a; // メンバ変数として格納
280+ Candidate.setMasses_a(masses_a); // Candidateクラスのstatic変数として登録する.
281+ }
282+
283+ /**
284+ * 予測に用いるスコア式を指定します.
285+ * @param formula スコア式
286+ */
287+ public void setScoringFormula(int formula)
288+ {
289+ Candidate.setScoringFormula(formula); // Candidateクラスのstatic変数として登録する.
290+ }
291+
292+ /**
293+ * 出現確率分布のウィンドウサイズを指定します.
294+ * @param window ウィンドウサイズ
295+ */
296+ public void setWindowSize(int window)
297+ {
298+ Candidate.setWindowSize(window); // Candidateクラスのstatic変数として登録する.
299+ }
300+
301+ /**
302+ * 現在登録されている出現確率分布のウィンドウサイズを取得します.
303+ * @return ウィンドウサイズ
304+ */
305+ public int getWindowSize()
306+ {
307+ return Candidate.getWindowSize(); // Candidateクラスのstatic変数を呼び出す.
308+ }
309+
310+ /**
311+ * プレカーサーマスの<I>m/z</I> を登録します.
312+ * @param precursor プレカーサーマスの<I>m/z</I>
313+ */
314+ public void setPrecursorMass(double precursor)
315+ {
316+ this.precursor = precursor; // メンバ変数として格納
317+ }
318+
319+ /**
320+ * 糖鎖組成の予測に用いる許容誤差を登録します.
321+ * @param tolerance_ms 許容誤差
322+ */
323+ public void setMsTolerance(double tolerance_ms)
324+ {
325+ this.tolerance_ms = tolerance_ms;
326+ }
327+
328+ /**
329+ * 既知糖鎖構造を登録します.
330+ * @param known_gc 既知構造
331+ */
332+ public void setGlycan(Glycan known_gc)
333+ {
334+ this.known_gc = known_gc;
335+ }
336+
337+ /**
338+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
339+ * @param lcb 長鎖塩基組成
340+ */
341+ public void setLongChainBase(java.util.List<String> lcb) throws Exception
342+ {
343+ cp_agg.setLongChainBase(lcb);
344+ }
345+
346+ /**
347+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
348+ * @param fa 脂肪酸組成
349+ */
350+ public void setFattyAcid(java.util.List<String> fa) throws Exception
351+ {
352+ cp_agg.setFattyAcid(fa);
353+ }
354+
355+ /**
356+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
357+ * @param min 炭素数の最小値
358+ * @param max 炭素数の最大値
359+ */
360+ public void setLongChainBase(int min, int max) throws Exception
361+ {
362+ cp_agg.setLongChainBase(min, max);
363+ }
364+
365+ /**
366+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
367+ * @param min 炭素数の最小値
368+ * @param max 炭素数の最大値
369+ */
370+ public void setFattyAcid(int min, int max, int bond) throws Exception
371+ {
372+ cp_agg.setFattyAcid(min, max, bond);
373+ }
374+
375+ /**
376+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
377+ * @param ceramide セラミド組成
378+ */
379+ public void setCeramide(java.util.List<String> ceramide) throws Exception
380+ {
381+ cp_agg.setCeramide(ceramide);
382+ }
383+
384+ /**
385+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
386+ * @param min 炭素数の最小値
387+ * @param max 炭素数の最大値
388+ * @param bond 脂肪酸の二重結合の最大値
389+ */
390+ public void setCeramide(int min, int max, int bond)
391+ {
392+ cp_agg.setCeramide(min, max, bond);
393+ }
394+
395+ /**
396+ * 予測で考慮する各糖の糖数を指定します.
397+ * @param str 糖数を指定する糖
398+ * @param max 指定する糖数
399+ */
400+ public void setMax(String str, int max) throws Exception
401+ { // デフォルトはhex_max = 10, hexnac_max = 10, dhex_max = 10, dhexme_max = 0, pen_max = 0
402+ cp_agg.setMax(str, max);
403+ }
404+
405+ /**
406+ * 予測で考慮する各糖の糖数を指定します.
407+ * @param str 指定する糖
408+ * @param bl 糖を存在させるかを指定
409+ */
410+ public void setMax(String str, boolean bl) throws Exception
411+ {
412+ cp_agg.setMax(str, bl);
413+ }
414+
415+ /**
416+ * 予測された候補構造を返します.
417+ * @return スコアが高い順に予想構造を返します.
418+ */
419+ public java.util.List<? extends Candidate> getPrediction() throws Exception
420+ { // 指定された条件から候補構造を生成します.
421+ java.util.List<Composition> cps = getCandidateComposition(); // 候補組成を作成
422+ java.util.List<Glycan> candi = this.getCandidateGlycan2(cps); // 候補構造を生成し,リストに格納
423+ java.util.List<Candidate> al = this.toCandidateInstance2(candi); // Glycanを,Candidateの候補構造として登録
424+ Candidate.setFreq(this.getFreqency(al)); // 出現確率を計算し,
425+ // Candidateクラスのstatic変数として登録
426+ Collections.sort(al, new Comparator<Candidate>() // スコア順にソート
427+ {
428+ public int compare(Candidate cp1, Candidate cp2)
429+ {
430+ double sub = 0.0; // スコアの差
431+ try
432+ {
433+ double score1 = cp1.getScore();
434+ double score2 = cp2.getScore();
435+
436+ if (score1 == score2) // スコアが等しい構造は,分岐数の少ない
437+ sub = cp1.countLeaf() - cp2.countLeaf(); // (葉ノードの数が少ない)構造を上位に表示
438+ else
439+ sub = score2 - score1;
440+
441+ }
442+ catch (Exception e)
443+ {
444+ System.err.println("Prediction.getPrediction(): score compare error");
445+ }
446+
447+ return (int)(sub*1024); // 精度を1024倍に上げる
448+ }
449+ }); // スコアが高い順にソートを行う.
450+
451+ return al;
452+ }
453+
454+ /**
455+ * 候補組成を生成し,リストに格納します.
456+ */
457+ protected java.util.List<Composition> getCandidateComposition() throws Exception
458+ {
459+ java.util.List<Composition> cps; // 考えられる組成を格納するリスト
460+
461+ cp_agg.setComposition(known_cp);
462+ cp_agg.setGlycan(known_gc);
463+ cp_agg.setMsTolerance(tolerance_ms);
464+
465+ if (precursor == 0.0) // 親マスの分子量が登録されていない場合,
466+ { // フラグメント分子量の最大実測値から計算する.
467+ cp_agg.setMass(masses_a); // フラグメントのm/zを配列のまま入力する.
468+ cps = cp_agg.getComposition();
469+ }
470+ else // 親マスの分子量が登録されている場合
471+ {
472+ cp_agg.setMass(precursor);
473+ java.util.List<Double> masses_a_li = new ArrayList<Double>(); // プレカーサマスとPSDスペクトルの親マスとの
474+ for (double temp : masses_a) // 誤差がPSDスペクトルの許容誤差以内の場合,
475+ if (temp < precursor - tolerance_psd) // かつ,親マスのm/zより,小さなm/z
476+ masses_a_li.add(temp); // を持つPSDフラグメントから組成を予測する.
477+
478+ double[] masses_a_temp = new double[masses_a_li.size()]; // リストと同じ大きさの配列を用意する.
479+ Iterator<Double> it = masses_a_li.iterator();
480+ for (int i = 0; it.hasNext(); i++) // リストの内容を配列にコピー
481+ masses_a_temp[i] = it.next();
482+
483+ cp_agg.setMass(masses_a_temp); // フラグメントのm/zを配列として入力
484+ cps = cp_agg.getComposition();
485+ }
486+
487+ return cps;
488+ }
489+
490+ /**
491+ * 候補構造を生成し,リストに格納します.(シングルスレッド版)
492+ */
493+ protected java.util.List<Glycan> getCandidateGlycan(java.util.List<Composition> cps) throws Exception
494+ {
495+ java.util.List<Glycan> candi = new ArrayList<Glycan>(); // 候補構造を格納するリスト
496+ Iterator<Composition> it = cps.iterator();
497+ for (int i = 1; it.hasNext() && flag; i++) // プレカーサーマスとフラグメントから求めた候補組成
498+ {
499+ Composition cp = it.next(); // 候補組成を取得
500+
501+ percent = (int)(i * 99.0 / cps.size()); // 処理が何%進んだかを格納(表示が消えるため99%)
502+ String messege = (int)(i*100.0/cps.size()) + "% Creating candidate structure... " + "[" + cp + "]";
503+ this.setChanged(); // 変更があったことを明示する.
504+ this.notifyObservers(messege); // 監視者に進行状況を通知
505+ this.clearChanged(); // 変更された状態でないことを明示する.
506+
507+ CandidateTools ct = new CandidateTools(); // 候補構造を生成するためにインスタンスを生成
508+ ct.setComposition(cp); // 既知構造の登録であるsetGlycan()は処理済み.
509+ ct.setGlycan(known_gc); // 既知糖鎖構造を登録
510+ candi.addAll(ct.getGlycan()); // 候補構造を取得し,全てHashSetに格納
511+ }
512+
513+ if (!flag) // 処理が中断された場合,
514+ candi.clear(); // Glycanインスタンスの候補構造を削除
515+
516+ return candi;
517+ }
518+
519+ /**
520+ * 候補構造を生成し,リストに格納します.(マルチスレッド版)
521+ */
522+ protected java.util.List<Glycan> getCandidateGlycan2(java.util.List<Composition> cps) throws Exception
523+ {
524+ java.util.List<Glycan> candi = new ArrayList<Glycan>(); // 候補構造を格納するリスト
525+ Iterator<Composition> it = cps.iterator();
526+ for (int i = 1; it.hasNext() && flag; i++) // プレカーサーマスとフラグメントから求めた候補組成
527+ {
528+ StringBuffer cp_messege = new StringBuffer(); // 現在処理中の糖鎖を文字列表示にて格納
529+ java.util.List<Composition> cp_thread = new ArrayList<Composition>(); // 1回の処理で並列計算させるタスク
530+ for (int j = 0; j < 8 && it.hasNext(); j++) // 8スレッドを並列
531+ {
532+ Composition temp = it.next(); // 候補組成を取得
533+ cp_messege.append("[" + temp + "], ");
534+ cp_thread.add(temp); // マルチスレッドのタスクに追加
535+
536+ i++; // 処理済みの個数を増加させる.
537+ }
538+ i--; // for文の中で値が1つ多くなるため,削除
539+
540+ percent = (int)(i * 99.0 / cps.size()); // 処理が何%進んだかを格納(表示が消えるため99%)
541+ String messege = (int)(i*100.0/cps.size())
542+ + "% Creating candidate structures. "
543+ + cp_messege.toString();
544+ this.setChanged(); // 変更があったことを明示する.
545+ this.notifyObservers(messege); // 監視者に進行状況を通知
546+ this.clearChanged(); // 変更された状態でないことを明示する.
547+
548+ java.util.List<Callable<java.util.List<Glycan>>> tasks
549+ = new ArrayList<Callable<java.util.List<Glycan>>>(); // タスクを格納するリスト
550+ for (Composition temp : cp_thread)
551+ {
552+ Callable<java.util.List<Glycan>> task
553+ = new MultiThreadTool2(new Composition(temp), new Glycan(known_gc));
554+ tasks.add(task);
555+ }
556+ ExecutorService es = Executors.newFixedThreadPool(8); // 8スレッドで実行
557+ java.util.List<Future<java.util.List<Glycan>>> futures = es.invokeAll(tasks); // タスクの実行
558+
559+ for (Future<java.util.List<Glycan>> future : futures) // 実行結果の回収
560+ candi.addAll(future.get()); // 候補構造を取得し,全てHashSetに格納
561+ es.shutdown(); // 並列処理の終了
562+ }
563+
564+ if (!flag) // 処理が中断された場合,
565+ candi.clear(); // Glycanインスタンスの候補構造を削除
566+
567+ return candi;
568+ }
569+
570+ /**
571+ * Glycanインスタンスを,Candidateインスタンスとし,フラグメント化を行います.(シングルスレッド版)
572+ */
573+ protected java.util.List<Candidate> toCandidateInstance(java.util.List<Glycan> candi) throws Exception
574+ {
575+ java.util.List<Candidate> al = new ArrayList<Candidate>(); // スコア付けを行う候補構造
576+ long start = new Date().getTime(); // プログラム開始時刻
577+ int candi_size = candi.size(); // 候補構造数を格納
578+ ListIterator<Glycan> it2 = candi.listIterator(); // 候補構造のイテレータを取得
579+ for (int i = 1; it2.hasNext() && flag; i++) // 考えられる組成のとり得る構造をArrayListに格納
580+ {
581+ Glycan temp = it2.next();
582+ it2.remove(); // 不必要であるGlycanインスタンスを削除する.
583+
584+ percent = (int)(i * 99.0 / candi_size); // 処理が何%進んだかを格納(表示が消えるため99%)
585+ String messege = progress(i, candi_size, start); // オブザーバに送るメッセージを作成する.
586+ try
587+ {
588+ messege = messege + " [" + temp.toNormalFormat() + "]"; // ノーマルのフォーマットで格納する.
589+ }
590+ catch (Exception e)
591+ {
592+ messege = messege + " [" + temp.toString() + "]"; // 二分岐以上の構造はLinucs形式で格納する.
593+ }
594+ this.setChanged(); // 変更があったことを明示する.
595+ this.notifyObservers(messege); // 監視者に進行状況を通知
596+ this.clearChanged(); // 変更された状態でないことを明示する.
597+
598+ Candidate cd = new Candidate(temp);
599+ al.add(cd);
600+ }
601+
602+ if (!flag) // 処理が中断された場合,
603+ al.clear(); // Candidateインスタンスの候補構造を削除
604+ else // 処理が正常に完了した場合,
605+ {
606+ percent = 100; // ProgressMonitorを終了するために100%にする.
607+ this.setChanged(); // 変更があったことを明示する.
608+ this.notifyObservers(progress(candi.size(), candi.size(), start)); // 監視者に進行状況を通知
609+ this.clearChanged(); // 変更された状態でないことを明示する.
610+ }
611+
612+ return al;
613+ }
614+
615+ /**
616+ * Glycanインスタンスを,Candidateインスタンスとし,フラグメント化を行います.(マルチスレッド版)
617+ */
618+ protected java.util.List<Candidate> toCandidateInstance2(java.util.List<Glycan> candi) throws Exception
619+ {
620+ java.util.List<Candidate> al = new ArrayList<Candidate>(); // スコア付けを行う候補構造
621+ long start = new Date().getTime(); // プログラム開始時刻
622+ int candi_size = candi.size(); // 候補構造数を格納
623+ ListIterator<Glycan> it2 = candi.listIterator(); // 候補構造のイテレータを取得
624+ for (int i = 1; it2.hasNext() && flag; i++) // 考えられる組成のとり得る構造をArrayListに格納.
625+ {
626+ StringBuffer gc_messege = new StringBuffer(); // 現在処理中の糖鎖を文字列表示にて格納する.
627+ java.util.List<Glycan> gc_thread = new ArrayList<Glycan>(); // 1回の処理で並列計算させるGlycanインスタンス
628+ for (int j = 0; j < 8 && it2.hasNext(); j++) // 8スレッドを並列させるので,8個ずつ処理する.
629+ {
630+ Glycan temp = it2.next();
631+ try
632+ {
633+ gc_messege.append(temp.toNormalFormat() + ", "); // ノーマルのフォーマットで格納する.
634+ }
635+ catch (Exception e)
636+ {
637+ gc_messege.append(temp.toString() + ", "); // 二分岐以上の構造はLinucs形式で格納する.
638+ }
639+ gc_thread.add(temp); // マルチスレッドのタスクに追加
640+ it2.remove(); // 不必要であるGlycanインスタンスを削除する.
641+
642+ i++; // 処理済みの個数を増加させる.
643+ }
644+ i--; // for文の中で値が1つ多くなるため,削除
645+
646+ percent = (int)(i * 99.0 / candi_size); // 処理が何%進んだかを格納(表示が消えるため99%)
647+ String messege = progress(i, candi_size, start); // オブザーバに送るメッセージ
648+ messege = messege + " " + gc_messege.toString();
649+ this.setChanged(); // 変更があったことを明示する.
650+ this.notifyObservers(messege); // 監視者に進行状況を通知
651+ this.clearChanged(); // 変更された状態でないことを明示する.
652+
653+ java.util.List<Callable<Candidate>> tasks = new ArrayList<Callable<Candidate>>(); // タスクを格納するリスト
654+ for (Glycan temp : gc_thread)
655+ {
656+ Callable<Candidate> task = new MultiThreadTool1(new Glycan(temp));
657+ tasks.add(task);
658+ }
659+ ExecutorService es = Executors.newFixedThreadPool(8); // 8スレッドで実行
660+ java.util.List<Future<Candidate>> futures = es.invokeAll(tasks); // タスクの実行
661+
662+ for (Future<Candidate> future : futures) // 実行結果の回収
663+ {
664+ Candidate cd = future.get();
665+ al.add(cd);
666+ }
667+ es.shutdown(); // 並列処理の終了
668+ }
669+
670+ if (!flag) // 処理が中断された場合,
671+ al.clear(); // Candidateインスタンスの候補構造を削除する
672+ else // 処理が正常に完了した場合,
673+ {
674+ percent = 100; // ProgressMonitorを終了するために100%にする.
675+ this.setChanged(); // 変更があったことを明示する.
676+ this.notifyObservers(progress(candi.size(), candi.size(), start)); // 監視者に進行状況を通知
677+ this.clearChanged(); // 変更された状態でないことを明示する.
678+ }
679+
680+ return al;
681+ }
682+
683+ /**
684+ * フラグメントの出現確率の計算値を返します.
685+ */
686+ public double[] getFreqency(java.util.List<? extends Candidate> al) throws Exception
687+ {
688+ double[] freq; // returnする確率分布
689+
690+ if (precursor == 0.0) // 親マスの分子量が登録されていない場合,
691+ { // フラグメント分子量の最大実測値から計算
692+ Arrays.sort(masses_a); // 最大値を取り出すために昇順にソート.
693+ freq = new double[(int)(masses_a[masses_a.length-1]/this.getWindowSize())+100]; // 10Daずつ出現頻度を計算
694+ }
695+ else // 親マスの分子量が登録されている場合
696+ freq = new double[(int)(precursor/this.getWindowSize())+100]; // 10Daずつ出現頻度を計算する.
697+
698+ for (Candidate cd : al)
699+ {
700+ boolean[] check = new boolean[freq.length]; // 1構造で質量が重複させないために使用
701+
702+ double[] masses = cd.getFragMasses();
703+ for (int i = 0; i < masses.length; i++) // それぞれのフラグメントを取得し,
704+ { // フラグメントが存在したらtrueとする.
705+ if ((int)(masses[i]/this.getWindowSize()) > 0)
706+ check[(int)(masses[i]/this.getWindowSize()) - 1] = true; // 前のフラッグを立てる.
707+
708+ check[(int)(masses[i]/this.getWindowSize())] = true; // 現在の位置のフラッグを立てる.
709+
710+ if (i+1 < freq.length)
711+ check[(int)(masses[i]/this.getWindowSize()) + 1] = true; // 後ろのフラッグも立てる.
712+ }
713+
714+ for (int i = 0; i < freq.length; i++) // フラッグを出現確率の配列へコピー
715+ if (check[i]) // フラグメントが存在したら1個増加
716+ freq[i] += 1.0;
717+ }
718+
719+ double max = 1.0; // 0で割らないために初期値は1とする.
720+ for (double temp : freq) // 最大値を探す.
721+ max = Math.max(temp,max);
722+
723+ for (int i = 0; i < freq.length; i++) // 最大値で割り,0.0〜1.0の範囲に変換.
724+ freq[i] = freq[i] / max;
725+
726+ return freq;
727+ }
728+
729+ /**
730+ * 進捗情報の表示
731+ * @parm prog 処理の終わった個数
732+ * @parm total 処理する個数
733+ * @parm strat 処理開始時間
734+ */
735+ protected String progress(int prog, int total, long start)
736+ {
737+ Calendar cd;
738+ StringBuilder temp = new StringBuilder(64); // リターンする文字列
739+
740+ if (total != 0) // 0で割らないための処理
741+ temp.append((int)(prog*100/total));
742+ else
743+ temp.append("100");
744+ temp.append("%");
745+
746+ cd = Calendar.getInstance();
747+ cd.set(Calendar.DAY_OF_YEAR, 1);
748+ cd.set(Calendar.HOUR_OF_DAY, 0);
749+ cd.set(Calendar.MINUTE, 0);
750+ cd.set(Calendar.SECOND, 0);
751+ if (prog != 0) // 0で割らないための処理
752+ cd.set(Calendar.MILLISECOND, (int)((new Date().getTime() - start)*(total-prog)/prog));
753+ else
754+ cd.set(Calendar.MILLISECOND, 0);
755+ temp.append(" Remain: ");
756+ temp.append(cd.get(Calendar.DAY_OF_YEAR)-1);
757+ temp.append(":");
758+ temp.append(new SimpleDateFormat("HH:mm:ss").format(cd.getTime()));
759+
760+ cd = Calendar.getInstance();
761+ cd.set(Calendar.DAY_OF_YEAR, 1);
762+ cd.set(Calendar.HOUR_OF_DAY, 0);
763+ cd.set(Calendar.MINUTE, 0);
764+ cd.set(Calendar.SECOND, 0);
765+ cd.set(Calendar.MILLISECOND, (int)(new Date().getTime() - start));
766+ temp.append(" Current: ");
767+ temp.append(cd.get(Calendar.DAY_OF_YEAR)-1);
768+ temp.append(":");
769+ temp.append(new SimpleDateFormat("HH:mm:ss").format(cd.getTime()));
770+
771+ cd = Calendar.getInstance();
772+ cd.set(Calendar.DAY_OF_YEAR, 1);
773+ cd.set(Calendar.HOUR_OF_DAY, 0);
774+ cd.set(Calendar.MINUTE, 0);
775+ cd.set(Calendar.SECOND, 0);
776+ if (prog != 0) // 0で割らないための処理
777+ cd.set(Calendar.MILLISECOND, (int)((new Date().getTime() - start)*(total)/prog));
778+ else
779+ cd.set(Calendar.MILLISECOND, 0);
780+ temp.append(" Total: ");
781+ temp.append(cd.get(Calendar.DAY_OF_YEAR)-1);
782+ temp.append(":");
783+ temp.append(new SimpleDateFormat("HH:mm:ss").format(cd.getTime()));
784+
785+ return temp.toString();
786+ }
787+
788+ /**
789+ * 理論値による検証(実験結果出力用メソッド)
790+ * @parm args 検証を始める構造のm/z
791+ */
792+ private static void runSimulation(double args) throws Exception
793+ {
794+ System.out.println("Da,\t選択flag数,\t理論flag数,\t予測可否,\t予測順位,\t出力順位,\t同スコア構造数,\t候補構造数,\tスコア,\t"
795+ + "糖数(ノード数-1),\t予測時間(msec),\t予測時間,\tメモリ使用量,\t分子量,\t構造");
796+ CompositionTools ci = new CompositionTools();
797+ for (double d = args; ; d++) // 指定した分子量からシミュレーションを行う.
798+ {
799+ ci.setMass(d);
800+ ci.setGlycan(new Glycan("[][hex]{}"));
801+ java.util.List<String> ceramide = new ArrayList<String>();
802+ ceramide.add("dc34:1");
803+ ci.setCeramide(ceramide); // セラミド組成は"dc34:1"のみとする.
804+ ci.setMax("pen", 0); // 各糖数の上限まを指定
805+ ci.setMax("dhex", 10);
806+ ci.setMax("dhexme", 0);
807+ ci.setMax("hex", 10);
808+ ci.setMax("hexnac", 10);
809+ ci.setMsTolerance(0.5);
810+ for (Composition cp : ci.getComposition()) // 親マスから組成を予測
811+ {
812+ CandidateTools ct = new CandidateTools();
813+ ct.setGlycan(new Glycan("[][hex]{}"));
814+ ct.setComposition(cp);
815+ for (Glycan gc : ct.getGlycan()) // 組成から検証構造を生成
816+ {
817+ java.util.List<Composition> li = gc.getCompositionFragment() ; // 検証構造のフラグメントを得る.
818+
819+ double[] masses = new double[li.size()]; // 検証構造の全てのフラグメント分子量を格納する.
820+ int i = 0;
821+ for (Composition frags : li) // フラグメント組成のリストから分子量のリストに変換
822+ {
823+ masses[i] = frags.getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
824+ i++;
825+ }
826+
827+ System.out.print(d + "\t"); // Daを表示する.
828+ System.out.print(masses.length + "\t" + li.size() + "\t"); // フラグメント数を表示
829+ runPrediction(masses, gc); // 与えられたフラグメント分子量から構造を予測
830+ }
831+ }
832+ }
833+ }
834+
835+ /**
836+ * 理論値による検証(実験結果出力用メソッド)
837+ * @parm args 検証を始める構造のm/z
838+ * @parm percent 検証構造の何%のフラグメントをランダムに選択するかを指定
839+ */
840+ private static void runSimulation(double args, double percent) throws Exception
841+ {
842+ System.out.println("Da,\t選択flag数,\t理論flag数,\t予測可否,\t予測順位,\t出力順位,\t"
843+ + "同スコア構造数,\t候補構造数,\tスコア,\t糖数(ノード数-1),\t"
844+ + "予測時間(msec),\t予測時間,\tメモリ使用量,\t分子量,\t構造");
845+ CompositionTools ci = new CompositionTools();
846+ for (double d = args; ; d++) // 指定した分子量からシミュレーションを行う.
847+ {
848+ ci.setMass(d);
849+ ci.setGlycan(new Glycan("[][hex]{}"));
850+ java.util.List<String> ceramide = new ArrayList<String>();
851+ ceramide.add("dc34:1");
852+ ci.setCeramide(ceramide); // セラミド組成は"dc34:1"のみとする.
853+ ci.setMax("pen", 0); // 各糖数の上限まを指定
854+ ci.setMax("dhex", 10);
855+ ci.setMax("dhexme", 0);
856+ ci.setMax("hex", 10);
857+ ci.setMax("hexnac", 10);
858+ ci.setMsTolerance(0.5);
859+ for (Composition cp : ci.getComposition()) // 親マスから組成を予測
860+ {
861+ CandidateTools ct = new CandidateTools();
862+ ct.setGlycan(new Glycan("[][hex]{}"));
863+ ct.setComposition(cp);
864+ for (Glycan gc : ct.getGlycan()) // 組成から検証構造を生成
865+ {
866+ java.util.List<Composition> li = gc.getCompositionFragment() ; // 検証構造のフラグメントを得る.
867+
868+ double[] masses = new double[(int)((li.size()-1)*percent/100.0)+1];
869+ // プレカーサーマスは必ず選択する.
870+ masses[0] = li.remove(li.size()-1).getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
871+
872+ int i = 1; // 既にプレカーサーマスを登録しているので,1からスタート
873+ while (i < masses.length) // 分子量を格納する配列が一杯になるまで繰り返す.
874+ { // ランダムにフラグメントを選択
875+ int index = (int)(Math.random() * (li.size()-2));
876+ masses[i] = li.remove(index).getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
877+ i++;
878+ }
879+
880+ for (int j = 1; j < masses.length; j++) // masses[0]がプレカーサーマスであるかどうか
881+ if (masses[j] > masses[0]) // (masses[0]より大きなm/zが存在していないか)
882+ {
883+ throw new Exception("Fragment selection error: " // 念のためチェックする.
884+ + masses[0] + " is not precursor mass.");
885+ }
886+
887+ System.out.print(d + "\t"); // Daを表示
888+ System.out.print(masses.length + "\t" + (li.size()+masses.length) + "\t"); // フラグメント数を表示
889+ runPrediction(masses, gc); // 与えられたフラグメント質量から
890+ } // 構造を予測
891+ }
892+ }
893+ }
894+
895+ /**
896+ * 理論値による検証(実験結果出力用メソッド)
897+ * @parm args 検証を始める構造のm/z
898+ */
899+ private static void runNoiseSimulation(double args) throws Exception
900+ {
901+ System.out.println("条件1,\t条件2,\tDa,\t選択flag数,\t理論flag数,\tノイズflag数,\t予測可否,\t"
902+ + "予測順位,\t出力順位,\t同スコア構造数,\t候補構造数,\tスコア,\t糖数(ノード数-1),\t"
903+ + "予測時間(msec),\t予測時間,\tメモリ使用量,\t分子量,\t構造");
904+
905+ int[] percent = {100, 90, 80, 70, 60, 50, 40, 30, 20, 10}; // 検証構造の何%のフラグメントを選択するかを指定
906+ int[] noise = {2048, 1024, 512, 256, 128, 64, 32, 16, 8}; // 何Daごとに1本のノイズが存在するかを指定
907+
908+ for (double d = args; ; d++) // 指定した分子量からシミュレーションを行う.
909+ for (int m = 0; m < percent.length; m++)
910+ for (int n = 0; n < noise.length; n++)
911+ {
912+ CompositionTools ci = new CompositionTools();
913+ ci.setMass(d);
914+ ci.setGlycan(new Glycan("[][hex]{}"));
915+ java.util.List<String> ceramide = new ArrayList<String>();
916+ ceramide.add("dc34:1");
917+ ci.setCeramide(ceramide); // セラミド組成は"dc34:1"のみとする.
918+ ci.setMax("pen", 0); // 各糖数の上限まを指定
919+ ci.setMax("dhex", 10);
920+ ci.setMax("dhexme", 0);
921+ ci.setMax("hex", 10);
922+ ci.setMax("hexnac", 10);
923+ ci.setMsTolerance(0.5);
924+ for (Composition cp : ci.getComposition()) // 親マスから組成を予測
925+ {
926+ CandidateTools ct = new CandidateTools();
927+ ct.setGlycan(new Glycan("[][hex]{}"));
928+ ct.setComposition(cp);
929+ for (Glycan gc : ct.getGlycan()) // 組成から検証構造を生成
930+ {
931+ java.util.List<Composition> li = gc.getCompositionFragment() ; // 検証構造のフラグメントを得る.
932+ // 検証構造の50%のフラグメント分子量を格納する.
933+ double[] masses = new double[(int)((li.size()-1)*percent[m]/100.0)+1];
934+ // プレカーサーマスは必ず選択する.
935+ masses[0] = li.remove(li.size()-1).getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
936+
937+ int i = 1; // 既にプレカーサーマスを登録しているので,1からスタート
938+ while (i < masses.length) // 分子量を格納する配列が一杯になるまで繰り返す.
939+ { // ランダムにフラグメントを選択
940+ int index = (int)(Math.random() * (li.size()-2));
941+ masses[i] = li.remove(index).getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
942+ i++;
943+ }
944+
945+ // ノイズを挿入
946+ double mass = gc.getMass(MassCalc.MONO_MASS, MassCalc.Na_ION);
947+ int noise_count = (int)(mass / noise[n]); // ノイズ数
948+ double[] noise_masses = new double[masses.length + noise_count]; // ノイズ入りフラグメントを再定義
949+ for (int j = 0; j < masses.length; j++) // ノイズ挿入前フラグメントをコピー
950+ noise_masses[j] = masses[j];
951+ for (int j = masses.length; j < noise_masses.length; j++) // ノイズを追加
952+ noise_masses[j] = Math.random() * mass;
953+
954+ for (int j = 1; j < masses.length; j++) // masses[0]がプレカーサーマスであるかどうか
955+ if (masses[j] > masses[0]) // (masses[0]より大きなm/zが存在していないか)
956+ throw new Exception("Fragment selection error: " // 念のためチェックする.
957+ + masses[0] + " is not precursor mass.");
958+
959+ System.out.print(percent[m] + "\t" + noise[n] + "\t"); // 予測条件を表示する.
960+ System.out.print(d + "\t"); // Daを表示する.
961+ System.out.print(masses.length + "\t" + (li.size()+masses.length) + "\t"); // フラグメント数
962+ System.out.print(noise_count + "\t"); // ノイズフラグメント数
963+ runPrediction(noise_masses, gc); // 与えられたフラグメント分子量から
964+ } // 構造を予測
965+ }
966+ }
967+ }
968+
969+ /**
970+ * 与えられたフラグメントの質量から構造を予測し,その統計情報を出力します.
971+ * @parm masses 予測に用いるフラグメント分子量
972+ * @parm gc 正解構造
973+ */
974+ private static void runPrediction(double[] masses, Glycan gc) throws Exception
975+ {
976+ /**/long start = new Date().getTime(); // 開始時刻
977+
978+ Prediction pd = new Prediction(); // ここから予測
979+ pd.setFragments(masses); // フラグメントの実測値の配列を登録
980+ pd.setMsTolerance(0.5); // 許容誤差を格納
981+ pd.setGlycan(new Glycan("[][hex]{}")); // 既知構造を登録
982+ pd.setCeramide(30,44,0); // セラミド組成は炭素数30-44とする.
983+ pd.setMax("pen", 0); // 各糖数の上限まを指定
984+ pd.setMax("dhex", 10);
985+ pd.setMax("dhexme", 0);
986+ pd.setMax("hex", 10);
987+ pd.setMax("hexnac", 10);
988+ pd.setScoringFormula(Candidate.TFIDF_SCORING);
989+
990+ Iterator<? extends Candidate> it = pd.getPrediction().iterator(); // 結果を表示
991+ boolean success = false; // 予測が成功したか否かを格納する.
992+ boolean flag = true; // while文を抜けるのに用いる.
993+ int rank = 0, count = 0; // 予測順位と候補構造数
994+ int rank2 = 0, same_score = 1;
995+ double score = 0.0, previous_score = 0.0;
996+ while (it.hasNext())
997+ {
998+ Candidate cd = it.next();
999+
1000+ if (flag) // まだ入力構造が現れなかった場合,予測順位の値を更新
1001+ rank++;
1002+
1003+ if (previous_score != cd.getScore() && flag) // 前回のスコアと異なる場合
1004+ {
1005+ rank2++; // ランクが下がる.
1006+ same_score = 1; // 数をクリア
1007+ }
1008+
1009+ // 前のスコアと同じスコアである場合,かつ[まだ入力構造しない場合,または入力構造と同じスコアである場合]
1010+ if (previous_score == cd.getScore() && (flag || score == cd.getScore()))
1011+ same_score++;
1012+
1013+ if (new Glycan(cd.toString()).equals(gc)) // 入力構造が存在した場合
1014+ {
1015+ success = true; // 予測に成功
1016+ score = cd.getScore(); // スコアの値を保存
1017+ flag = false;
1018+ }
1019+
1020+ previous_score = cd.getScore(); // スコアの値を保存
1021+ count++; // 候補構造数
1022+ }
1023+
1024+ /**/long end = new Date().getTime(); // 終了時刻
1025+ /**/long time = end - start; // 処理時間を表示
1026+ Calendar cd = Calendar.getInstance();
1027+ cd.set(Calendar.DAY_OF_YEAR, 1);
1028+ cd.set(Calendar.HOUR_OF_DAY, 0);
1029+ cd.set(Calendar.MINUTE, 0);
1030+ cd.set(Calendar.SECOND, 0);
1031+ cd.set(Calendar.MILLISECOND, (int)(new Date().getTime() - start));
1032+
1033+ MemoryMXBean mm = ManagementFactory.getMemoryMXBean();
1034+ MemoryUsage mu = mm.getHeapMemoryUsage();
1035+
1036+ // 予測可否,予測順位,出力順位,同スコア構造数,候補構造数,スコア
1037+ // 糖数(ノード数-1),予測時間(msec),予測時間,メモリ使用量,分子量,構造
1038+ System.out.println(success
1039+ + "\t" + rank2 + "\t" + rank
1040+ + "\t" + same_score + "\t" + count
1041+ + "\t" + String.format("%.4f", score)
1042+ + "\t" + (gc.size()-1)
1043+ + "\t" + time
1044+ + "\t" + new SimpleDateFormat("HH:mm:ss").format(cd.getTime())
1045+ + "\t" + String.format("%.1f/", mu.getUsed() / 1024.0 / 1024)
1046+ + String.format("%.1fMB", mu.getMax() / 1024.0 / 1024)
1047+ + "\t" + String.format("%.4f", gc.getMass(MassCalc.MONO_MASS, MassCalc.Na_ION))
1048+ + "\t" + gc.toNormalFormat());
1049+ it.hasNext(); // ここの行までに候補構造による使用済みメモリを解放しないために実行
1050+ System.gc(); // ガーベジコレクタによるメモリの解放
1051+ }
1052+
1053+ /**
1054+ * 遊離糖鎖の構造予測
1055+ */
1056+ private static void runFreeGlycanTest() throws Exception
1057+ { // HexNAc-HexNAc-HexNAc-HexNAc-HexNAcの実測フラグメント
1058+ double[] masses = {227.1, 346.3, 429.3, 447.1, 548.5, 631.4, 649.3, 833.8, 851.7, 1054.2};
1059+ Prediction pd = new Prediction(); // ここから予測
1060+ pd.setPrecursorMass(1056.4008);
1061+ pd.setMsTolerance(0.5); // 許容誤差を格納
1062+ pd.setFragments(masses); // フラグメントの実測値の配列を登録
1063+ pd.setPsdTolerance(1.0);
1064+ pd.setGlycan(new Glycan("[][hexnac]{}")); // 既知構造を登録
1065+ pd.setMax("pen", false); // 各糖数の上限まを指定
1066+ pd.setMax("dhex", false);
1067+ pd.setMax("dhexme", false);
1068+ pd.setMax("hex", false);
1069+ pd.setMax("hexnac", true);
1070+ pd.setScoringFormula(Candidate.TFIDF_SCORING);
1071+
1072+ for (Candidate cd : pd.getPrediction())
1073+ System.out.println(cd);
1074+ }
1075+}
1076+
1077+class MultiThreadTool1 implements Callable<Candidate>
1078+{
1079+ Glycan gc; // 並列処理のために保存しておく候補構造
1080+
1081+ public MultiThreadTool1(Glycan gc) throws Exception
1082+ {
1083+ this.gc = gc; // 候補構造を登録
1084+ }
1085+
1086+ public Candidate call() throws Exception
1087+ {
1088+ return new Candidate(gc); // フラグメント化後の分子量の計算済みの候補構造を返す.
1089+ }
1090+}
1091+
1092+class MultiThreadTool2 implements Callable<java.util.List<Glycan>>
1093+{
1094+ Composition cp; // 並列処理のために保存しておく候補組成
1095+ Glycan known_gc;
1096+
1097+ public MultiThreadTool2(Composition cp, Glycan known_gc) throws Exception
1098+ {
1099+ this.cp = cp;
1100+ this.known_gc = known_gc;
1101+ }
1102+
1103+ public java.util.List<Glycan> call() throws Exception
1104+ {
1105+ CandidateTools ct = new CandidateTools(); // 候補構造を生成するためにインスタンスを生成
1106+ ct.setComposition(cp); // 既知構造の登録であるsetGlycan()は処理済み.
1107+ ct.setGlycan(known_gc); // 既知糖鎖構造を登録
1108+
1109+ return ct.getGlycan();
1110+ }
1111+}
--- jp/ac/ritsumei/is/infobio/FragmentationServlet.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/FragmentationServlet.java (revision 1)
@@ -0,0 +1,238 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+import java.io.*;
5+import javax.servlet.*;
6+import javax.servlet.http.*;
7+
8+/**
9+ * フラグメントイオンの組成と理論上の<I>m/z</I> を計算するServletクラスです.
10+ * @author 横井一仁
11+ * @version 20090102
12+ */
13+public class FragmentationServlet extends HttpServlet
14+{
15+ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
16+ {
17+ response.setContentType("text/html");
18+ PrintWriter out = response.getWriter();
19+
20+ try
21+ {
22+ Glycan gc; // 開裂させたい構造
23+ String adduct = ""; // 付加イオン
24+ boolean monoavg = true; // Monoisotopic(ture),Averaget(false)
25+
26+ try
27+ {
28+ gc = new Glycan(request.getParameter("struct")); // 何も指定されない場合,例外
29+ }
30+ catch (Exception e1)
31+ {
32+ try
33+ {
34+ GlycanTools gi = new GlycanTools(); // Linucs形式以外の形式で試してみる.
35+ gc = gi.readNormalFormat(request.getParameter("struct"));
36+ }
37+ catch (Exception e2)
38+ {
39+ GlycanTools gi = new GlycanTools(); // 全てにおいて失敗した場合,L5を表示する.
40+ gc = gi.readNormalFormat("dc34:1-glc-man-glcnac-galnac-galnac");
41+ }
42+ }
43+
44+ try
45+ {
46+ adduct = request.getParameter("adduct");
47+
48+ if (adduct == null) // 何も指定されなかった場合,
49+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
50+ }
51+ catch (Exception e)
52+ {
53+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
54+ }
55+
56+ try
57+ {
58+ String temp = request.getParameter("monoavg");
59+ if (temp.equals("mono"))
60+ monoavg = true;
61+ else if (temp.equals("avg"))
62+ monoavg = false;
63+ else
64+ monoavg = true; // その他の場合Monoisotopicとする.
65+ }
66+ catch (Exception e)
67+ {
68+ monoavg = true; // その他の場合Monoisotopicとする.
69+ }
70+
71+ out.println("<HTML><HEAD><TITLE>Fragmentation</TITLE></HEAD><BODY>"); // 入力部
72+ out.println("<FONT SIZE=+2>Fragmentation</FONT><BR><BR>");
73+ out.println("<FORM>");
74+
75+ try
76+ {
77+ String normal = gc.toNormalFormat(); // ノーマル形式を取得し,
78+ if (normal.length() <= 60) // 入力部のサイズを調節する.
79+ out.println("Structure: <INPUT TYPE=text NAME=struct VALUE='"
80+ + normal + "' SIZE=90><BR>");
81+ else
82+ out.println("Structure: <INPUT TYPE=text NAME=struct VALUE='"
83+ + normal + "' SIZE=" + (normal.length() + 30) + "><BR>");
84+ }
85+ catch (Exception e) // 3分岐以上の場合,Linucs形式で表示
86+ {
87+ String linucs = gc.toString(); // Linucs形式を取得し,
88+ if (linucs.length() <= 60) // 入力部のサイズを調節する.
89+ out.println("Structure: <INPUT TYPE=text NAME=struct VALUE='"
90+ + linucs + "' SIZE=80><BR>");
91+ else
92+ out.println("Structure: <INPUT TYPE=text NAME=struct VALUE='"
93+ + linucs + "' SIZE=" + (linucs.length()+20) + "><BR>");
94+ }
95+
96+ out.println("Adduct ion: <SELECT NAME=adduct>"+adduct); // 前回の内容を初期値とする.
97+ if (adduct.equals(MassCalc.Na_ION))
98+ out.println("<OPTION VALUE="+MassCalc.Na_ION+" SELECTED>Na+");
99+ else
100+ out.println("<OPTION VALUE="+MassCalc.Na_ION+">Na+");
101+ if (adduct.equals(MassCalc.H_ION))
102+ out.println("<OPTION VALUE="+MassCalc.H_ION+" SELECTED>H+");
103+ else
104+ out.println("<OPTION VALUE="+MassCalc.H_ION+">H+");
105+ if (adduct.equals(MassCalc.Li_ION))
106+ out.println("<OPTION VALUE="+MassCalc.Li_ION+" SELECTED>Li+");
107+ else
108+ out.println("<OPTION VALUE="+MassCalc.Li_ION+">Li+");
109+ if (adduct.equals(MassCalc.K_ION))
110+ out.println("<OPTION VALUE="+MassCalc.K_ION+" SELECTED>K+");
111+ else
112+ out.println("<OPTION VALUE="+MassCalc.K_ION+">K+");
113+ if (adduct.equals(MassCalc.H_NION))
114+ out.println("<OPTION VALUE="+MassCalc.H_NION+" SELECTED>H-");
115+ else
116+ out.println("<OPTION VALUE="+MassCalc.H_NION+">H-");
117+ if (adduct.equals(""))
118+ out.println("<OPTION VALUE='' SELECTED>no adduct");
119+ else
120+ out.println("<OPTION VALUE=''>No adduct");
121+ out.println("</SELECT><BR>");
122+ out.println("Mass mode: <SELECT NAME=monoavg>");
123+ if (monoavg)
124+ {
125+ out.println("<OPTION VALUE=mono SELECTED>Monoisotopic");
126+ out.println("<OPTION VALUE=avg>Average");
127+ }
128+ else
129+ {
130+ out.println("<OPTION VALUE=mono>Monoisotopic");
131+ out.println("<OPTION VALUE=avg SELECTED>Average");
132+ }
133+ out.println("</SELECT><BR>");
134+ out.println("<INPUT TYPE=submit>");
135+ out.println("</FORM><BR>");
136+
137+ out.println("<B>Result</B><BR>"); // 表示部
138+ out.println("LINUCS: " + gc + "<BR>");
139+ try
140+ {
141+ out.println("NORMAL: " + gc.toNormalFormat() + "<BR>");
142+ }
143+ catch (Exception e)
144+ {
145+ out.println("NORMAL: " + e + "<BR>"); // 3分岐以上の場合
146+ }
147+
148+ if (adduct.equals(MassCalc.Na_ION))
149+ out.println("Adduct ion: Na+<BR>");
150+ else if (adduct.equals(MassCalc.H_ION))
151+ out.println("Adduct ion: H+<BR>");
152+ else if (adduct.equals(MassCalc.Li_ION))
153+ out.println("Adduct ion: Li+<BR>");
154+ else if (adduct.equals(MassCalc.K_ION))
155+ out.println("Adduct ion: K+<BR>");
156+ else if (adduct.equals(MassCalc.H_NION))
157+ out.println("Adduct ion: H-<BR>");
158+ else if (adduct.equals(""))
159+ out.println("Adduct ion: No adduct<BR>");
160+ else
161+ out.println("Adduct ion: "+adduct+"<BR>");
162+ if (monoavg)
163+ out.println("Mass mode: Monoisotopic<BR><BR>");
164+ else
165+ out.println("Mass mode: Average<BR><BR>");
166+ out.println("<B>Fragment table</B><BR><TABLE border=1><TR>");
167+ out.println("<TH>Composition</TH>");
168+ out.println("<TH><I>m/z</I></TH>");
169+ out.println("</TR>");
170+
171+ Fragmentation fg = new Fragmentation();
172+ Glycan temp = new Glycan(gc.toString()); // Hexへ変換するためにインスタンスを生成
173+ temp.toHexose(); // Glc->Hexへ変換します.
174+ fg.setGlycan(temp);
175+
176+ int dehydrate = 0; // 脱水糖を含んだ組成の数
177+ int oligo = 0; // フリーの糖鎖の組成の数
178+ int ceramide = 0; // セラミドを含んだ組成の数
179+
180+ for (Composition cp : fg.getComposition())
181+ {
182+ if (cp.hasCeramide())
183+ {
184+ out.print("<TR bgcolor=#B0C4DE>"); // セラミドを含んだ組成は,背景色を青にする.
185+ ceramide++;
186+ }
187+ else if (cp.contains("-h2o"))
188+ {
189+ out.print("<TR bgcolor=#DCDCDC>"); // 脱水糖を含んだ組成は,背景色を灰色にする.
190+ dehydrate++;
191+ }
192+ else
193+ {
194+ out.print("<TR bgcolor=#98FB98>"); // フリーの糖鎖の組成は,背景色を緑にする.
195+ oligo++;
196+ }
197+ out.print("<TD>" + cp + "</TD>");
198+ out.print(String.format("<TD align=right>%.4f</TD>", cp.getMass(monoavg, adduct)));
199+ out.println("</TR>");
200+ }
201+ out.println("</TABLE><BR>");
202+
203+ out.println("<B>Number of fragment</B><BR><TABLE border=1><TR>"); // フラグメントの内訳
204+ out.print("<TH bgcolor=#DCDCDC>Dehydrated<BR>oligosaccharide</TH>");
205+ out.print("<TH bgcolor=#98FB98>Oligosaccharide</TH>");
206+ if (ceramide != 0) // 糖脂質の組成数が0の場合は,非表示
207+ out.print("<TH bgcolor=#B0C4DE>Glycosphingolipid</TH>");
208+ out.print("<TH>Total</TH>");
209+ out.println("</TR>");
210+ out.print("<TR>");
211+ out.print("<TD bgcolor=#DCDCDC align=center>" + dehydrate + "</TD>"); // 脱水糖を含む組成は,背景色を灰色
212+ out.print("<TD bgcolor=#98FB98 align=center>" + oligo + "</TD>"); // フリーの糖鎖の組成は,背景色を緑
213+ if (ceramide != 0) // 糖脂質の組成数が0の場合は,非表示
214+ out.print("<TD bgcolor=#B0C4DE align=center>" + ceramide + "</TD>"); // 糖脂質の組成は,背景色を青
215+ out.print("<TD align=center>" + (dehydrate + oligo + ceramide) + "</TD>"); // 合計
216+ out.println("</TR>");
217+ out.println("</TABLE><BR><BR>");
218+ }
219+ catch (Exception e)
220+ {
221+ out.println("ERROR:"+e.getMessage());
222+ }
223+
224+ out.println("<Div Align=right><FONT color=gray>(c) Kazuhito Yokoi</FONT></Div><BR>");
225+ out.println("<A HREF=../>Back</A>"); // トップページへのリンク
226+
227+ out.println("<script type=\"text/javascript\">");
228+ out.println("var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");");
229+ out.println("document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));");
230+ out.println("</script>");
231+ out.println("<script type=\"text/javascript\">");
232+ out.println("try {");
233+ out.println("var pageTracker = _gat._getTracker(\"UA-1643740-14\");");
234+ out.println("pageTracker._trackPageview();");
235+ out.println("} catch(err) {}</script>");
236+ out.println("</BODY></HTML>"); // 終了タグ
237+ }
238+}
--- jp/ac/ritsumei/is/infobio/FragmentationGUI.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/FragmentationGUI.java (revision 1)
@@ -0,0 +1,403 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.io.*;
3+import java.util.*;
4+import java.awt.*;
5+import java.awt.event.*;
6+import java.util.regex.*;
7+import org.jfree.chart.*;
8+import org.jfree.data.xy.*;
9+import org.jfree.chart.plot.*;
10+import org.jfree.ui.*;
11+import org.jfree.chart.entity.*;
12+import javax.swing.*;
13+import javax.swing.table.*;
14+
15+/**
16+ * フラグメントイオンにおける理論上の<I>m/z</I> と実測スペクトルを重ね合わせするクラスです.
17+ * @author 横井一仁
18+ * @version 20090102
19+ */
20+public class FragmentationGUI implements ActionListener, ItemListener, WindowListener
21+{
22+ XYSeries xs; // 実測値のスペクトルを格納
23+ XYSeriesCollection xc;
24+ JFreeChart jc;
25+ JTextField inpit_tf; // 糖鎖構造を格納
26+ JComboBox ion_ch; // 付加イオンを格納
27+ JComboBox ma_ch; // MONO/AVGを格納
28+ JButton theory_bt; // Calculateボタン
29+ JButton actual_bt; // 実測値読み込みボタン(Plot dataボタン)
30+
31+ String[] title = {"m/z", "Composition"}; // 断片化後の組成の出力部
32+ DefaultTableModel tm = new DefaultTableModel(title, 0);
33+ JTable theory_tb = new JTable(tm); // PSD壊裂データを格納
34+
35+ TextArea actual_ta; // 実測値を格納
36+
37+ FragmentationGUI() // フレームの表示
38+ {
39+ byte[] bytes = {40, 99, 41, 32, 75, 97, 122, 117, 104, 105, 116, 111, 32, 89, 111, 107, 111, 105};
40+
41+ JFrame fr = new JFrame("Fragment Matcher");
42+ xc = new XYSeriesCollection(); // グラフ部の設定
43+ jc = ChartFactory.createXYBarChart("", "m/z", false, "Intensity (%)", xc, PlotOrientation.VERTICAL,
44+ false, false, false);
45+ // 糖鎖構造入力部
46+ inpit_tf = new JTextField("dc34:1-Glc-Man-GlcNAc-GalNAc-GalNAc-Gal-GlcNAc", 40);
47+ inpit_tf.addActionListener(this);
48+ JPanel input_pn = new JPanel();
49+ input_pn.setLayout(new FlowLayout());
50+ input_pn.add(new JLabel("Structure:"));
51+ input_pn.add(inpit_tf);
52+
53+ // 付加イオン選択部
54+ ion_ch = new JComboBox(new String[] {"Na+",
55+ "H+",
56+ "Li+",
57+ "K+",
58+ "H-",
59+ "No adduct"});
60+ ion_ch.addItemListener(this);
61+
62+ JPanel ion_pn = new JPanel();
63+ ion_pn.setLayout(new FlowLayout());
64+ ion_pn.add(new JLabel("Adduct ion:"));
65+ ion_pn.add(ion_ch);
66+
67+ // MONO/AVG選択部
68+ ma_ch = new JComboBox(new String[] {"Monoisotopic", "Average"});
69+ ma_ch.addItemListener(this);
70+ JPanel ma_pn = new JPanel();
71+ ma_pn.setLayout(new FlowLayout());
72+ ma_pn.add(new JLabel("Mass mode: "));
73+ ma_pn.add(ma_ch);
74+
75+ // フラグメント計算ボタン
76+ theory_bt = new JButton("Calculate");
77+ theory_bt.addActionListener(this);
78+
79+ // 条件設定部
80+ JPanel condi_pn = new JPanel();
81+ condi_pn.setLayout(new FlowLayout());
82+ condi_pn.add(input_pn);
83+ condi_pn.add(ion_pn);
84+ condi_pn.add(ma_pn);
85+ condi_pn.add(theory_bt);
86+
87+ // 理論ピーク出力部
88+ JPanel theory_pn_north = new JPanel();
89+ theory_pn_north.setLayout(new BorderLayout());
90+ theory_pn_north.add(new JLabel("Calculated fragments:"), BorderLayout.WEST);
91+
92+ JPanel theory_pn = new JPanel();
93+ theory_pn.setLayout(new BorderLayout());
94+ theory_pn.add(theory_pn_north, BorderLayout.NORTH);
95+ resetTableColumnSize(); // テーブルのカラム幅を調節
96+
97+ // 組成に従ってセルに色を付ける.(セラミド付き…青,糖鎖のみ…緑,脱水糖…灰色)
98+ TableColumn tc = theory_tb.getColumnModel().getColumn(0);
99+ tc.setCellRenderer(new DefaultTableCellRenderer()
100+ {
101+
102+ });
103+
104+ JScrollPane theory_sp = new JScrollPane(theory_tb); // JTableへスクロールバーをつける.
105+ theory_sp.addMouseListener(new MouseListener() // 表を右クリックすると印刷する.
106+ {
107+ public void mouseExited(MouseEvent me){}
108+ public void mouseEntered(MouseEvent me){}
109+ public void mousePressed(MouseEvent me){}
110+ public void mouseReleased(MouseEvent me){}
111+ public void mouseClicked(MouseEvent me)
112+ {
113+ if (me.getButton() == MouseEvent.BUTTON3) // 右クリック
114+ {
115+ try
116+ {
117+ theory_tb.print(); // 印刷ダイアログを表示
118+ }
119+ catch (Exception e)
120+ {
121+ System.out.println("Cannot print: " + e);
122+ }
123+ }
124+ }
125+ });
126+ theory_pn.add(theory_sp, BorderLayout.CENTER);
127+
128+
129+ actual_bt = new JButton("Plot data"); // 実測ピーク入力部
130+ actual_bt.addActionListener(this);
131+
132+ try // 実測データの読み込み
133+ {
134+ File fi = new File("L7.dat");
135+ FileReader rd = new FileReader(fi);
136+ BufferedReader br = new BufferedReader(rd);
137+ String line;
138+ StringBuilder sb = new StringBuilder();
139+ while ((line = br.readLine()) != null)
140+ sb.append(line + "\n");
141+ actual_ta = new TextArea(sb.toString());
142+ }
143+ catch (Exception e)
144+ {
145+ System.err.println(e);
146+ actual_ta = new TextArea("Index Centroid Mass Lower Bound Upper Bound Charge (z) Height Relative Intensity Area\n"
147+ + "1 226.086656 214.70 239.20 0 114 10.96 34568.98\n"
148+ + "2 387.921207 386.08 389.29 0 213 20.48 14047.02\n"
149+ + "3 405.818468 404.62 406.39 0 498 47.84 15389.71\n"
150+ + "4 428.798146 427.14 429.52 0 721 69.26 36846.05\n"
151+ + "5 429.659166 429.52 430.33 0 227 21.78 4598.69\n"
152+ + "6 591.182879 589.05 594.66 0 168 16.15 10405.74\n"
153+ + "7 631.871619 629.39 632.56 0 172 16.57 6567.95\n"
154+ + "8 667.634938 645.90 695.00 0 35 3.40 3256.74\n"
155+ + "9 723.822798 697.10 752.20 0 125 12.03 13931.21\n"
156+ + "10 794.294571 791.94 794.56 0 376 36.11 9785.54\n"
157+ + "11 866.510011 852.50 875.70 0 31 2.96 2429.69\n"
158+ + "12 888.507352 866.70 917.90 0 109 10.45 13012.58\n"
159+ + "13 953.956244 926.00 971.00 0 98 9.42 8019.90\n"
160+ + "14 996.455212 993.22 997.08 1 908 87.21 25463.38\n"
161+ + "15 1087.733154 1086.34 1088.26 0 161 15.49 3065.23\n"
162+ + "16 1159.078169 1157.70 1159.41 0 556 53.40 8082.03\n"
163+ + "17 1161.051801 1160.86 1163.34 0 224 21.56 4189.52\n"
164+ + "18 1177.134560 1167.00 1193.70 0 39 3.71 3051.84\n"
165+ + "19 1236.261198 1214.10 1261.10 0 35 3.37 3128.91\n"
166+ + "20 1290.025315 1288.32 1290.50 0 294 28.26 4952.25\n"
167+ + "21 1323.832952 1314.20 1337.40 0 63 6.03 3641.91\n"
168+ + "22 1333.465729 1308.20 1371.40 0 126 12.12 14288.28\n"
169+ + "23 1473.616981 1457.30 1485.90 0 46 4.38 4034.31\n"
170+ + "24 1493.937713 1492.41 1494.44 0 422 40.60 5174.78\n"
171+ + "25 1513.374222 1500.30 1533.00 0 75 7.21 9087.53\n"
172+ + "26 1859.320454 1858.70 1859.85 1 1041 100.00 6482.10\n"
173+ + "27 1877.614229 1870.20 1893.40 0 153 14.70 6686.62");
174+ }
175+
176+ JPanel actual_pn = new JPanel();
177+ actual_pn.setLayout(new BorderLayout());
178+ actual_pn.add(new JLabel("Measured data:"), BorderLayout.WEST);
179+ actual_pn.add(actual_bt, BorderLayout.EAST);
180+ actual_pn.add(actual_ta, BorderLayout.SOUTH);
181+
182+
183+ JPanel south_pn = new JPanel(); // SOUTH部の設定
184+ south_pn.setLayout(new BorderLayout());
185+ south_pn.add(new ChartPanel(jc), BorderLayout.CENTER);
186+ south_pn.add(actual_pn, BorderLayout.SOUTH);
187+
188+ fr.add(condi_pn, BorderLayout.NORTH);
189+ fr.add(theory_pn, BorderLayout.WEST);
190+ fr.add(south_pn, BorderLayout.CENTER);
191+ JLabel author = new JLabel(new String(bytes));
192+ author.setForeground(Color.gray);
193+ fr.add(author, BorderLayout.SOUTH);
194+ fr.addWindowListener(this);
195+ fr.pack();
196+ //jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ウインドウが閉じられた時に終了
197+
198+ try // Swingのデザインから,Windowsのデザインへ変更する(Linuxの場合は例外が発生し,Swing表示となる)
199+ {
200+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); // 外観を設定
201+ SwingUtilities.updateComponentTreeUI(fr); // 外観変更
202+ }
203+ catch (Exception e)
204+ {
205+ System.err.println("Cannot use WindowsLookAndFeel: " + e);
206+ }
207+
208+ int width = fr.getWidth() / 3; // 表のサイズを横幅の1/3のサイズとする.
209+ theory_pn.setPreferredSize(new Dimension(width, width));
210+
211+ fr.setVisible(true);
212+ }
213+
214+ public void actionPerformed(ActionEvent ae)
215+ {
216+ if (ae.getSource() == actual_bt) // "Plot peaks"ボタンがクリックされた時
217+ {
218+ xc.removeAllSeries(); // 前回のXYSeriesを削除
219+ xs = new XYSeries("");
220+
221+ double temp = 0.0;
222+ BufferedReader br = new BufferedReader(new StringReader(actual_ta.getText()));
223+ boolean flag = true; // BarChartかLineChartかを指定する.(trueがBarChart)
224+ try
225+ {
226+ String str;
227+ while ((str = br.readLine()) != null)
228+ {
229+ Pattern pt1 = Pattern.compile("^(\\d+)[\\t|\\s]+(\\d+\\.\\d+)[\\t|\\s]+"
230+ + "(\\d+\\.\\d+)[\\t|\\s]+(\\d+\\.\\d+)[\\t|\\s]+"
231+ + "(\\d+)[\\t|\\s]+(\\d+)[\\t|\\s]+"
232+ + "(\\d+\\.\\d+)[\\t|\\s]+(\\d+\\.\\d+).*");
233+ Matcher mt1 = pt1.matcher(str);
234+
235+ if (mt1.matches()) // 先頭の条件を読み飛ばし,
236+ { // 数字,'.',タブで構成されている行を読み込む.
237+ xs.add(Double.parseDouble(mt1.group(2)), Double.parseDouble(mt1.group(7)));
238+ flag = true; // BarChartで表示
239+ }
240+
241+ Pattern pt2 = Pattern.compile("^(\\d+\\.\\d+)[\\t|\\s]+(\\d+\\.\\d+).*");
242+ Matcher mt2 = pt2.matcher(str);
243+
244+ if (mt2.matches()) // 先頭の条件を読み飛ばし,
245+ { // 数字,'.',タブで構成されている行を読み込む.
246+ xs.add(Double.parseDouble(mt2.group(1)), Double.parseDouble(mt2.group(2)));
247+ flag = false; // LineChartで表示
248+ }
249+ }
250+ }
251+ catch (Exception e)
252+ {
253+ System.err.println("markPeaks error1 : " + e);
254+ e.printStackTrace();
255+ }
256+
257+ actual_bt.setText("Plot data"); // ボタンを元に戻す
258+ xc.addSeries(xs);
259+ }
260+
261+ // "Mark peaks"ボタンがクリックされた時
262+ if (ae.getSource() == theory_bt || ae.getSource() == inpit_tf)
263+ try
264+ {
265+ markPeaks();
266+ }
267+ catch (Exception e)
268+ {
269+ System.err.println("markPeaks error2 : " + e);
270+ e.printStackTrace();
271+ }
272+ }
273+
274+ public void itemStateChanged(ItemEvent ie)
275+ {
276+ if (ie.getSource() == ion_ch || ie.getSource() == ma_ch)
277+ try
278+ {
279+ markPeaks();
280+ }
281+ catch (Exception e)
282+ {
283+ System.err.println("markPeaks error3 : " + e);
284+ e.printStackTrace();
285+ }
286+ }
287+
288+ void markPeaks() throws Exception
289+ {
290+ XYPlot xp = jc.getXYPlot();
291+ xp.clearDomainMarkers(); // 既に表示されているマーカーを削除
292+
293+ DefaultTableModel tm = (DefaultTableModel)theory_tb.getModel(); // テーブルモデルを取得し,
294+ tm.setRowCount(0); // 表の内容を削除する.
295+
296+ String adduct;
297+ if (ion_ch.getSelectedItem().equals("Na+"))
298+ adduct = MassCalc.Na_ION;
299+ else if (ion_ch.getSelectedItem().equals("H+"))
300+ adduct = MassCalc.H_ION;
301+ else if (ion_ch.getSelectedItem().equals("Li+"))
302+ adduct = MassCalc.Li_ION;
303+ else if (ion_ch.getSelectedItem().equals("K+"))
304+ adduct = MassCalc.K_ION;
305+ else if (ion_ch.getSelectedItem().equals("H-"))
306+ adduct = MassCalc.H_NION;
307+ else if (ion_ch.getSelectedItem().equals("No adduct"))
308+ adduct = "";
309+ else
310+ adduct = "";
311+
312+ boolean monoavg;
313+ if (ma_ch.getSelectedItem().equals("Monoisotopic"))
314+ monoavg = true;
315+ else
316+ monoavg = false;
317+
318+ Glycan gc = null;
319+ try
320+ {
321+ gc = new Glycan(inpit_tf.getText());
322+ }
323+ catch (Exception e1)
324+ {
325+ try
326+ {
327+ GlycanTools gi = new GlycanTools();
328+ gc = gi.readNormalFormat(inpit_tf.getText());
329+ }
330+ catch (Exception e2)
331+ {
332+ System.err.println("Input format error: " + e1 + e2);
333+ }
334+ }
335+
336+ try // 入力した糖鎖構造文字列を正しく修正する.(hex,hexnacなどをHex,HexNAcに修正)
337+ {
338+ inpit_tf.setText(gc.toNormalFormat()); // Linucs形式でない表示方法が可能であるかを試してみる.
339+ }
340+ catch (Exception e)
341+ {
342+ inpit_tf.setText(gc.toString()); // 失敗した場合は,Linucs形式を用いて表示する.
343+ }
344+
345+ gc.toHexose(); // Glc->Hexへ変換します.
346+ Fragmentation fg = new Fragmentation();
347+ fg.setGlycan(gc);
348+ for (Composition cp : fg.getComposition())
349+ {
350+ System.out.println(cp);
351+ String[] table = new String[2]; // カラムの追加時は,配列の大きさに注意する.
352+ table[0] = String.format("%.4f", cp.getMass(monoavg, adduct));
353+ table[1] = cp.toString();
354+ tm.addRow(table); // テーブルに追加
355+
356+ ValueMarker mk1 = new ValueMarker(cp.getMass(monoavg, adduct) - 1);
357+ ValueMarker mk2 = new ValueMarker(cp.getMass(monoavg, adduct) + 1);
358+ if (cp.hasCeramide())
359+ {
360+ mk1.setPaint(Color.blue);
361+ mk2.setPaint(Color.blue);
362+ }
363+ else if(!cp.contains("-h2o"))
364+ {
365+ mk1.setPaint(Color.green);
366+ mk2.setPaint(Color.green);
367+ }
368+ xp.addDomainMarker(mk1); // マーカーを追加
369+ xp.addDomainMarker(mk2);
370+ }
371+
372+ resetTableColumnSize(); // テーブルのカラム幅を調節
373+ }
374+
375+ /*
376+ * テーブルのカラム幅を調節します.
377+ */
378+ private void resetTableColumnSize()
379+ {
380+ DefaultTableCellRenderer tr = new DefaultTableCellRenderer(); // テーブルのカラム幅を調整する
381+ tr.setHorizontalAlignment(SwingConstants.RIGHT);
382+ TableColumn tc0 = theory_tb.getColumnModel().getColumn(0); // m/zのカラム(0番目)のサイズを固定
383+ tc0.setMinWidth(70);
384+ tc0.setMaxWidth(70);
385+ tc0.setCellRenderer(tr); // カラムを右寄せする
386+ }
387+
388+ public void windowOpened(WindowEvent evt){}
389+ public void windowClosing(WindowEvent evt)
390+ {
391+ System.exit(0);
392+ }
393+ public void windowClosed(WindowEvent evt){}
394+ public void windowIconified(WindowEvent evt){}
395+ public void windowDeiconified(WindowEvent evt){}
396+ public void windowActivated(WindowEvent evt){}
397+ public void windowDeactivated(WindowEvent evt) {}
398+
399+ public static void main(String[] args)
400+ {
401+ new FragmentationGUI();
402+ }
403+}
--- jp/ac/ritsumei/is/infobio/FragmentComparing.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/FragmentComparing.java (revision 1)
@@ -0,0 +1,346 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+import java.io.*;
5+import javax.servlet.*;
6+import javax.servlet.http.*;
7+
8+/**
9+ * 2つの糖鎖構造を比較し,特徴的なフラグメントイオンを探し出すServletクラスです.
10+ * @author 横井一仁
11+ * @version 20090102
12+ */
13+public class FragmentComparing extends HttpServlet
14+{
15+ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
16+ {
17+ response.setContentType("text/html");
18+ PrintWriter out = response.getWriter();
19+
20+ try
21+ {
22+ Glycan gc1; // 開裂させたい構造
23+ Glycan gc2; // 開裂させたい構造
24+ String adduct = ""; // 付加イオン
25+ boolean monoavg = true; // Monoisotopic(ture), Average(false)
26+
27+ try
28+ {
29+ gc1 = new Glycan(request.getParameter("struct1")); // 何も指定されない場合,例外
30+ }
31+ catch (Exception e1)
32+ {
33+ try
34+ {
35+ GlycanTools gi = new GlycanTools(); // Linucs形式以外の形式で試してみる.
36+ gc1 = gi.readNormalFormat(request.getParameter("struct1"));
37+ }
38+ catch (Exception e2)
39+ {
40+ GlycanTools gi = new GlycanTools(); // 全てにおいて失敗した場合,L5を表示する.
41+ gc1 = gi.readNormalFormat("dc36:1-hex3me-hex3me-hexnac3me-hexnac3me-hexnac4me");
42+ }
43+ }
44+
45+ try
46+ {
47+ gc2 = new Glycan(request.getParameter("struct2")); // 何も指定されない場合,例外
48+ }
49+ catch (Exception e1)
50+ {
51+ try
52+ {
53+ GlycanTools gi = new GlycanTools(); // Linucs形式以外の形式で試してみる.
54+ gc2 = gi.readNormalFormat(request.getParameter("struct2"));
55+ }
56+ catch (Exception e2)
57+ { // 全てにおいて失敗した場合,
58+ GlycanTools gi = new GlycanTools(); // L5と同じフラグメントを持つ構造を表示する.
59+ gc2 = gi.readNormalFormat("dc36:1-hex3me-hex3me-hexnac2me(-hexnac4me)-hexnac4me");
60+ }
61+ }
62+
63+ try
64+ {
65+ adduct = request.getParameter("adduct");
66+
67+ if (adduct == null) // 何も指定されなかった場合,
68+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
69+ }
70+ catch (Exception e)
71+ {
72+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
73+ }
74+
75+ try
76+ {
77+ String temp = request.getParameter("monoavg");
78+ if (temp.equals("mono"))
79+ monoavg = true;
80+ else if (temp.equals("avg"))
81+ monoavg = false;
82+ else
83+ monoavg = true; // その他の場合Monoisotopicとする.
84+ }
85+ catch (Exception e)
86+ {
87+ monoavg = true; // その他の場合Monoisotopicとする.
88+ }
89+
90+ out.println("<HTML><HEAD><TITLE>Fragment Comparing</TITLE></HEAD><BODY>"); // 入力部
91+ out.println("<FONT SIZE=+2>Fragment Comparing</FONT><BR><BR>");
92+ out.println("<FORM><BR>");
93+
94+ try
95+ {
96+ String normal = gc1.toNormalFormat(); // ノーマル形式を取得し,
97+ if (normal.length() <= 60) // 入力部のサイズを調節する.
98+ out.println("Structure1: <INPUT TYPE=text NAME=struct1 VALUE='"
99+ + normal + "' SIZE=100><BR>");
100+ else
101+ out.println("Structure1: <INPUT TYPE=text NAME=struct1 VALUE='"
102+ + normal + "' SIZE=" + (normal.length() + 40) + "><BR>");
103+ }
104+ catch (Exception e) // 3分岐以上の場合,Linucs形式で表示
105+ {
106+ String linucs = gc1.toString(); // Linucs形式を取得し,
107+ if (linucs.length() <= 60) // 入力部のサイズを調節する.
108+ out.println("Structure1: <INPUT TYPE=text NAME=struct1 VALUE='"
109+ + linucs + "' SIZE=100><BR>");
110+ else
111+ out.println("Structure1: <INPUT TYPE=text NAME=struct1 VALUE='"
112+ + linucs + "' SIZE=" + (linucs.length() + 40) + "><BR>");
113+ }
114+
115+ try
116+ {
117+ String normal = gc2.toNormalFormat(); // ノーマル形式を取得し,
118+ if (normal.length() <= 60) // 入力部のサイズを調節する.
119+ out.println("Structure2: <INPUT TYPE=text NAME=struct2 VALUE='"
120+ + normal + "' SIZE=100><BR>");
121+ else
122+ out.println("Structure2: <INPUT TYPE=text NAME=struct2 VALUE='"
123+ + normal + "' SIZE=" + (normal.length() + 40) + "><BR>");
124+ }
125+ catch (Exception e) // 3分岐以上の場合,Linucs形式で表示
126+ {
127+ String linucs = gc2.toString(); // Linucs形式を取得し,
128+ if (linucs.length() <= 60) // 入力部のサイズを調節する.
129+ out.println("Structure2: <INPUT TYPE=text NAME=struct2 VALUE='"
130+ + linucs + "' SIZE=100><BR>");
131+ else
132+ out.println("Structure2: <INPUT TYPE=text NAME=struct2 VALUE='"
133+ + linucs + "' SIZE=" + (linucs.length() + 40) + "><BR>");
134+ }
135+
136+ out.println("Adduct ion: <SELECT NAME=adduct>"+adduct); // 前回の内容を初期値とする.
137+ if (adduct.equals(MassCalc.Na_ION))
138+ out.println("<OPTION VALUE="+MassCalc.Na_ION+" SELECTED>Na+");
139+ else
140+ out.println("<OPTION VALUE="+MassCalc.Na_ION+">Na+");
141+ if (adduct.equals(MassCalc.H_ION))
142+ out.println("<OPTION VALUE="+MassCalc.H_ION+" SELECTED>H+");
143+ else
144+ out.println("<OPTION VALUE="+MassCalc.H_ION+">H+");
145+ if (adduct.equals(MassCalc.Li_ION))
146+ out.println("<OPTION VALUE="+MassCalc.Li_ION+" SELECTED>Li+");
147+ else
148+ out.println("<OPTION VALUE="+MassCalc.Li_ION+">Li+");
149+ if (adduct.equals(MassCalc.K_ION))
150+ out.println("<OPTION VALUE="+MassCalc.K_ION+" SELECTED>K+");
151+ else
152+ out.println("<OPTION VALUE="+MassCalc.K_ION+">K+");
153+ if (adduct.equals(MassCalc.H_NION))
154+ out.println("<OPTION VALUE="+MassCalc.H_NION+" SELECTED>H-");
155+ else
156+ out.println("<OPTION VALUE="+MassCalc.H_NION+">H-");
157+ if (adduct.equals(""))
158+ out.println("<OPTION VALUE='' SELECTED>No adduct");
159+ else
160+ out.println("<OPTION VALUE=''>No adduct");
161+ out.println("</SELECT><BR>");
162+ out.println("Mass mode: <SELECT NAME=monoavg>");
163+ if (monoavg)
164+ {
165+ out.println("<OPTION VALUE=mono SELECTED>Monoisotopic");
166+ out.println("<OPTION VALUE=avg>Average");
167+ }
168+ else
169+ {
170+ out.println("<OPTION VALUE=mono>Monoisotopic");
171+ out.println("<OPTION VALUE=avg SELECTED>Average");
172+ }
173+ out.println("</SELECT><BR>");
174+ out.println("<INPUT TYPE=submit>");
175+ out.println("</FORM><BR>");
176+
177+ out.println("<B>Result</B><BR>"); // 表示部
178+ try
179+ {
180+ out.println("Structure1: " + gc1.toNormalFormat() + "<BR>");
181+ }
182+ catch (Exception e)
183+ {
184+ out.println("Structure1: " + e + "<BR>"); // 3分岐以上の場合
185+ }
186+ try
187+ {
188+ out.println("Structure2: " + gc2.toNormalFormat() + "<BR>");
189+ }
190+ catch (Exception e)
191+ {
192+ out.println("Structure2: " + e + "<BR>"); // 3分岐以上の場合
193+ }
194+
195+ if (adduct.equals(MassCalc.Na_ION))
196+ out.println("Adduct ion: Na+<BR>");
197+ else if (adduct.equals(MassCalc.H_ION))
198+ out.println("Adduct ion: H+<BR>");
199+ else if (adduct.equals(MassCalc.Li_ION))
200+ out.println("Adduct ion: Li+<BR>");
201+ else if (adduct.equals(MassCalc.K_ION))
202+ out.println("Adduct ion: K+<BR>");
203+ else if (adduct.equals(MassCalc.H_NION))
204+ out.println("Adduct ion: H-<BR>");
205+ else if (adduct.equals(""))
206+ out.println("Adduct ion: No adduct<BR>");
207+ else
208+ out.println("Adduct ion: "+adduct+"<BR>");
209+ if (monoavg)
210+ out.println("Mass mode: Monoisotopic<BR><BR>");
211+ else
212+ out.println("Mass mode: Average<BR><BR>");
213+ out.println("<B>Fragment table</B><BR><TABLE border=1><TR>");
214+ out.println("<TH>Fragment composition<BR>(Structure1)</TH>");
215+ out.println("<TH><I>m/z</I></TH>");
216+ out.println("<TH>Fragment composition<BR>(Structure2)</TH>");
217+ out.println("<TH><I>m/z</I></TH>");
218+ out.println("</TR>");
219+
220+ Fragmentation fg1 = new Fragmentation();
221+ Glycan temp1 = new Glycan(gc1.toString()); // Hexへ変換するためにインスタンスを生成
222+ temp1.toHexose(); // Glc->Hexへ変換します.
223+ fg1.setGlycan(temp1);
224+ List<Composition> cps1 = fg1.getComposition();
225+
226+ Fragmentation fg2 = new Fragmentation();
227+ Glycan temp2 = new Glycan(gc2.toString()); // Hexへ変換するためにインスタンスを生成
228+ temp2.toHexose(); // Glc->Hexへ変換します.
229+ fg2.setGlycan(temp2);
230+ List<Composition> cps2 = fg2.getComposition();
231+
232+ Set<Double> temp_st = new HashSet<Double>(); // 2つの構造のフラグメントの質量を重複を除いて足し合わせる.
233+ for (Composition cp : cps1)
234+ temp_st.add(cp.getMass(monoavg, adduct));
235+ for (Composition cp : cps2)
236+ temp_st.add(cp.getMass(monoavg, adduct));
237+ List<Double> temp_li = new ArrayList<Double>(temp_st); // ソートのため,リストに変換
238+
239+ Collections.sort(temp_li, new Comparator<Double>() // ソートを行う.
240+ {
241+ public int compare(Double db1, Double db2)
242+ {
243+ double sub = db1 - db2;
244+ // compareメソッドの返り値がint型しか受け付けないので1024倍して精度を上げる.
245+ return (int)(sub*1024);
246+ }
247+ });
248+
249+ for (Double db : temp_li)
250+ {
251+ List<Composition> output1 = new ArrayList<Composition>(); // 同じ質量の組成を格納する.
252+ List<Composition> output2 = new ArrayList<Composition>();
253+
254+ for (Composition cp : cps1) // 質量が一致した組成をリストに格納する.
255+ if (cp.getMass(monoavg, adduct) == db)
256+ output1.add(cp);
257+
258+ for (Composition cp : cps2) // 質量が一致した組成をリストに格納する.
259+ if (cp.getMass(monoavg, adduct) == db)
260+ output2.add(cp);
261+
262+ if (!output1.isEmpty())
263+ {
264+ if (!output2.isEmpty()) // 両方の構造が持つフラグメントであった場合
265+ {
266+ out.print("<TR>");
267+ out.print("<TD>"); // セルの開始
268+ Iterator<Composition> it1 = output1.iterator();
269+ while (it1.hasNext())
270+ {
271+ out.print(it1.next());
272+ if (it1.hasNext()) // 組成を複数持っている場合はセル内で改行
273+ out.print("<BR>");
274+ }
275+ out.print("</TD>"); // セルの終わり
276+ out.print(String.format("<TD align=right>%.4f</TD>", db));
277+ out.print("<TD>"); // セルの開始
278+ Iterator<Composition> it2 = output2.iterator();
279+ while (it2.hasNext())
280+ {
281+ out.print(it2.next());
282+ if (it2.hasNext()) // 組成を複数持っている場合はセル内で改行
283+ out.print("<BR>");
284+ }
285+ out.print("</TD>"); // セルの終わり
286+ out.print(String.format("<TD align=right>%.4f</TD>", db));
287+ out.println("</TR>");
288+ }
289+ else // cp1のみが持つフラグメントであった場合
290+ {
291+ out.print("<TR>");
292+ out.print("<TD bgcolor=#FF99FF>"); // セルの開始
293+ Iterator<Composition> it1 = output1.iterator();
294+ while (it1.hasNext())
295+ {
296+ out.print(it1.next());
297+ if (it1.hasNext()) // 組成を複数持っている場合はセル内で改行
298+ out.print("<BR>");
299+ }
300+ out.print("</TD>"); // セルの終わり
301+ out.print(String.format("<TD bgcolor=#FF99FF align=right>%.4f</TD>", db));
302+ out.print("<TD></TD><TD></TD>");
303+ out.println("</TR>");
304+ }
305+ }
306+ else if (!output2.isEmpty()) // cp2のみが持つフラグメントであった場合
307+ {
308+ out.print("<TR>");
309+ out.print("<TD></TD><TD></TD>");
310+ out.print("<TD bgcolor=#99FFFF>"); // セルの開始
311+ Iterator<Composition> it2 = output2.iterator();
312+ while (it2.hasNext())
313+ {
314+ out.print(it2.next());
315+ if (it2.hasNext()) // 組成を複数持っている場合はセル内で改行
316+ out.print("<BR>");
317+ }
318+ out.print("</TD>"); // セルの終わり
319+ out.print(String.format("<TD bgcolor=#99FFFF align=right>%.4f</TD>", db));
320+ out.println("</TR>");
321+ }
322+ else
323+ throw new Exception("else if error!");
324+ }
325+ }
326+ catch (Exception e)
327+ {
328+ out.println("ERROR:"+e.getMessage());
329+ }
330+ out.println("</TABLE><BR>");
331+
332+ out.println("<Div Align=right><FONT color=gray>(c) Kazuhito Yokoi</FONT></Div><BR>");
333+ out.println("<A HREF=../>Back</A>"); // トップページへのリンク
334+
335+ out.println("<script type=\"text/javascript\">");
336+ out.println("var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");");
337+ out.println("document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));");
338+ out.println("</script>");
339+ out.println("<script type=\"text/javascript\">");
340+ out.println("try {");
341+ out.println("var pageTracker = _gat._getTracker(\"UA-1643740-14\");");
342+ out.println("pageTracker._trackPageview();");
343+ out.println("} catch(err) {}</script>");
344+ out.println("</BODY></HTML>"); // 終了タグ
345+ }
346+}
--- jp/ac/ritsumei/is/infobio/Composition.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/Composition.java (revision 1)
@@ -0,0 +1,605 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+
5+/**
6+ * 糖鎖の組成を扱うクラスです.
7+ * @author 横井一仁
8+ * @version 20081218
9+ */
10+public class Composition extends ArrayList<String>
11+{
12+ /**
13+ * 要素がないクラスを作ります.
14+ */
15+ public Composition() throws Exception
16+ {
17+ super();
18+ }
19+
20+ /**
21+ * Compositionクラスから新しいCompositionインスタンスを作成します.
22+ * @param cp 新しく作成するCompositionクラス
23+ */
24+ public Composition(Composition cp) throws Exception
25+ {
26+ super(cp);
27+ }
28+
29+ /**
30+ * 文字列からCompositionインスタンスを作成します.
31+ * @param str "Hex, dHex, th38:0"と組成を列挙した文字列
32+ */
33+ public Composition(String str) throws Exception
34+ {
35+ str = str.toLowerCase(); // 全て小文字に変換
36+ String[] strs = str.split("[^\\w:\\-*]"); // 単語構成文字と':','-','*'以外の文字列で分割
37+
38+ for (int i = 0; i < strs.length; i++) // cd->dc, hd->dh, ct->tc, ht->thへ入力ミスを訂正
39+ {
40+ Pattern pt = Pattern.compile("^([ch])([dt])([0-9]+:[0-9])$"); // 長鎖塩基と脂肪酸の順番が逆
41+ Matcher mt = pt.matcher(strs[i]);
42+
43+ if (mt.matches()) // セラミド組成の入力にミスが存在した場合,
44+ strs[i] = mt.group(2) + mt.group(1) + mt.group(3); // "([dt])"+"([ch])"+"([0-9]+:[0-9])"とする.
45+ }
46+
47+ for (int i = 0; i < strs.length; i++)
48+ if (!strs[i].equals("")) // 文字列が格納されていない場合は除く.
49+ if (strs[i].matches("[\\w:\\-]+\\*\\d+")) // 掛け算が存在する場合
50+ {
51+ String[] temps = strs[i].split("\\*");
52+ for (int j = 0; j < Integer.parseInt(temps[1]); j++)
53+ this.add(temps[0]); // 個数分の組成を格納する.
54+ }
55+ else
56+ this.add(strs[i]); // 掛け算が存在する場合,そのまま格納する.
57+ }
58+
59+ /**
60+ * Glycanクラスから新しいCompositionインスタンスを作成します.
61+ * @param gc Glycanクラス
62+ */
63+ public Composition(Glycan gc) throws Exception
64+ {
65+ search(gc); // 深さ優先探索を行い,組成をListへ追加
66+ }
67+
68+ /**
69+ * 糖鎖の組成を追加します.
70+ * @param gc 追加するGlycanクラス
71+ */
72+ public void add(Glycan gc) throws Exception
73+ {
74+ search(gc); // 深さ優先探索を行い,組成をListへ追加
75+ }
76+
77+ /**
78+ * Glycanクラスに対し、深さ優先探索を行い組成を求めます.
79+ * @param root Treeクラスのルート
80+ * @param pointer Treeクラスのポインタ
81+ */
82+ private void search(Glycan pointer)
83+ {
84+ super.add(pointer.getNode()); // 組成をListへ追加
85+
86+ for (Glycan gc : pointer.getChildren()) // 子ノードがあるならば,さらに探索を行う.
87+ search(gc);
88+ }
89+
90+ /**
91+ * 理論上の<I>m/z</I> を返します.
92+ * @param monoisotopic モノアイソトピックかアベレージかをMassCalc.MONO_MASSで指定
93+ * @param adduct 付加イオンをMassCalc.Na_IONで指定
94+ * @return 理論上の<I>m/z</I>
95+ */
96+ public double getMass(boolean monoisotopic, String adduct) throws Exception
97+ {
98+ MassCalc mc = new MassCalc(monoisotopic, adduct);
99+ return mc.getMass(this);
100+ }
101+
102+ /**
103+ * セラミドを含んでいるかを返します.
104+ * @return セラミドを含んでいるか
105+ */
106+ public boolean hasCeramide() throws Exception
107+ {
108+ for (String str : this)
109+ if (str.matches("^([dt])([ch][0-9]+:[0-9])$")) // セラミドが存在した場合
110+ return true;
111+
112+ return false; // セラミドが存在しなかった場合
113+ }
114+
115+ /**
116+ * 組成の中からセラミドを取得します.
117+ * @return セラミド
118+ */
119+ public String getCeramide() throws Exception
120+ {
121+ Iterator<String> it = this.iterator();
122+ int count = 0; // 組成の中にセラミドが1個または0個であるかを確認する.
123+ String ceramide = null;
124+ for (String temp : this)
125+ if (temp.matches("^([dt])([Cch][0-9]+:[0-9])$")) // セラミドが存在した場合,
126+ {
127+ ceramide = temp;
128+ count++;
129+ }
130+
131+ if (count == 1) // 1個の時
132+ return ceramide;
133+ else // セラミドの個数が1個でない時
134+ throw new Exception("Exception at Composition.getCeramide()");
135+ }
136+
137+ /**
138+ * ヒドロキシル基の数を返します.
139+ * @return ヒドロキシル基の数
140+ */
141+ public int countHydroxy() throws Exception
142+ {
143+ Pattern pt1 = Pattern.compile("^(pen|xyl|ara|dhex|fuc|rha|hex|glc|gal|man|hexnac|glcnac|galnac|glca|hexa|neuac|kdn|neugc)([0-9]*)(me)*$"); // アセチル基には未対応
144+ Pattern pt2 = Pattern.compile("^([dt])([ch])([0-9]+):([0-9])$");
145+ int count = 0; // ヒドロキシル基の数
146+ int bound = 0; // グリコシド結合の数
147+
148+ for (String str : this)
149+ {
150+ Matcher mt1 = pt1.matcher(str);
151+ Matcher mt2 = pt2.matcher(str);
152+
153+ if (mt1.matches()) // 糖のメチル化
154+ {
155+ if (mt1.group(1).matches("^(pen|xyl|ara|dhex|fuc|rha)$")) // デオキシヘキソースとペントースの場合,
156+ count += 3; // 修飾基の付加できる部分は最大3ヶ所
157+ else if (mt1.group(1).matches("^(hex|glc|gal|man|hexnac|glcnac|galnac|glca|hexa)$")) // 他の糖の場合,
158+ count += 4; // 最大4ヶ所
159+ else if (mt1.group(1).matches("^(neuac|kdn)$")) // NeuAc,KDNは,6個のメチル基が入る.
160+ count += 6;
161+ else if (mt1.group(1).equals("neugc")) // NeuGcは,NeuAcからさらにOH基が1つ多いため,
162+ count += 7; // 7個のメチル基が入る.
163+
164+ int reduce = 0; // 現在の修飾基が付加できる数から,減らさなくてはならない数
165+ if (mt1.group(2).matches("^\\d$") && mt1.group(3).matches("^(me|ac)$")) // 修飾基の数を指定した場合,
166+ reduce = Integer.parseInt(mt1.group(2)); // 指定された数を読み込む.
167+ else if (mt1.group(3) != null && mt1.group(3).equals("me")) // 数が指定されていない場合は,
168+ reduce = 1; // 1つ減らす.
169+ count -= reduce; // 最後に指定された数を減らす.
170+
171+ bound++; // グリコシド結合の数を1つ加算する.
172+ }
173+ else if (mt2.matches()) // セラミドのメチル化(長鎖塩基のNにもメチル基が入る)
174+ {
175+ if (mt2.group(1).equals("d")) // ジヒドロキシスフィンゴシンの場合,
176+ count += 3; // メチル基が2つ増加(=炭素数が2つ増加)
177+ else if (mt2.group(1).equals("t")) // トリヒドロキシスフィンゴシンの場合,
178+ count += 4; // メチル基が3つ増加(=炭素数が3つ増加)
179+
180+ if (mt2.group(2).equals("h")) // ヒドロキシ脂肪酸の場合,
181+ count++; // メチル基が1つ増加(=炭素数が1つ増加)
182+
183+ bound++; // グリコシド結合の数を1つ加算する.
184+ }
185+ else if (str.matches("^(me|ac)$")) // 修飾基の場合,
186+ {
187+ count += 0; // メチル基が入らない.
188+ bound++; // グリコシド結合の数を1つ加算する.
189+ }
190+ else if (str.matches("^(-h|h|na|li|k|h2o|-h2o)$")) // 付加イオンの場合,
191+ {
192+ count += 0; // メチル基が入らない.
193+ }
194+ else // 全ての条件と一致しなかった場合
195+ throw new Exception("Unknown Composition in countHydroxy(): " + str);
196+ }
197+
198+ if (bound != 0) // 糖鎖が存在する場合
199+ count = count - bound + 1; // 結合に使うOH基を削除
200+
201+ if (!this.hasCeramide() && bound != 0) // 糖鎖が存在しており,セラミドが存在しない場合,
202+ count++; // 還元末端側のOH基をカウントする.
203+
204+ return count;
205+ }
206+
207+ /**
208+ * 候補と数を文字列型として返します.
209+ * @return 候補と数の文字列
210+ */
211+ public String toString()
212+ {
213+ StringBuilder str = new StringBuilder(); // リターンする文字列
214+
215+ try
216+ {
217+ List<String> li = new ArrayList<String>(new HashSet<String>(this)); // 要素の重複を削除し,ArrayListへ変換
218+
219+ Collections.sort(li, new Comparator<String>() // セラミド,長鎖塩基または脂肪酸,糖,その他の順にソート
220+ {
221+ public int compare(String str1, String str2)
222+ {
223+ return getSortScore(str1) - getSortScore(str2); // 各単糖の並び順のスコアを用いる.
224+ }
225+ });
226+
227+ Iterator<String> it = li.iterator();
228+ while (it.hasNext())
229+ {
230+ String comp = it.next(); // 組成を取得
231+ int count = Collections.frequency(this, comp); // 要素を探索し,個数を数える.
232+
233+ comp = Composition.toFixSignage(comp); // 正しい表記に変換
234+
235+ if (count == 1)
236+ str.append(comp); // 要素が1つならばそのまま出力
237+ else
238+ str.append(comp + "*" + count); // 要素が1つ以上ならば,個数を付加して出力
239+
240+ if (it.hasNext())
241+ str.append(", "); // 次の要素を持っていたら", "を追加する.
242+ }
243+ }
244+ catch (Exception e)
245+ {
246+ System.out.println("Exception at Composition.toString()");
247+ }
248+
249+ return str.toString();
250+ }
251+
252+ /**
253+ * toString()メソッドに用いる各単糖の並び順のスコアを返します.
254+ * @parm str 文字列型の単糖
255+ */
256+ private int getSortScore(String str)
257+ {
258+ int score; // リターンするスコア
259+
260+ // 大まかに10ずつ単糖を区別し,詳細に区別する場合は1ずつ区別する.
261+ if (str.matches("^[dt][ch][0-9]+:[0-9]$") || str.matches("^.+pa$") || str.matches("^.+ab$") )
262+ score = 0; // セラミドまたはPA糖の場合
263+ else if (str.matches("^[dt][0-9]+:[0-9]$"))
264+ score = 10; // 長鎖塩基の場合
265+ else if (str.matches("^[Cch][0-9]+:[0-9]$"))
266+ score = 20; // 脂肪酸の場合
267+ else if (str.matches("^(pc|ins|hexa)$"))
268+ score = 30; // 還元末端側である可能性の高い糖の場合
269+ else if (str.matches("^(gal|glc)$"))
270+ score = 40; // 還元末端側である可能性の高い糖の場合
271+ else if (str.matches("^(man)$"))
272+ score = 50; // 次に還元末端側である可能性の高い糖の場合
273+ else if (str.matches("^(hex)$"))
274+ score = 60;
275+ else if (str.matches("^(fuc|rha)$"))
276+ score = 70;
277+ else if (str.matches("^(dhex)$"))
278+ score = 80;
279+ else if (str.matches("^(xyl|rha)$"))
280+ score = 90;
281+ else if (str.matches("^(pen)$"))
282+ score = 100;
283+ else if (str.matches("^(galnac|glcnac)$"))
284+ score = 110;
285+ else if (str.matches("^(hexnac)$"))
286+ score = 120;
287+ else if (str.matches("^(gal|glc)\\d*(me|ac)$"))
288+ score = 130 + countModification(str); // メチル化,アセチル化の個数で並び替える.
289+ else if (str.matches("^man\\d*(me|ac)$"))
290+ score = 140 + countModification(str);
291+ else if (str.matches("^hex\\d*(me|ac)$"))
292+ score = 150 + countModification(str);
293+ else if (str.matches("^(fuc|rha)\\d*(me|ac)$"))
294+ score = 160 + countModification(str);
295+ else if (str.matches("^dhex\\d*(me|ac)$"))
296+ score = 170 + countModification(str);
297+ else if (str.matches("^(xyl|rha)\\d*(me|ac)$"))
298+ score = 180 + countModification(str);
299+ else if (str.matches("^pen\\d*(me|ac)$"))
300+ score = 190 + countModification(str);
301+ else if (str.matches("^(galnac|glcnac)\\d*(me|ac)$"))
302+ score = 200 + countModification(str);
303+ else if (str.matches("^hexnac\\d*(me|ac)$"))
304+ score = 210 + countModification(str);
305+ else if (str.matches("^(p|c|pea|aep|kdn|neuac|neugc)$"))
306+ score = 220; // 糖の場合
307+ else if (str.matches("^(p|c|pea|aep|kdn|neuac|neugc)\\d*(me|ac)$"))
308+ score = 230; // 糖の場合
309+ else
310+ score = 240;// その他の修飾基など
311+
312+ return score;
313+ }
314+
315+ /**
316+ * 単糖のメチル基,アセチル基の個数を返します.
317+ */
318+ private int countModification(String str)
319+ {
320+ Pattern pt = Pattern.compile("^\\D+(\\d*)(me|ac)$");
321+ Matcher mt = pt.matcher(str);
322+
323+ if (mt.matches())
324+ {
325+ String number = mt.group(1);
326+ if (!number.equals(""))
327+ return Integer.parseInt(number); // 個数が指定されている場合
328+ else
329+ return 1; // 個数を指定していない場合は1個となる.
330+ }
331+ else
332+ {
333+ System.err.println("Monosacchride does not contain modification:" + str);
334+ return 0; // メチル基,アセチル基を持っていない場合は,0個を返す.
335+ }
336+ }
337+
338+ /**
339+ * glcをGlcへ,hexnacpaをHexNAcPAなど,単糖の表記を正しく変換します.
340+ */
341+ public static String toFixSignage(String before)
342+ {
343+ before = before.replace("nac", "NAc"); // "NAc"の置換後に"Ac"を置換
344+ before = before.replace("ac","Ac");
345+
346+ before = before.replace("me", "Me");
347+ before = before.replace("et", "Et");
348+ before = before.replace("tms", "TMS");
349+ before = before.replace("h2o", "H2O");
350+ before = before.replace("pa", "PA");
351+ before = before.replace("ab", "AB");
352+
353+ before = before.replace("pen", "Pen");
354+ before = before.replace("xyl", "Xyl");
355+ before = before.replace("ara", "Ara");
356+
357+ before = before.replace("lfuc", "LFuc"); // "LFuc"の置換後に"Fuc"を置換
358+ before = before.replace("fuc", "Fuc");
359+ before = before.replace("rha", "Rha");
360+
361+ before = before.replace("hexa", "HexA"); // "HexA"の置換後に"Hex"を置換
362+ before = before.replace("hex", "Hex"); // "dHex, HexNAcも同時に置換"
363+
364+ before = before.replace("glca", "GlcA"); // "GlcA"の置換後に"Glc"を置換
365+ before = before.replace("glc", "Glc");
366+ before = before.replace("gal", "Gal");
367+ before = before.replace("man", "Man");
368+
369+ if (before.equals("s"))
370+ before = "S";
371+ if (before.equals("p"))
372+ before = "P";
373+ if (before.equals("c"))
374+ before = "C";
375+ before = before.replace("pc", "PC");
376+
377+ before = before.replace("ins", "Ins");
378+ before = before.replace("aep", "AEP");
379+ before = before.replace("pea", "PEA");
380+ before = before.replace("kdn", "KDN");
381+ before = before.replace("neu", "Neu");
382+ before = before.replace("gc", "Gc");
383+
384+ if (before.equals("-h"))
385+ before = "-H";
386+ if (before.equals("h"))
387+ before = "H";
388+ if (before.equals("na"))
389+ before = "Na";
390+ if (before.equals("li"))
391+ before = "Li";
392+ if (before.equals("k"))
393+ before = "K";
394+
395+ return before;
396+ }
397+
398+ /**
399+ * 糖鎖組成が同じであるかを判定します.
400+ * @param cp 比較する組成
401+ * @return 判定結果
402+ */
403+ public boolean equals(Composition cp)
404+ {
405+ try
406+ {
407+ Composition cp1 = new Composition(this); // 順番を変化させないよう
408+ Composition cp2 = new Composition(cp); // コピーを作成
409+ Collections.sort(cp1); // ソート
410+ Collections.sort(cp2);
411+ return cp1.toString().equals(cp2.toString()); // Stringのメソッドで比較
412+ }
413+ catch (Exception e)
414+ {
415+ System.out.println("Exception at Composition.equals()");
416+ return false; // 例外が発生した場合,戻り値はfalseとする.
417+ }
418+ }
419+
420+ /**
421+ * 組成のハッシュ値を返します.
422+ * @return 判定結果
423+ */
424+ public int hashCode()
425+ {
426+ try
427+ {
428+ Composition cp = new Composition(this); // 順番を変化させないようコピーを作成
429+ Collections.sort(cp); // ソート
430+ return cp.toString().hashCode(); // CompositionのhashCode()であると再帰してしまうため,
431+ } // StringのhashCode()を使用
432+ catch (Exception e)
433+ {
434+ System.out.println("Exception at Composition.hashCode()");
435+ return 0; // 例外が発生した場合,戻り値は0とする.
436+ }
437+ }
438+
439+ /**
440+ * Glc,Gal,ManをHexへ,GlcNAc,GalNAcをHexNAcへ変換します.
441+ */
442+ public void toHexose()
443+ {
444+ ListIterator<String> li = this.listIterator();
445+
446+ while (li.hasNext())
447+ {
448+ String str = li.next();
449+ str = str.replaceAll("glc|man|gal", "hex"); // Hexへ変換
450+ str = str.replaceAll("lfuc|fuc|rha", "dhex"); // dHexへ変換
451+ str = str.replaceAll("xyl|ara", "pen"); // penへ変換
452+ li.set(str); // 変換した組成を格納する.
453+ }
454+ }
455+
456+ /*
457+ * GlcからHexなどの変換のテスト
458+ */
459+ private static void testToHexose() throws Exception
460+ {
461+ Composition cp1 = new Composition(new Glycan("[][th39:0]{[][fuc]{}[][hex]{}}"));
462+ Composition cp2 = new Composition("Hex, Hex*2, th38:0, c18:0, d17:0, Fuc");
463+ cp1.toHexose();
464+ cp2.toHexose();
465+ System.out.println(cp1);
466+ System.out.println(cp2);
467+ }
468+
469+ /**
470+ * 要素を含んでいるかを判定します.
471+ * @param str 判定したい文字列
472+ * @return 判定結果
473+ */
474+ public boolean contains(String str)
475+ {
476+ return super.contains(str.toLowerCase()); // 引数の文字列を小文字に変換して,親クラスのメソッドに渡す.
477+ }
478+
479+ /**
480+ * 指定した要素を削除します.
481+ * @param str 削除したい文字列
482+ * @return 削除の成功したか否か
483+ */
484+ public boolean remove(String str)
485+ {
486+ return super.remove(str.toLowerCase()); // 引数の文字列を小文字に変換して,親クラスのメソッドに渡す.
487+ }
488+
489+ /**
490+ * Globo系列であるかを判定します.
491+ * @return 指定した系列であるか否か
492+ */
493+ public boolean isGloboSeries() throws Exception
494+ {
495+ return this.isSeries(new Composition("glc, gal, gal, galnac"));
496+ }
497+
498+ /**
499+ * Lacto系列であるかを判定します.
500+ * @return 指定した系列であるか否か
501+ */
502+ public boolean isLactoSeries() throws Exception
503+ {
504+ return this.isSeries(new Composition("glc, gal, glcnac, gal"));
505+ }
506+
507+ /**
508+ * Ganglio系列であるかを判定します.
509+ * @return 指定した系列であるか否か
510+ */
511+ public boolean isGanglioSeries() throws Exception
512+ {
513+ return this.isSeries(new Composition("glc, gal, galnac, gal"));
514+ }
515+
516+ /**
517+ * Lactoganglio系列であるかを判定します.
518+ * @return 指定した系列であるか否か
519+ */
520+ public boolean isLactoganglioSeries() throws Exception
521+ {
522+ return this.isSeries(new Composition("glc, gal, galnac, glcnac"));
523+ }
524+
525+ /**
526+ * Gala系列であるかを判定します.
527+ * @return 指定した系列であるか否か
528+ */
529+ public boolean isGalaSeries() throws Exception
530+ {
531+ return this.isSeries(new Composition("gal, gal"));
532+ }
533+
534+ /**
535+ * Muco系列であるかを判定します.
536+ * @return 指定した系列であるか否か
537+ */
538+ public boolean isMucoSeries() throws Exception
539+ {
540+ return this.isSeries(new Composition("glc, gal, gal, gal"));
541+ }
542+
543+ /**
544+ * Arthro系列であるかを判定します.
545+ * @return 指定した系列であるか否か
546+ */
547+ public boolean isArthroSeries() throws Exception
548+ {
549+ return this.isSeries(new Composition("glc, man, glcnac, galnac"));
550+ }
551+
552+ /**
553+ * Mollu系列であるかを判定します.
554+ * @return 指定した系列であるか否か
555+ */
556+ public boolean isMolluSeries() throws Exception
557+ {
558+ return this.isSeries(new Composition("glc, man, man, glcnac"));
559+ }
560+
561+ /**
562+ * 指定した系列であるかを判定します.
563+ * @return 指定した系列であるか否か
564+ */
565+ private boolean isSeries(Composition series) throws Exception
566+ {
567+ Composition cp = new Composition(this); // 新しいインスタンスを作成
568+
569+ for (String str : series)
570+ {
571+ if (cp.contains(str)) // "glc"が存在した場合,削除する.
572+ cp.remove(str);
573+ else
574+ {
575+ Composition temp = new Composition(str); // "Glc"->"Hex"に変換するためにインスタンスを作成
576+ temp.toHexose(); // "Glc"->"Hex"に変換
577+
578+ if (cp.contains(temp.toString())) // "glc"が存在せず"hex"が存在した場合,削除する.
579+ cp.remove(temp.toString());
580+ else
581+ return false; // "glc"も"hex"も存在しない場合,削除に失敗したとする.
582+ }
583+ }
584+
585+ return true; // 全ての条件を満たした場合のみ,この系列であると判断する.
586+ }
587+
588+ /**
589+ * 組成から糖鎖系列の判定を行います.
590+ */
591+ private static void testSeries() throws Exception
592+ {
593+ Composition cp = new Composition("Glc, Glc, Hex, Hex, GlcNAc, -H2O");
594+ System.out.println(cp.isGloboSeries());
595+ }
596+
597+ /**
598+ * メチル基の入るヒドロキシル基の数を正しく数えているかをテストします.
599+ */
600+ private static void testCountHydroxy() throws Exception
601+ {
602+ Composition cp = new Composition("NeuAc2Me");
603+ System.out.println(cp + " : " + cp.countHydroxy());
604+ }
605+}
--- jp/ac/ritsumei/is/infobio/PredictionGUIGlycan.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/PredictionGUIGlycan.java (revision 1)
@@ -0,0 +1,600 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.text.*;
3+import java.awt.*;
4+import java.awt.event.*;
5+import javax.swing.*;
6+import java.util.*;
7+import javax.swing.table.*;
8+import java.util.concurrent.*;
9+import java.lang.management.*;
10+
11+/**
12+ * 糖鎖,およびピリジルアミノ化糖鎖のフラグメントイオンから構造を予測するクラスです.(GUI版)
13+ * @author 横井一仁
14+ * @version 20090202
15+ */
16+public class PredictionGUIGlycan implements Observer, ActionListener, Runnable
17+{
18+ String adduct = MassCalc.Na_ION; // 付加イオン(デフォルトはNa+)選択部のコードの重複ためグローバル変数とする.
19+ boolean monoavg = MassCalc.MONO_MASS; // Monoisotopic(ture),Averaget(false)
20+
21+ JFrame jf = new JFrame("Structure Predictor (free/PA oligosaccharide ver)"); // メインのフレーム
22+
23+ // HexNAc-HexNAc-HexNAc-HexNAc-HexNAcの実測フラグメント
24+ JTextArea query_ta = new JTextArea("210.46\n226.40\n259.28\n304.23\n322.24\n347.22\n388.27\n406.33\n507.56\n"
25+ + "512.00\n525.63\n532.50\n550.61\n568.62\n696.83\n712.80\n730.76\n753.75\n"
26+ + "760.46\n786.82\n831.78\n849.81\n874.75\n915.72\n933.68\n975.46\n990.71\n"
27+ + "993.66\n996.84\n1011.81\n1034.68\n1047.76\n1052.76\n1077.76\n1095.74\n"
28+ + "1111.85\n1118.75\n1126.02\n1129.14\n1151.93\n1171.90\n1196.97\n1199.47\n"
29+ + "1214.88\n1280.94\n1299.03\n1359.16\n1361.36\n1377.22\n1400.49\n1418.19\n"
30+ + "1472.53\n1579.87");
31+ JTextField precursor_mass_tf = new JTextField(""); // プレカーサーマスのm/z
32+ JTextField precursor_tolerance_tf = new JTextField("2.0"); // プレカーサーマスの許容誤差
33+ JTextField psd_tolerance_tf = new JTextField("2.0"); // PSDフラグメントの許容誤差
34+ JTextField known_gc_tf = new JTextField("GlcNAcPA-GlcNAc-Man(-Man)-Man"); // 既知構造
35+ JComboBox adduct_cb = new JComboBox(new String[]{"Na+","H+","Li+","K+","H-","No adduct"}); // 付加イオン
36+ JComboBox pen_cb = new JComboBox(new String[] {"Yes", "No"}); // Penが存在しているか否かを指定
37+ JComboBox dhex_cb = new JComboBox(new String[] {"Yes", "No"}); // dHexが存在しているか否かを指定
38+ JComboBox hex_cb = new JComboBox(new String[] {"Yes", "No"}); // Hexが存在しているか否かを指定
39+ JComboBox hexnac_cb = new JComboBox(new String[] {"Yes", "No"}); // HexNAcが存在しているか否かを指定
40+ JComboBox penme_cb = new JComboBox(new String[] {"Yes", "No"}); // PenMeが存在しているか否かを指定
41+ JComboBox dhexme_cb = new JComboBox(new String[] {"Yes", "No"}); // dHexMeが存在しているか否かを指定
42+ JComboBox hexme_cb = new JComboBox(new String[] {"Yes", "No"}); // HexMeが存在しているか否かを指定
43+ JComboBox hexnacme_cb = new JComboBox(new String[] {"Yes", "No"}); // HexNAcMeが存在しているか否かを指定
44+
45+ JTextArea ceramide_tf = new JTextArea("dc30-44:1, dh30-44:1,\ntc30-44:0, th30-44:0"); // 既知セラミド組成
46+ JComboBox formula_cb = new JComboBox(new String[] // スコア計算式
47+ {
48+ "POSITIVE",
49+ "TFIDF",
50+ "PENALTY01",
51+ "PENALTY001",
52+ "PMF",
53+ "GEOMETRICAVG"
54+ });
55+ JButton start = new JButton("Start search"); // 検索開始ボタン
56+ JButton reset = new JButton("Reset form"); // リセットボタン
57+
58+ String[] title = {"Score", "Candidate structure", "Occupancy", "m/z"}; // 予想構造出力部
59+ DefaultTableModel tm = new DefaultTableModel(title, 0);
60+ JTable result_ta = new JTable(tm);
61+
62+ ProgressMonitor pm; // 進捗バー
63+
64+ /*
65+ * 実測値を入力する部分のJPanelを取得します.
66+ */
67+ protected JPanel getInputJPanel()
68+ {
69+ JPanel west_center = new JPanel(); // ウィンドウのWESTに貼り付けるパネルのCENTER
70+ west_center.setLayout(new BorderLayout()); // ウィンドウの左上
71+ west_center.add(new JLabel("Fragment mass:"), BorderLayout.NORTH);
72+ west_center.add(new JScrollPane(query_ta), BorderLayout.CENTER); // JTextAreaへスクロールバーをつける.
73+
74+ return west_center;
75+ }
76+
77+ /*
78+ * 実験的な予測条件を設定する部分のJPanelを取得します.
79+ */
80+ protected JPanel getExperimentalConditionJPanel()
81+ {
82+ JPanel west_south_north = new JPanel(); // 予測条件入力部 ウィンドウのWESTに貼り付けるパネルのSOUTH
83+ // ウィンドウの左下
84+ // JComboBoxの初期選択項目を指定する.
85+ pen_cb.setSelectedItem("No"); // Penのデフォルトは"No"
86+ dhex_cb.setSelectedItem("Yes"); // dHexのデフォルトは"Yes"
87+ hex_cb.setSelectedItem("Yes"); // Hexのデフォルトは"Yes"
88+ hexnac_cb.setSelectedItem("Yes"); // HexNAcのデフォルトは"Yes"
89+
90+ penme_cb.setSelectedItem("No"); // PenMeのデフォルトは"No"
91+ dhexme_cb.setSelectedItem("No"); // dHexMeのデフォルトは"No"
92+ hexme_cb.setSelectedItem("No"); // HexMeのデフォルトは"No"
93+ hexnacme_cb.setSelectedItem("No"); // HexNAcMeのデフォルトは"No"
94+
95+ formula_cb.setSelectedItem("TFIDF"); // スコア計算式のデフォルトは"TFIDF"
96+
97+ west_south_north.setLayout(new GridLayout(12, 2)); // 縦の数×横の数
98+ west_south_north.add(new JLabel("Fragment tolerance: "));
99+ west_south_north.add(psd_tolerance_tf);
100+ west_south_north.add(new JLabel("Precursor mass: "));
101+ west_south_north.add(precursor_mass_tf);
102+ west_south_north.add(new JLabel("Precursor tolerance: "));
103+ west_south_north.add(precursor_tolerance_tf);
104+ west_south_north.add(new JLabel("Adduct ion: "));
105+ west_south_north.add(adduct_cb);
106+ west_south_north.add(new JLabel("Pen: "));
107+ west_south_north.add(pen_cb);
108+ west_south_north.add(new JLabel("dHex: "));
109+ west_south_north.add(dhex_cb);
110+ west_south_north.add(new JLabel("Hex: "));
111+ west_south_north.add(hex_cb);
112+ west_south_north.add(new JLabel("HexNAc: "));
113+ west_south_north.add(hexnac_cb);
114+ west_south_north.add(new JLabel("PenMe: "));
115+ west_south_north.add(penme_cb);
116+ west_south_north.add(new JLabel("dHexMe: "));
117+ west_south_north.add(dhexme_cb);
118+ west_south_north.add(new JLabel("HexMe: "));
119+ west_south_north.add(hexme_cb);
120+ west_south_north.add(new JLabel("HexNAcMe: "));
121+ west_south_north.add(hexnacme_cb);
122+
123+ return west_south_north;
124+ }
125+
126+ /*
127+ * 実験的な予測条件を設定する部分のJPanelを取得します.
128+ */
129+ protected JPanel getKnownConditionJPanel()
130+ {
131+ JPanel west_south_center = new JPanel();
132+ west_south_center.setLayout(new GridBagLayout()); // 入力部を広くするためにGridBagLayoutを用いる.
133+
134+ GridBagConstraints gb3 = new GridBagConstraints(); // 既知糖鎖組成入力部のラベル
135+ gb3.gridx = 0;
136+ gb3.gridy = 1;
137+ gb3.anchor = GridBagConstraints.WEST; // 左寄せ
138+ west_south_center.add(new JLabel("Known: "), gb3);
139+
140+ GridBagConstraints gb4 = new GridBagConstraints(); // 既知糖鎖組成入力部
141+ gb4.gridx = 1;
142+ gb4.gridy = 1;
143+ gb4.fill = GridBagConstraints.HORIZONTAL; // 水平方向のみに塗りつぶしを行う.
144+ gb4.weightx = 1.0; // 無いとレイアウトが崩れる.
145+ west_south_center.add(known_gc_tf, gb4);
146+
147+ return west_south_center;
148+ }
149+
150+ /*
151+ * 計算機的な予測条件を設定する部分のJPanelを取得します.
152+ */
153+ protected JPanel getComputationalConditionJPanel()
154+ {
155+ byte[] bytes = {40, 99, 41, 32, 75, 97, 122, 117, 104, 105, 116, 111, 32, 89, 111, 107, 111, 105};
156+
157+ // スコアリング選択部分をBorderLayoutのNORTHとし,
158+ // 検索開始ボタンとリセットボタンをSOUTHとして返す.
159+ JPanel west_south_south_north = new JPanel(); // スコアリングの選択
160+ west_south_south_north.setLayout(new GridLayout(1, 2)); // 縦の数×横の数
161+
162+ JPanel west_south_south_south = new JPanel(); // 検索開始ボタンとリセットボタン
163+ west_south_south_south.setLayout(new GridLayout(1, 2)); // 縦の数×横の数
164+ start.addActionListener(this); // 検索開始ボタンにリスナを付ける.
165+ reset.addActionListener(this); // リセットボタンにリスナを付ける.
166+
167+ JLabel author = new JLabel(new String(bytes));
168+ author.setHorizontalAlignment(SwingConstants.CENTER);
169+ author.setForeground(Color.gray);
170+ west_south_south_south.add(author);
171+ west_south_south_south.add(start);
172+
173+ JPanel west_south_south = new JPanel(); // returnするJPanelインスタンス
174+ west_south_south.setLayout(new BorderLayout());
175+ west_south_south.add(west_south_south_north, BorderLayout.NORTH); // スコアリングの選択部分を追加
176+ west_south_south.add(west_south_south_south, BorderLayout.SOUTH); // 検索開始ボタンとリセットボタンを追加
177+
178+ return west_south_south;
179+ }
180+
181+ /*
182+ * 予測条件を設定する部分のJPanelを取得します.
183+ */
184+ protected JPanel getConditionJPanel()
185+ { // 予測条件入力部
186+ JPanel west_south = new JPanel(); // ウィンドウのWESTに貼り付ける
187+ // パネルのSOUTH(ウィンドウの左下)
188+ west_south.setLayout(new BorderLayout());
189+
190+ west_south.add(getExperimentalConditionJPanel(), BorderLayout.NORTH); // 実験的な予測条件を設定
191+ west_south.add(getKnownConditionJPanel(), BorderLayout.CENTER); // 実験的な予測条件を設定
192+ west_south.add(getComputationalConditionJPanel(), BorderLayout.SOUTH); // 計算機的な予測条件を設定
193+
194+ return west_south;
195+ }
196+
197+ /*
198+ * 予測結果を出力する部分のJPanelを取得します.
199+ */
200+ protected JPanel getOutputJPanel()
201+ {
202+ JPanel center = new JPanel(); // 予想構造出力部
203+ center.setLayout(new BorderLayout()); // ウィンドウのCENTERに貼り付けるパネル(ウィンドウの右)
204+ this.resetTableColumnSize(); // カラム幅を指定する.
205+ JScrollPane result_sp = new JScrollPane(result_ta); // JTableへスクロールバーをつける.
206+ result_sp.addMouseListener(new MouseListener() // 表を右クリックすると印刷する.
207+ {
208+ public void mouseExited(MouseEvent me){}
209+ public void mouseEntered(MouseEvent me){}
210+ public void mousePressed(MouseEvent me){}
211+ public void mouseReleased(MouseEvent me){}
212+ public void mouseClicked(MouseEvent me)
213+ {
214+ if (me.getButton() == MouseEvent.BUTTON3) // 右クリック
215+ {
216+ try
217+ {
218+ result_ta.print(); // 印刷ダイアログを表示
219+ }
220+ catch (Exception e)
221+ {
222+ System.out.println("Cannot print: " + e);
223+ }
224+ }
225+ }
226+ });
227+ center.add(new JLabel("Result:"), BorderLayout.NORTH);
228+ center.add(result_sp, BorderLayout.CENTER);
229+
230+ return center;
231+ }
232+
233+ /*
234+ * テーブルのカラム幅を調節します.
235+ */
236+ protected void resetTableColumnSize()
237+ {
238+ DefaultTableCellRenderer tr = new DefaultTableCellRenderer(); // カラムを右寄せするインスタンス
239+ tr.setHorizontalAlignment(SwingConstants.RIGHT);
240+
241+ TableColumn tc0 = result_ta.getColumnModel().getColumn(0); // スコアのカラム(0番目)のサイズを固定
242+ tc0.setMinWidth(70);
243+ tc0.setMaxWidth(70);
244+ tc0.setCellRenderer(tr); // カラムを右寄せ
245+ // 候補構造のカラムはサイズを指定
246+ TableColumn tc2 = result_ta.getColumnModel().getColumn(2); // 占有率のカラム(2番目)のサイズを固定
247+ tc2.setMinWidth(70);
248+ tc2.setMaxWidth(70);
249+ tc2.setCellRenderer(tr); // カラムを右寄せ
250+ TableColumn tc3 = result_ta.getColumnModel().getColumn(3); // m/zのカラム(3番目)のサイズを固定
251+ tc3.setMinWidth(80);
252+ tc3.setMaxWidth(80);
253+ tc3.setCellRenderer(tr); // カラムを右寄せ
254+ }
255+
256+ public PredictionGUIGlycan() throws Exception
257+ {
258+ jf.setLayout(new BorderLayout()); // ウィンドウへのコンポーネントの貼り付けは
259+ // BorderLayoutを用いる.
260+ JPanel west = new JPanel(); // ウィンドウのWESTに貼り付けるパネル
261+ west.setLayout(new BorderLayout()); // ウィンドウの左
262+ west.add(getInputJPanel(), BorderLayout.CENTER); // 実測値を入力する部分をWESTのCENTERに配置
263+ west.add(getConditionJPanel(), BorderLayout.SOUTH); // 予測条件を設定する部分をWESTのNORTHに配置
264+ jf.getContentPane().add(west, BorderLayout.WEST);
265+
266+ jf.getContentPane().add(getOutputJPanel(), BorderLayout.CENTER); // 予測結果を出力する部分をCENTERに配置
267+
268+ try // タスクトレイにアイコンを追加する.
269+ {
270+ SystemTray st = SystemTray.getSystemTray();
271+ ImageIcon ii = (ImageIcon)UIManager.getIcon("FileView.computerIcon"); // IconからImageIconへ型変換
272+ TrayIcon ti = new TrayIcon(ii.getImage());
273+ ti.addActionListener(new ActionListener() // トレイアイコンをダブルクリックすることで,
274+ { // ウィンドウの表示/非表示を切り替える.
275+ public void actionPerformed(ActionEvent e)
276+ {
277+ if (jf.isShowing()) // ウィンドウが表示されている場合は,
278+ jf.setVisible(false); // 非表示にする.
279+ else
280+ { // 表示されていない場合は,
281+ jf.setVisible(true); // 表示した後,
282+ jf.toFront(); // このウィンドウにフォーカスを当てる.
283+ }
284+ }
285+ });
286+ st.add(ti);
287+ }
288+ catch (Exception e)
289+ {
290+ System.err.println("Cannot use SystemTray: " + e);
291+ }
292+
293+ try // Swingから,Windowsのデザインへ変更
294+ {
295+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); // 外観を設定
296+ SwingUtilities.updateComponentTreeUI(jf); // 外観変更
297+ }
298+ catch (Exception e)
299+ {
300+ System.err.println("Cannot use WindowsLookAndFeel: " + e);
301+ }
302+
303+ jf.setSize(900,700);
304+ jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ウインドウが閉じられた時に終了
305+ jf.setVisible(true); // 表示
306+ }
307+
308+ /*
309+ * Swingのアクションイベントが発生した時の動作を指定します.
310+ * @parm ae 取得したアクションイベント
311+ */
312+ public void actionPerformed(ActionEvent ae)
313+ {
314+ if (ae.getSource() == start) // Startボタンが押された時
315+ {
316+ DefaultTableModel tm = (DefaultTableModel)result_ta.getModel(); // テーブルモデルを取得し,
317+ tm.setRowCount(0); // 表の内容を削除する.
318+ start.setEnabled(false); // ボタンを押せなくする.
319+ reset.setEnabled(false);
320+
321+ try // ProgressMonitorのタイトルなどは
322+ { // デフォルトでは日本語のため,英語名に変更
323+ UIManager.put( "ProgressMonitor.progressText", "Progress Monitor" ); // ウィンドウ名
324+ UIManager.put( "OptionPane.cancelButtonText", "Cancel" ); // キャンセルボタン名
325+ }
326+ catch (Exception e)
327+ {
328+ System.err.println("ProgressMonitor connot edit: " + e);
329+ }
330+
331+ // 表示する文字列のテンプレート
332+ String length = "Creating Glycan Composition from precursor and fragment mass... ";
333+ pm = new ProgressMonitor(jf, "Calculating...", length, 0, 100); // 進捗バー
334+ pm.setMillisToDecideToPopup(0);
335+ pm.setMillisToPopup(0);
336+ pm.setProgress(0); // 監視対象のインスタンスから変数を取得
337+ Thread th = new Thread(this);
338+ th.start();
339+ }
340+ else if (ae.getSource() == reset) // Resetボタンが押された時
341+ {
342+ query_ta.setText(""); // フラグメント分子量の内容を削除
343+ DefaultTableModel tm = (DefaultTableModel)result_ta.getModel(); // テーブルモデルを取得し,
344+ tm.setRowCount(0); // 表の内容を削除する.
345+ }
346+ }
347+
348+ /*
349+ * 監視対象が更新された時の動作を指定します.
350+ * @parm ae 取得したアクションイベント
351+ */
352+ public void update(Observable ob, Object arg)
353+ {
354+ if (ob instanceof Prediction) // Predictionクラスのインスタンスであるかを判定
355+ {
356+ Prediction temp = (Prediction)ob; // Observableインスタンスとして渡されるので型変換
357+ pm.setProgress(temp.percent); // 監視対象のインスタンスからメンバ変数を取得
358+ pm.setNote(arg.toString()); // 進捗情報の表示
359+
360+ StringBuilder line = new StringBuilder(32); // コマンドラインに表示する文字列
361+ MemoryMXBean mm = ManagementFactory.getMemoryMXBean();
362+ MemoryUsage mu = mm.getHeapMemoryUsage();
363+ line.append(" Memory: ");
364+ line.append(String.format("%.1f/", mu.getUsed() / 1024.0 / 1024));
365+ line.append(String.format("%.1fMB", mu.getMax() / 1024.0 / 1024));
366+
367+ System.out.println(arg + " " + line); // 進捗情報の表示
368+
369+ if (pm.isCanceled()) // ProgressMonitorのキャンセルボタンが押された時
370+ {
371+ pm.close(); // ProgressMonitorウィンドウを閉じる.
372+ temp.flag = false; // 断片化処理を抜ける.
373+ }
374+ }
375+ else
376+ System.out.println("ERROR: unknown incetance of observerable class.");
377+ }
378+
379+ /*
380+ * Startをクリックした時に実行されるスレッド
381+ */
382+ public void run()
383+ {
384+ try
385+ {
386+ Prediction pd_agg = new Prediction(); // 継承の代わりに集約を用いる.
387+ pd_agg.addObserver(this); // 進行状況をこのクラスへ伝えるために,
388+ // このクラスをオブザーバとする.
389+ // テキストエリアから実測値を取得
390+ String[] strs = query_ta.getText().split("[^\\.\\d]"); // '.'と数字以外の文字列で切り出す.
391+ java.util.List<Double> massli = new ArrayList<Double>(); // 可変長配列を用意する.
392+ for (String str : strs)
393+ {
394+ try
395+ {
396+ massli.add(Double.parseDouble(str));
397+ }
398+ catch (Exception e) // 数字以外の文字が入っていた場合の時,
399+ { // 無視したことを報告
400+ System.err.println(e);
401+ }
402+ }
403+ double[] frags = new double[massli.size()]; // Listと同じ大きさの配列を用意する.
404+ Iterator<Double> massit = massli.iterator();
405+ for (int i = 0; massit.hasNext(); i++) // double[]型のfragsへ配列の型変換
406+ frags[i] = massit.next();
407+ pd_agg.setFragments(frags); // フラグメントの実測値の配列を登録
408+
409+ try // プレカーサーマスを登録
410+ {
411+ pd_agg.setPrecursorMass(Double.parseDouble(precursor_mass_tf.getText()));
412+ }
413+ catch (Exception e)
414+ { // プレカーサーマスを登録しなかった場合,
415+ System.err.println("Precursor mass is null."); // PSDフラグメントの最大値を
416+ } // プレカーサーマスとして計算
417+
418+ try // プレカーサーマスの許容誤差を登録
419+ {
420+ pd_agg.setMsTolerance(Double.parseDouble(precursor_tolerance_tf.getText())); // 許容誤差を格納
421+ }
422+ catch (Exception e)
423+ {
424+ throw new Exception("'Precursor tolerance' contains error.\n" + e);
425+ }
426+
427+ try // PSDフラグメントの許容誤差を登録
428+ {
429+ pd_agg.setPsdTolerance(Double.parseDouble(psd_tolerance_tf.getText())); // 許容誤差を格納
430+ }
431+ catch (Exception e)
432+ {
433+ throw new Exception("'PSD tolerance' contains error.\n" + e);
434+ }
435+
436+ try // 付加イオンを登録
437+ { // 選択された付加イオンを取得する.
438+ String temp = (String)adduct_cb.getSelectedItem(); // 表の部分でm/zを取得するのに必要なため,
439+ if (temp.equals("Na+")) // adductはグローバル変数としている.
440+ adduct = MassCalc.Na_ION;
441+ else if (temp.equals("H+"))
442+ adduct = MassCalc.H_ION;
443+ else if (temp.equals("Li+"))
444+ adduct = MassCalc.Li_ION;
445+ else if (temp.equals("K+"))
446+ adduct = MassCalc.K_ION;
447+ else if (temp.equals("H-"))
448+ adduct = MassCalc.H_NION;
449+ else if (temp.equals("No adduct"))
450+ adduct = "";
451+ else
452+ throw new Exception(temp + " is unknown adduct ion.");
453+
454+ pd_agg.setAdduct(adduct);
455+ }
456+ catch (Exception e)
457+ {
458+ throw new Exception("'Adduct ion' contains error.\n" + e);
459+ }
460+
461+ try // 既知構造を登録
462+ {
463+ pd_agg.setGlycan(new Glycan(known_gc_tf.getText())); // Linucs形式から既知構造を登録
464+ }
465+ catch (Exception e1) // Linucs形式の読み込みに失敗した場合,
466+ { // ノーマル形式の読み込みを試す.
467+ try
468+ {
469+ GlycanTools gi = new GlycanTools();
470+ pd_agg.setGlycan(gi.readNormalFormat(known_gc_tf.getText())); // 既知構造を登録
471+ }
472+ catch (Exception e2)
473+ {
474+ throw new Exception("'Known structure' contains error.\n" + e1 + e2);
475+ }
476+ }
477+
478+ try // 各糖の最大数を登録
479+ {
480+ pd_agg.setMax("pen", ((String)pen_cb.getSelectedItem()).equals("Yes"));
481+ pd_agg.setMax("dhex", ((String)dhex_cb.getSelectedItem()).equals("Yes"));
482+ pd_agg.setMax("hex", ((String)hex_cb.getSelectedItem()).equals("Yes"));
483+ pd_agg.setMax("hexnac", ((String)hexnac_cb.getSelectedItem()).equals("Yes"));
484+ pd_agg.setMax("penme", ((String)penme_cb.getSelectedItem()).equals("Yes"));
485+ pd_agg.setMax("dhexme", ((String)dhexme_cb.getSelectedItem()).equals("Yes"));
486+ pd_agg.setMax("hexme", ((String)hexme_cb.getSelectedItem()).equals("Yes"));
487+ pd_agg.setMax("hexnacme", ((String)hexnacme_cb.getSelectedItem()).equals("Yes"));
488+ }
489+ catch (Exception e)
490+ {
491+ throw new Exception("'max' contains error.\n" + e);
492+ }
493+
494+ try // スコアリングの式を登録
495+ {
496+ String temp = (String)formula_cb.getSelectedItem(); // 選択されたスコアリングの式を取得
497+ if (temp.equals("POSITIVE"))
498+ pd_agg.setScoringFormula(Candidate.POSITIVE_SCORING);
499+ else if (temp.equals("TFIDF"))
500+ pd_agg.setScoringFormula(Candidate.TFIDF_SCORING);
501+ else if (temp.equals("PENALTY01"))
502+ pd_agg.setScoringFormula(Candidate.PENALTY01_SCORING);
503+ else if (temp.equals("PENALTY001"))
504+ pd_agg.setScoringFormula(Candidate.PENALTY001_SCORING);
505+ else if (temp.equals("PMF"))
506+ pd_agg.setScoringFormula(Candidate.PMF_SCORING);
507+ else if (temp.equals("GEOMETRICAVG"))
508+ pd_agg.setScoringFormula(Candidate.GEOMETRICAVG_SCORING);
509+ else
510+ throw new Exception(temp + " is unknown adduct ion.");
511+ }
512+ catch (Exception e)
513+ {
514+ throw new Exception("'Scoring' contains error.\n" + e);
515+ }
516+
517+ try // 出現確率分布のウィンドウサイズを登録
518+ {
519+ pd_agg.setWindowSize(1);
520+ }
521+ catch (Exception e)
522+ {
523+ throw new Exception("'Window size' contains error.\n" + e);
524+ }
525+
526+ // 出力部
527+ java.util.List<? extends Candidate> cds = pd_agg.getPrediction();
528+ Collections.sort(cds, new Comparator<Candidate>() // フラグメントの存在率の高い順にソート
529+ {
530+ public int compare(Candidate cp1, Candidate cp2)
531+ {
532+ double sub = 0.0; // 存在率の差
533+ try
534+ {
535+ double score1 = cp1.getOccupancy();
536+ double score2 = cp2.getOccupancy();
537+
538+ if (score1 == score2) // 存在率が等しい構造は,分岐数の少ない
539+ sub = cp1.countLeaf() - cp2.countLeaf(); // (葉ノードの数が少ない)構造を上位に表示
540+ else
541+ sub = score2 - score1;
542+ }
543+ catch (Exception e)
544+ {
545+ System.err.println("Prediction.getPrediction(): score compare error");
546+ }
547+
548+ return (int)(sub*1024); // 精度を1024倍に上げる
549+ }
550+ }); // 存在率が高い順にソートを行う.
551+ Iterator<? extends Candidate> it = cds.iterator();
552+ DefaultTableModel tm = new DefaultTableModel(title, 0);
553+ for (int i = 0; i < 50 && it.hasNext(); i++) // 上位50候補を表示
554+ {
555+ Candidate cd = it.next();
556+
557+ String[] table = new String[4]; // カラムの追加時は,配列の大きさに注意
558+ table[0] = String.format("%.4f", cd.getScore());
559+
560+ try
561+ {
562+ table[1] = cd.toNormalFormat(); // ノーマルのフォーマットで格納
563+ }
564+ catch (Exception e)
565+ {
566+ table[1] = cd.toString(); // 二分岐以上の構造はLinucs形式で格納
567+ }
568+
569+ table[2] = String.format("%.4f", cd.getOccupancy());
570+ table[3] = String.format("%.4f", cd.getMass(monoavg, adduct));
571+ tm.addRow(table);
572+ }
573+ result_ta.setModel(tm);
574+ RowSorter<TableModel> rs = new TableRowSorter<TableModel>(tm); // ソート可能なテーブルにする.
575+ result_ta.setRowSorter(rs);
576+ this.resetTableColumnSize(); // カラム幅を指定する.
577+
578+ java.awt.Toolkit.getDefaultToolkit().beep(); // 終了する時にビープ音を鳴らす.
579+
580+ UIManager.put("OptionPane.messageDialogTitle", "Messege"); // "タイトルを"Messege"に変更する.
581+ UIManager.put("OptionPane.okButtonText", "OK"); // "了解"の部分を"OK"に変更する.
582+ JOptionPane.showMessageDialog(jf, "Calclation is finished.\n" + pm.getNote() + "\n"
583+ + "Candidate structure: " + cds.size());
584+ start.setEnabled(true); // ボタンを押せるようにする.
585+ reset.setEnabled(true);
586+ }
587+ catch (Exception e) // 処理の途中で例外が発生した場合,
588+ { // 警告ダイアログを表示し処理を中断
589+ JOptionPane.showMessageDialog(jf, "ERROR: " + e);
590+ e.printStackTrace();
591+ start.setEnabled(true); // ボタンを押せるようにする.
592+ reset.setEnabled(true);
593+ }
594+ }
595+
596+ public static void main(String[] args) throws Exception
597+ {
598+ new PredictionGUIGlycan();
599+ }
600+}
--- jp/ac/ritsumei/is/infobio/PredictionGUI.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/PredictionGUI.java (revision 1)
@@ -0,0 +1,664 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.text.*;
3+import java.awt.*;
4+import java.awt.event.*;
5+import javax.swing.*;
6+import java.util.*;
7+import javax.swing.table.*;
8+import java.util.concurrent.*;
9+import java.lang.management.*;
10+
11+/**
12+ * 糖脂質のフラグメントイオンから構造を予測するクラスです.(GUI版)
13+ * @author 横井一仁
14+ * @version 20090129
15+ */
16+public class PredictionGUI implements Observer, ActionListener, Runnable
17+{
18+ String adduct = MassCalc.Na_ION; // 付加イオン(デフォルトはNa+)選択部のコードの重複ためグローバル変数とする.
19+ boolean monoavg = MassCalc.MONO_MASS; // Monoisotopic(ture),Averaget(false)
20+
21+ JFrame jf = new JFrame("Structure Predictor"); // メインのフレーム
22+
23+ // L5のフラグメント
24+ JTextArea query_ta = new JTextArea("226.6\n346.4\n364.8\n429.3\n447.5\n590.5\n632.3\n722.2\n736.7\n793.6\n"
25+ + "811.1\n884.5\n899.7\n956.5\n974.0\n1087.9\n1103.2\n1493.8\n1508.2");
26+
27+ JTextField precursor_mass_tf = new JTextField("1493.6327"); // プレカーサーマスのm/z
28+ JTextField precursor_tolerance_tf = new JTextField("0.5"); // プレカーサーマスの許容誤差
29+ JTextField psd_tolerance_tf = new JTextField("1.0"); // PSDフラグメントの許容誤差
30+ JTextField known_gc_tf = new JTextField("Hex"); // 既知構造
31+ JComboBox adduct_cb = new JComboBox(new String[]{"Na+","H+","Li+","K+","H-","No adduct"}); // 付加イオン
32+ JComboBox pen_cb = new JComboBox(new String[] {"Yes", "No"}); // Penが存在しているか否かを指定
33+ JComboBox dhex_cb = new JComboBox(new String[] {"Yes", "No"}); // dHexが存在しているか否かを指定
34+ JComboBox hex_cb = new JComboBox(new String[] {"Yes", "No"}); // Hexが存在しているか否かを指定
35+ JComboBox hexnac_cb = new JComboBox(new String[] {"Yes", "No"}); // HexNAcが存在しているか否かを指定
36+ JComboBox penme_cb = new JComboBox(new String[] {"Yes", "No"}); // Penが存在しているか否かを指定
37+ JComboBox dhexme_cb = new JComboBox(new String[] {"Yes", "No"}); // dHexMeが存在しているか否かを指定
38+ JComboBox hexme_cb = new JComboBox(new String[] {"Yes", "No"}); // HexMeが存在しているか否かを指定
39+ JComboBox hexnacme_cb = new JComboBox(new String[] {"Yes", "No"}); // HexNAcMeが存在しているか否かを指定
40+
41+ JTextArea ceramide_tf = new JTextArea("d14-20:1, c14-24:0,\n"
42+ + "t14-20:0, h14-24:0"); // 既知セラミド組成
43+ JComboBox formula_cb = new JComboBox(new String[] // スコア計算式
44+ {
45+ "POSITIVE",
46+ "TFIDF",
47+ "PENALTY01",
48+ "PENALTY001",
49+ "PMF",
50+ "GEOMETRICAVG"
51+ });
52+ JButton start = new JButton("Start search"); // 検索開始ボタン
53+ JButton reset = new JButton("Reset form"); // リセットボタン
54+
55+ String[] title = {"Score", "Candidate structure", "Occupancy", "m/z"}; // 予想構造出力部
56+ DefaultTableModel tm = new DefaultTableModel(title, 0);
57+ JTable result_ta = new JTable(tm);
58+
59+ ProgressMonitor pm; // 進捗バー
60+
61+ /*
62+ * 実測値を入力する部分のJPanelを取得します.
63+ */
64+ protected JPanel getInputJPanel()
65+ {
66+ JPanel west_center = new JPanel(); // 実測値入力部
67+ west_center.setLayout(new BorderLayout()); // ウィンドウのWESTに貼り付けるパネルのCENTER
68+ west_center.add(new JLabel("Fragment mass:"), BorderLayout.NORTH);
69+ west_center.add(new JScrollPane(query_ta), BorderLayout.CENTER); // JTextAreaへスクロールバーをつける.
70+
71+ return west_center;
72+ }
73+
74+ /*
75+ * 実験的な予測条件を設定する部分のJPanelを取得します.
76+ */
77+ protected JPanel getExperimentalConditionJPanel()
78+ {
79+ JPanel west_south_north = new JPanel(); // 予測条件入力部 ウィンドウのWESTに貼り付けるパネルのSOUTH
80+ // JComboBoxの初期選択項目を指定する.
81+ pen_cb.setSelectedItem("No"); // Penのデフォルトは"No"
82+ dhex_cb.setSelectedItem("Yes"); // dHexのデフォルトは"Yes"
83+ hex_cb.setSelectedItem("Yes"); // Hexのデフォルトは"Yes"
84+ hexnac_cb.setSelectedItem("Yes"); // HexNAcのデフォルトは"Yes"
85+ penme_cb.setSelectedItem("No"); // PenMeのデフォルトは"No"
86+ dhexme_cb.setSelectedItem("No"); // dHexMeのデフォルトは"No"
87+ hexme_cb.setSelectedItem("No"); // HexMeのデフォルトは"No"
88+ hexnacme_cb.setSelectedItem("No"); // HexNAcMeのデフォルトは"No"
89+
90+ formula_cb.setSelectedItem("TFIDF"); // スコア計算式のデフォルトは"TFIDF"
91+
92+ west_south_north.setLayout(new GridLayout(12, 2)); // 縦の数×横の数
93+ west_south_north.add(new JLabel("Fragment tolerance: "));
94+ west_south_north.add(psd_tolerance_tf);
95+ west_south_north.add(new JLabel("Precursor mass: "));
96+ west_south_north.add(precursor_mass_tf);
97+ west_south_north.add(new JLabel("Precursor tolerance: "));
98+ west_south_north.add(precursor_tolerance_tf);
99+ west_south_north.add(new JLabel("Adduct ion: "));
100+ west_south_north.add(adduct_cb);
101+ west_south_north.add(new JLabel("Pen: "));
102+ west_south_north.add(pen_cb);
103+ west_south_north.add(new JLabel("dHex: "));
104+ west_south_north.add(dhex_cb);
105+ west_south_north.add(new JLabel("Hex: "));
106+ west_south_north.add(hex_cb);
107+ west_south_north.add(new JLabel("HexNAc: "));
108+ west_south_north.add(hexnac_cb);
109+ west_south_north.add(new JLabel("PenMe: "));
110+ west_south_north.add(penme_cb);
111+ west_south_north.add(new JLabel("dHexMe: "));
112+ west_south_north.add(dhexme_cb);
113+ west_south_north.add(new JLabel("HexMe: "));
114+ west_south_north.add(hexme_cb);
115+ west_south_north.add(new JLabel("HexNAcMe: "));
116+ west_south_north.add(hexnacme_cb);
117+
118+ return west_south_north;
119+ }
120+
121+ /*
122+ * 実験的な予測条件を設定する部分のJPanelを取得します.
123+ */
124+ protected JPanel getKnownConditionJPanel()
125+ {
126+ JPanel west_south_center = new JPanel();
127+ west_south_center.setLayout(new GridBagLayout()); // 入力部を広くするためにGridBagLayoutを用いる.
128+
129+ GridBagConstraints gb1 = new GridBagConstraints(); // 糖鎖系列選択部のラベル
130+ gb1.gridx = 0;
131+ gb1.gridy = 0;
132+ gb1.anchor = GridBagConstraints.WEST; // 左寄せ
133+ west_south_center.add(new JLabel("Series: "), gb1);
134+
135+ GridBagConstraints gb2 = new GridBagConstraints(); // 糖鎖系列入力部
136+ gb2.gridx = 1;
137+ gb2.gridy = 0;
138+ gb2.fill = GridBagConstraints.HORIZONTAL; // 水平方向のみに塗りつぶしを行う.
139+ gb2.weightx = 1.0; // 無いとレイアウトが崩れる.
140+ final JComboBox series_cb = new JComboBox(new String[] // 内部クラスからアクセスするためfinalで宣言
141+ {
142+ "",
143+ "Globo/Isoglobo",
144+ "Lacto/Neolacto",
145+ "Ganglio/Isoganglio",
146+ "Lactoganglio",
147+ "Gala",
148+ "Muco",
149+ "Arthro",
150+ "Mollu"
151+ });
152+ series_cb.addActionListener(new ActionListener() // 既知糖鎖構造のテキストエリアに入力する.
153+ {
154+ public void actionPerformed(ActionEvent e)
155+ {
156+ String temp = (String)series_cb.getSelectedItem();
157+ if (temp.equals(""))
158+ known_gc_tf.setText("");
159+ else if (temp.equals("Globo/Isoglobo"))
160+ known_gc_tf.setText("Glc-Gal-Gal-GalNAc");
161+ else if (temp.equals("Lacto/Neolacto"))
162+ known_gc_tf.setText("Glc-Gal-GlcNAc-Gal");
163+ else if (temp.equals("Ganglio/Isoganglio"))
164+ known_gc_tf.setText("Glc-Gal-GalNAc-Gal");
165+ else if (temp.equals("Lactoganglio"))
166+ known_gc_tf.setText("Glc-Gal(-GlcNAc)-GalNAc");
167+ else if (temp.equals("Gala"))
168+ known_gc_tf.setText("Gal-Gal");
169+ else if (temp.equals("Muco"))
170+ known_gc_tf.setText("Glc-Gal-Gal-Gal");
171+ else if (temp.equals("Arthro"))
172+ known_gc_tf.setText("Glc-Man-GlcNAc-GalNAc");
173+ else if (temp.equals("Mollu"))
174+ known_gc_tf.setText("Glc-Man-Man-GlcNAc");
175+ else
176+ {
177+ System.err.println("unknown glycolipd series:" + temp);
178+ known_gc_tf.setText("");
179+ }
180+ }
181+ });
182+ west_south_center.add(series_cb, gb2);
183+
184+ GridBagConstraints gb3 = new GridBagConstraints(); // 既知糖鎖組成入力部のラベル
185+ gb3.gridx = 0;
186+ gb3.gridy = 1;
187+ gb3.anchor = GridBagConstraints.WEST; // 左寄せ
188+ west_south_center.add(new JLabel("Known: "), gb3);
189+
190+ GridBagConstraints gb4 = new GridBagConstraints(); // 既知糖鎖組成入力部
191+ gb4.gridx = 1;
192+ gb4.gridy = 1;
193+ gb4.fill = GridBagConstraints.HORIZONTAL; // 水平方向のみに塗りつぶしを行う.
194+ gb4.weightx = 1.0; // 無いとレイアウトが崩れる.
195+ west_south_center.add(known_gc_tf, gb4);
196+
197+ GridBagConstraints gb5 = new GridBagConstraints(); // セラミド組成入力部のラベル
198+ gb5.gridx = 0;
199+ gb5.gridy = 2;
200+ gb5.anchor = GridBagConstraints.WEST; // 左寄せ
201+ west_south_center.add(new JLabel("Ceramide: "), gb5);
202+
203+ GridBagConstraints gb6 = new GridBagConstraints(); // セラミド組成入力部
204+ gb6.gridx = 1;
205+ gb6.gridy = 2;
206+ gb6.fill = GridBagConstraints.BOTH; // 垂直方向と水平方向の両方に対して塗りつぶしを行う.
207+ gb6.weightx = 1.0; // 無いとレイアウトが崩れる.
208+ west_south_center.add(new JScrollPane(ceramide_tf), gb6);
209+
210+ return west_south_center;
211+ }
212+
213+ /*
214+ * 計算機的な予測条件を設定する部分のJPanelを取得します.
215+ */
216+ protected JPanel getComputationalConditionJPanel()
217+ {
218+ byte[] bytes = {40, 99, 41, 32, 75, 97, 122, 117, 104, 105, 116, 111, 32, 89, 111, 107, 111, 105};
219+
220+ // スコアリング選択部分をBorderLayoutのNORTHとし,
221+ // 検索開始ボタンとリセットボタンをSOUTHとして返す.
222+ JPanel west_south_south_north = new JPanel(); // スコアリングの選択
223+ west_south_south_north.setLayout(new GridLayout(1, 2)); // 縦の数×横の数
224+
225+ JPanel west_south_south_south = new JPanel(); // 検索開始ボタンとリセットボタン
226+ west_south_south_south.setLayout(new GridLayout(1, 2)); // 縦の数×横の数
227+ start.addActionListener(this); // 検索開始ボタンにリスナを付ける.
228+ reset.addActionListener(this); // リセットボタンにリスナを付ける.
229+
230+ JLabel author = new JLabel(new String(bytes));
231+ author.setHorizontalAlignment(SwingConstants.CENTER);
232+ author.setForeground(Color.gray);
233+ west_south_south_south.add(author);
234+ west_south_south_south.add(start);
235+
236+ JPanel west_south_south = new JPanel(); // returnするJPanelインスタンス
237+ west_south_south.setLayout(new BorderLayout());
238+ west_south_south.add(west_south_south_north, BorderLayout.NORTH); // スコアリングの選択部分を追加
239+ west_south_south.add(west_south_south_south, BorderLayout.SOUTH); // 検索開始ボタンとリセットボタンを追加
240+
241+ return west_south_south;
242+ }
243+
244+ /*
245+ * 予測条件を設定する部分のJPanelを取得します.
246+ */
247+ protected JPanel getConditionJPanel()
248+ {
249+ JPanel west_south = new JPanel(); // 予測条件入力部 ウィンドウのWESTに貼り付けるパネルのSOUTH部
250+ // ウィンドウの左下
251+ west_south.setLayout(new BorderLayout());
252+
253+ west_south.add(getExperimentalConditionJPanel(), BorderLayout.NORTH); // 実験的な予測条件を設定
254+ west_south.add(getKnownConditionJPanel(), BorderLayout.CENTER); // 実験的な予測条件を設定
255+ west_south.add(getComputationalConditionJPanel(), BorderLayout.SOUTH); // 計算機的な予測条件を設定
256+
257+ return west_south;
258+ }
259+
260+ /*
261+ * 予測結果を出力する部分のJPanelを取得します.
262+ */
263+ protected JPanel getOutputJPanel()
264+ {
265+ JPanel center = new JPanel(); // 予想構造出力部
266+ center.setLayout(new BorderLayout()); // ウィンドウのCENTERに貼り付けるパネル(ウィンドウの右)
267+ this.resetTableColumnSize(); // カラム幅を指定する.
268+ JScrollPane result_sp = new JScrollPane(result_ta); // JTableへスクロールバーをつける.
269+ result_sp.addMouseListener(new MouseListener() // 表を右クリックすると印刷する.
270+ {
271+ public void mouseExited(MouseEvent me){}
272+ public void mouseEntered(MouseEvent me){}
273+ public void mousePressed(MouseEvent me){}
274+ public void mouseReleased(MouseEvent me){}
275+ public void mouseClicked(MouseEvent me)
276+ {
277+ if (me.getButton() == MouseEvent.BUTTON3) // 右クリック
278+ {
279+ try
280+ {
281+ result_ta.print(); // 印刷ダイアログを表示
282+ }
283+ catch (Exception e)
284+ {
285+ System.out.println("Cannot print: " + e);
286+ }
287+ }
288+ }
289+ });
290+ center.add(new JLabel("Result:"), BorderLayout.NORTH);
291+ center.add(result_sp, BorderLayout.CENTER);
292+
293+ return center;
294+ }
295+
296+ /*
297+ * テーブルのカラム幅を調節します.
298+ */
299+ protected void resetTableColumnSize()
300+ {
301+ DefaultTableCellRenderer tr = new DefaultTableCellRenderer(); // カラムを右寄せするインスタンス
302+ tr.setHorizontalAlignment(SwingConstants.RIGHT);
303+
304+ TableColumn tc0 = result_ta.getColumnModel().getColumn(0); // スコアのカラム(0番目)のサイズを固定
305+ tc0.setMinWidth(70);
306+ tc0.setMaxWidth(70);
307+ tc0.setCellRenderer(tr); // カラムを右寄せする
308+ // 候補構造のカラムはサイズを指定しない.
309+ TableColumn tc2 = result_ta.getColumnModel().getColumn(2); // 占有率のカラム(2番目)のサイズを固定
310+ tc2.setMinWidth(70);
311+ tc2.setMaxWidth(70);
312+ tc2.setCellRenderer(tr); // カラムを右寄せする
313+ TableColumn tc3 = result_ta.getColumnModel().getColumn(3); // m/zのカラム(3番目)のサイズを固定
314+ tc3.setMinWidth(80);
315+ tc3.setMaxWidth(80);
316+ tc3.setCellRenderer(tr); // カラムを右寄せする
317+ }
318+
319+ public PredictionGUI() throws Exception
320+ {
321+ jf.setLayout(new BorderLayout()); // ウィンドウへのコンポーネントの貼り付けは
322+ // BorderLayoutを用いる.
323+ JPanel west = new JPanel(); // ウィンドウのWESTに貼り付けるパネル(ウィンドウの左)
324+ west.setLayout(new BorderLayout());
325+ west.add(getInputJPanel(), BorderLayout.CENTER); // 実測値を入力する部分をWESTのCENTERに配置
326+ west.add(getConditionJPanel(), BorderLayout.SOUTH); // 予測条件を設定する部分をWESTのNORTHに配置
327+ jf.getContentPane().add(west, BorderLayout.WEST);
328+
329+ jf.getContentPane().add(getOutputJPanel(), BorderLayout.CENTER); // 予測結果を出力する部分をCENTERに配置
330+
331+ try // タスクトレイにアイコンを追加する.
332+ {
333+ SystemTray st = SystemTray.getSystemTray();
334+ ImageIcon ii = (ImageIcon)UIManager.getIcon("FileView.computerIcon"); // IconからImageIconへ型変換
335+ TrayIcon ti = new TrayIcon(ii.getImage());
336+ ti.addActionListener(new ActionListener() // トレイアイコンをダブルクリックすることで,
337+ { // ウィンドウの表示/非表示を切り替える.
338+ public void actionPerformed(ActionEvent e)
339+ {
340+ if (jf.isShowing()) // ウィンドウが表示されている場合は,
341+ jf.setVisible(false); // 非表示にする.
342+ else
343+ { // 表示されていない場合は,
344+ jf.setVisible(true); // 表示した後,
345+ jf.toFront(); // このウィンドウにフォーカスを当てる.
346+ }
347+ }
348+ });
349+ st.add(ti);
350+ }
351+ catch (Exception e)
352+ {
353+ System.err.println("Cannot use SystemTray: " + e);
354+ }
355+
356+ try // Swingから,Windowsのデザインへ変更
357+ {
358+ UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); // 外観を設定
359+ SwingUtilities.updateComponentTreeUI(jf); // 外観変更
360+ }
361+ catch (Exception e)
362+ {
363+ System.err.println("Cannot use WindowsLookAndFeel: " + e);
364+ }
365+
366+ jf.setSize(900,700);
367+ jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // ウインドウが閉じられた時に終了
368+ jf.setVisible(true); // 表示
369+ }
370+
371+ /*
372+ * Swingのアクションイベントが発生した時の動作を指定します.
373+ * @parm ae 取得したアクションイベント
374+ */
375+ public void actionPerformed(ActionEvent ae)
376+ {
377+ if (ae.getSource() == start) // Startボタンが押された時
378+ {
379+ DefaultTableModel tm = (DefaultTableModel)result_ta.getModel(); // テーブルモデルを取得し,
380+ tm.setRowCount(0); // 表の内容を削除する.
381+ start.setEnabled(false); // ボタンを押せなくする.
382+ reset.setEnabled(false);
383+
384+ try // ProgressMonitorのタイトルなどを
385+ { // 日本語から英語名に変更
386+ UIManager.put( "ProgressMonitor.progressText", "Progress Monitor" ); // ウィンドウ名
387+ UIManager.put( "OptionPane.cancelButtonText", "Cancel" ); // キャンセルボタン名
388+ }
389+ catch (Exception e)
390+ {
391+ System.err.println("ProgressMonitor connot edit: " + e);
392+ }
393+ // 表示する文字列のテンプレート
394+ String length = "Creating candidate compositions from precursor and fragment mass.";
395+ pm = new ProgressMonitor(jf, "Calculating...", length, 0, 100); // 進捗バー
396+ pm.setMillisToDecideToPopup(0);
397+ pm.setMillisToPopup(0);
398+ pm.setProgress(0); // 監視対象インスタンスから変数を取得
399+ Thread th = new Thread(this);
400+ th.start();
401+ }
402+ else if (ae.getSource() == reset) // Resetボタンが押された時
403+ {
404+ query_ta.setText(""); // フラグメント分子量の内容を削除
405+ DefaultTableModel tm = (DefaultTableModel)result_ta.getModel(); // テーブルモデルを取得し,
406+ tm.setRowCount(0); // 表の内容を削除する.
407+ }
408+ }
409+
410+ /*
411+ * 監視対象が更新された時の動作を指定します.
412+ * @parm ae 取得したアクションイベント
413+ */
414+ public void update(Observable ob, Object arg)
415+ {
416+ if (ob instanceof Prediction) // Predictionクラスのインスタンスかを判定
417+ {
418+ Prediction temp = (Prediction)ob; // Observableインスタンスを型変換する.
419+ pm.setProgress(temp.percent); // 監視対象インスタンスから変数を取得
420+ pm.setNote(arg.toString()); // 進捗情報の表示
421+
422+ StringBuilder line = new StringBuilder(32); // コマンドラインに表示する文字列
423+ MemoryMXBean mm = ManagementFactory.getMemoryMXBean();
424+ MemoryUsage mu = mm.getHeapMemoryUsage();
425+ line.append(" Memory: ");
426+ line.append(String.format("%.1f/", mu.getUsed() / 1024.0 / 1024));
427+ line.append(String.format("%.1fMB", mu.getMax() / 1024.0 / 1024));
428+
429+ System.out.println(arg + " " + line); // 進捗情報の表示
430+
431+ if (pm.isCanceled()) // ProgressMonitorの
432+ { // キャンセルボタンが押された時
433+ pm.close(); // ProgressMonitorウィンドウを閉じる.
434+ temp.flag = false; // 断片化処理を抜ける.
435+ }
436+ }
437+ else
438+ System.out.println("ERROR: unknown incetance of observerable class.");
439+ }
440+
441+ /*
442+ * Startをクリックした時に実行されるスレッド
443+ */
444+ public void run()
445+ {
446+ try
447+ {
448+ Prediction pd_agg = new Prediction(); // 継承の代わりに集約を用いる.
449+ pd_agg.addObserver(this); // 進行状況をこのクラスへ伝えるために,このクラスをオブザーバとする.
450+ // テキストエリアから実測値を取得
451+ String[] strs = query_ta.getText().split("[^\\.\\d]"); // '.'と数字以外の文字列で切り出す.
452+ java.util.List<Double> massli = new ArrayList<Double>();
453+ for (String str : strs)
454+ {
455+ try
456+ {
457+ massli.add(Double.parseDouble(str));
458+ }
459+ catch (Exception e) // 数字以外の文字が入っていた場合の時,
460+ { // 無視したことを報告する.
461+ System.err.println(e);
462+ }
463+ }
464+ double[] frags = new double[massli.size()]; // Listと同じ大きさの配列を用意する.
465+ Iterator<Double> massit = massli.iterator();
466+ for (int i = 0; massit.hasNext(); i++) // double[]型のfragsへ配列の型変換
467+ frags[i] = massit.next();
468+ pd_agg.setFragments(frags); // フラグメントの実測値の配列を登録
469+
470+ try // プレカーサーマスを登録
471+ {
472+ pd_agg.setPrecursorMass(Double.parseDouble(precursor_mass_tf.getText()));
473+ }
474+ catch (Exception e) // プレカーサーマスを登録しなかった場合,
475+ { // PSDフラグメントの最大値をプレカーサーマスとして計算
476+ System.err.println("Precursor mass is null.");
477+ }
478+
479+ try // プレカーサーマスの許容誤差を登録
480+ {
481+ pd_agg.setMsTolerance(Double.parseDouble(precursor_tolerance_tf.getText())); // 許容誤差を格納
482+ }
483+ catch (Exception e)
484+ {
485+ throw new Exception("'Precursor tolerance' contains error.\n" + e);
486+ }
487+
488+ try // PSDフラグメントの許容誤差を登録
489+ {
490+ pd_agg.setPsdTolerance(Double.parseDouble(psd_tolerance_tf.getText())); // 許容誤差を格納
491+ }
492+ catch (Exception e)
493+ {
494+ throw new Exception("'PSD tolerance' contains error.\n" + e);
495+ }
496+
497+ try // 付加イオンを登録
498+ { // 選択された付加イオンを取得する.
499+ String temp = (String)adduct_cb.getSelectedItem(); // 表の部分でm/zを取得するのに必要なため,
500+ if (temp.equals("Na+")) // adductはグローバル変数としている.
501+ adduct = MassCalc.Na_ION;
502+ else if (temp.equals("H+"))
503+ adduct = MassCalc.H_ION;
504+ else if (temp.equals("Li+"))
505+ adduct = MassCalc.Li_ION;
506+ else if (temp.equals("K+"))
507+ adduct = MassCalc.K_ION;
508+ else if (temp.equals("H-"))
509+ adduct = MassCalc.H_NION;
510+ else if (temp.equals("No adduct"))
511+ adduct = "";
512+ else
513+ throw new Exception(temp + " is unknown adduct ion.");
514+
515+ pd_agg.setAdduct(adduct);
516+ }
517+ catch (Exception e)
518+ {
519+ throw new Exception("'Adduct ion' contains error.\n" + e);
520+ }
521+
522+ try // 既知構造を登録
523+ {
524+ pd_agg.setGlycan(new Glycan(known_gc_tf.getText())); // Linucs形式から既知構造を登録
525+ }
526+ catch (Exception e1) // Linucs形式の読み込みに失敗した場合,
527+ { // ノーマル形式の読み込みを試す.
528+ try
529+ {
530+ GlycanTools gi = new GlycanTools();
531+ pd_agg.setGlycan(gi.readNormalFormat(known_gc_tf.getText())); // 既知構造を登録
532+ }
533+ catch (Exception e2)
534+ {
535+ throw new Exception("'Known structure' contains error.\n" + e1 + e2);
536+ }
537+ }
538+
539+ try // 各糖の最大数を登録
540+ {
541+ pd_agg.setMax("pen", ((String)pen_cb.getSelectedItem()).equals("Yes"));
542+ pd_agg.setMax("dhex", ((String)dhex_cb.getSelectedItem()).equals("Yes"));
543+ pd_agg.setMax("hex", ((String)hex_cb.getSelectedItem()).equals("Yes"));
544+ pd_agg.setMax("hexnac", ((String)hexnac_cb.getSelectedItem()).equals("Yes"));
545+ pd_agg.setMax("penme", ((String)penme_cb.getSelectedItem()).equals("Yes"));
546+ pd_agg.setMax("dhexme", ((String)dhexme_cb.getSelectedItem()).equals("Yes"));
547+ pd_agg.setMax("hexme", ((String)hexme_cb.getSelectedItem()).equals("Yes"));
548+ pd_agg.setMax("hexnacme", ((String)hexnacme_cb.getSelectedItem()).equals("Yes"));
549+ }
550+ catch (Exception e)
551+ {
552+ throw new Exception("'max' contains error.\n" + e);
553+ }
554+
555+ try // セラミド組成を登録
556+ {
557+ java.util.List<String> ceramide = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
558+ java.util.List<String> lcb = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
559+ java.util.List<String> fa = new ArrayList<String>(); // 既知の脂肪酸組成を格納する.
560+
561+ for (String str : ceramide_tf.getText().split("[^\\w:-]")) // 単語構成文字と':','-'以外の文字列で分割
562+ if (str.matches("^[dt][ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // セラミドの場合
563+ ceramide.add(str);
564+ else if (str.matches("^[dt][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 長鎖塩基の場合
565+ lcb.add(str);
566+ else if (str.matches("^[ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 脂肪酸の場合
567+ fa.add(str);
568+
569+ pd_agg.setCeramide(ceramide); // セラミド組成を登録
570+ pd_agg.setLongChainBase(lcb); // 長鎖塩基組成を登録
571+ pd_agg.setFattyAcid(fa); // 脂肪酸組成を登録
572+ }
573+ catch (Exception e)
574+ {
575+ throw new Exception("'Ceramide' contains error.\n" + e);
576+ }
577+
578+ try // スコアリングの式を登録
579+ {
580+ String temp = (String)formula_cb.getSelectedItem(); // 選択されたスコアリング式を取得
581+ if (temp.equals("POSITIVE"))
582+ pd_agg.setScoringFormula(Candidate.POSITIVE_SCORING);
583+ else if (temp.equals("TFIDF"))
584+ pd_agg.setScoringFormula(Candidate.TFIDF_SCORING);
585+ else if (temp.equals("PENALTY01"))
586+ pd_agg.setScoringFormula(Candidate.PENALTY01_SCORING);
587+ else if (temp.equals("PENALTY001"))
588+ pd_agg.setScoringFormula(Candidate.PENALTY001_SCORING);
589+ else if (temp.equals("PMF"))
590+ pd_agg.setScoringFormula(Candidate.PMF_SCORING);
591+ else if (temp.equals("GEOMETRICAVG"))
592+ pd_agg.setScoringFormula(Candidate.GEOMETRICAVG_SCORING);
593+ else
594+ throw new Exception(temp + " is unknown adduct ion.");
595+ }
596+ catch (Exception e)
597+ {
598+ throw new Exception("'Scoring' contains error.\n" + e);
599+ }
600+
601+ try // 出現確率分布の
602+ { // ウィンドウサイズを登録
603+ pd_agg.setWindowSize(1);
604+ }
605+ catch (Exception e)
606+ {
607+ throw new Exception("'Window size' contains error.\n" + e);
608+ }
609+
610+ java.util.List<? extends Candidate> cds = pd_agg.getPrediction(); // 出力部
611+ Iterator<? extends Candidate> it = cds.iterator();
612+ DefaultTableModel tm = new DefaultTableModel(title, 0);
613+ for (int i = 0; i < 50 && it.hasNext(); i++) // 上位50候補を表示
614+ {
615+ Candidate cd = it.next();
616+
617+ String[] table = new String[4]; // カラムの追加時は,
618+ table[0] = String.format("%.4f", cd.getScore()); // 配列の大きさに注意
619+
620+ try
621+ {
622+ table[1] = cd.toNormalFormat(); // ノーマルのフォーマットで格納
623+ }
624+ catch (Exception e)
625+ {
626+ table[1] = cd.toString(); // 二分岐以上はLinucs形式で格納
627+ }
628+
629+ table[2] = String.format("%.4f", cd.getOccupancy());
630+ table[3] = String.format("%.4f", cd.getMass(monoavg, adduct));
631+ tm.addRow(table);
632+ }
633+ result_ta.setModel(tm);
634+ RowSorter<TableModel> rs = new TableRowSorter<TableModel>(tm); // ソート可能なテーブルにする.
635+ result_ta.setRowSorter(rs);
636+ this.resetTableColumnSize(); // カラム幅を指定する.
637+
638+ java.awt.Toolkit.getDefaultToolkit().beep(); // 終了する時にビープ音を鳴らす.
639+
640+ UIManager.put("OptionPane.messageDialogTitle", "Messege"); // "タイトルを"Messege"に変更する.
641+ UIManager.put("OptionPane.okButtonText", "OK"); // "了解"の部分を"OK"に変更する.
642+
643+ JOptionPane.showMessageDialog(jf, "Calclation is finished.\n"
644+ + pm.getNote() + "\n"
645+ + "Candidate structure: " + cds.size());
646+ start.setEnabled(true); // ボタンを押せるようにする.
647+ reset.setEnabled(true);
648+ }
649+ catch (Exception e) // 処理の途中で例外が発生した場合,
650+ { // 警告ダイアログを表示し処理を中断
651+ UIManager.put("OptionPane.messageDialogTitle", "Messege"); // "タイトルを"Messege"に変更する.
652+ UIManager.put("OptionPane.okButtonText", "OK"); // "了解"の部分を"OK"に変更する.
653+ JOptionPane.showMessageDialog(jf, "ERROR: " + e);
654+ e.printStackTrace();
655+ start.setEnabled(true); // ボタンを押せるようにする.
656+ reset.setEnabled(true);
657+ }
658+ }
659+
660+ public static void main(String[] args) throws Exception
661+ {
662+ new PredictionGUI();
663+ }
664+}
--- jp/ac/ritsumei/is/infobio/CompositionToolsMe.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/CompositionToolsMe.java (revision 1)
@@ -0,0 +1,314 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+import java.io.*;
5+
6+/**
7+ * 実測の<I>m/z</I> からメチル化糖鎖,メチル化糖脂質の組成を予測するクラスです.
8+ * @author 横井一仁
9+ * @version 20090128
10+ */
11+public class CompositionToolsMe extends CompositionTools
12+{
13+ /**
14+ * 予測された組成を返します.
15+ * @return 質量誤差の少ない順に格納して返します.
16+ */
17+ public List<Composition> getComposition() throws Exception
18+ {
19+ al_cp.clear(); // クラスの再利用の時のために要素を全て削除する.
20+
21+ Composition cp = new Composition();
22+ if (known_cp != null) // 既知組成が登録されている場合
23+ cp.addAll(known_cp);
24+ else if (known_gc != null) // 既知構造が登録されている場合
25+ cp.addAll(new Composition(known_gc));
26+
27+ // 継承による変更部分
28+ Composition temp_me = new Composition(cp); // 新たなインスタンスを作成する.
29+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
30+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
31+ temp_me.add("me");
32+ double mass_t = temp_me.getMass(monoavg, adduct);
33+ // 継承による変更部分(ここまで)
34+
35+ if (ceramide != null && ceramide.size() != 0) // セラミドが登録されている場合
36+ {
37+ if (mass_a > mass_t)
38+ addCer(cp); // セラミドから検索する.
39+ }
40+ else // セラミドが登録されていない場合は,糖鎖モードとする.
41+ {
42+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
43+ al_cp.add(cp);
44+ else if (mass_a > mass_t)
45+ addHex(cp); // Hexから検索する.
46+ }
47+
48+ final double temp_a = mass_a; // 内部クラスで用いる変数は,finalで宣言する必要がある.
49+ Collections.sort(al_cp, new Comparator<Composition>() // ソートを行う.
50+ {
51+ public int compare(Composition cp1, Composition cp2)
52+ {
53+ double sub = 0.0;
54+
55+ try
56+ {
57+ Composition temp1 = new Composition(cp1); // 新たなインスタンスを作成する.
58+ int count1 = temp1.countHydroxy(); // メチル基が附加できるOH基の数を数える.
59+ for (int i = 0; i < count1; i++) // OH基の数だけMe基を付加する.
60+ temp1.add("me");
61+
62+ Composition temp2 = new Composition(cp2); // 新たなインスタンスを作成する.
63+ int count2 = temp2.countHydroxy(); // メチル基が附加できるOH基の数を数える.
64+ for (int i = 0; i < count2; i++) // OH基の数だけMe基を付加する.
65+ temp2.add("me");
66+
67+ sub = Math.abs(temp1.getMass(monoavg, adduct) - temp_a)
68+ - Math.abs(temp2.getMass(monoavg, adduct) - temp_a);
69+ }
70+ catch (Exception e)
71+ {
72+
73+ }
74+
75+ return (int)(sub*1024); // compareメソッドの返り値がint型しか受け付けないので1024倍して精度を上げる.
76+ }
77+ });
78+
79+ ceramide.clear(); // 次回の実行する時に同じ組成を2回追加しないように
80+ lcb.clear(); // 既知のセラミド組成,長鎖塩基組成,脂肪酸組成を削除しておく.
81+ fa.clear(); // (これにより,次回実行時に通常通りセラミドを追加できる)
82+
83+ return al_cp;
84+ }
85+
86+ protected void addCer(Composition cp) throws Exception
87+ {
88+ for (String str : ceramide)
89+ {
90+ Composition temp = new Composition(str); // セラミドを登録.
91+ temp.addAll(cp);
92+
93+ // 継承による変更部分
94+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
95+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
96+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
97+ temp_me.add("me");
98+ double mass_t = temp_me.getMass(monoavg, adduct);
99+ // 継承による変更部分(ここまで)
100+
101+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
102+ al_cp.add(temp);
103+ else
104+ addHex(temp);
105+ }
106+ }
107+
108+ protected void addHex(Composition cp) throws Exception
109+ {
110+ addHexNAc(cp); // HexNAcを追加した構造
111+
112+ Composition temp = new Composition(cp);
113+ if (Collections.frequency(temp,"hex") < hex_max) // 要素を探索し,個数を数える.
114+ {
115+ temp.add("hex");
116+
117+ // 継承による変更部分
118+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
119+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
120+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
121+ temp_me.add("me");
122+ double mass_t = temp_me.getMass(monoavg, adduct);
123+ // 継承による変更部分(ここまで)
124+
125+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
126+ al_cp.add(temp);
127+ else if (mass_a > mass_t)
128+ addHex(temp);
129+ }
130+ }
131+
132+ protected void addHexNAc(Composition cp) throws Exception
133+ {
134+ adddHex(cp); // dHexを追加した構造
135+
136+ Composition temp = new Composition(cp);
137+ if (Collections.frequency(temp,"hexnac") < hexnac_max) // 要素を探索し,個数を数える.
138+ {
139+ temp.add("hexnac");
140+
141+ // 継承による変更部分
142+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
143+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
144+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
145+ temp_me.add("me");
146+ double mass_t = temp_me.getMass(monoavg, adduct);
147+ // 継承による変更部分(ここまで)
148+
149+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
150+ al_cp.add(temp);
151+ else if (mass_a > mass_t)
152+ addHexNAc(temp);
153+ }
154+ }
155+
156+ protected void adddHex(Composition cp) throws Exception
157+ {
158+ addPen(cp); // dHexMeを追加した構造
159+
160+ Composition temp = new Composition(cp);
161+ if (Collections.frequency(cp,"dhex") < dhex_max) // 要素を探索し,個数を数える.
162+ {
163+ temp.add("dhex");
164+
165+ // 継承による変更部分
166+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
167+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
168+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
169+ temp_me.add("me");
170+ double mass_t = temp_me.getMass(monoavg, adduct);
171+ // 継承による変更部分(ここまで)
172+
173+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
174+ al_cp.add(temp);
175+ else if (mass_a > mass_t)
176+ adddHex(temp);
177+ }
178+ }
179+
180+ protected void addPen(Composition cp) throws Exception
181+ {
182+ addKDN(cp); // KDNを追加した構造
183+
184+ Composition temp = new Composition(cp);
185+ if (Collections.frequency(temp,"pen") < pen_max) // 要素を探索し,個数を数える.
186+ {
187+ temp.add("pen");
188+
189+ // 継承による変更部分
190+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
191+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
192+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
193+ temp_me.add("me");
194+ double mass_t = temp_me.getMass(monoavg, adduct);
195+ // 継承による変更部分(ここまで)
196+
197+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
198+ al_cp.add(temp);
199+ else if (mass_a > mass_t)
200+ addPen(temp);
201+ }
202+ }
203+
204+ protected void addKDN(Composition cp) throws Exception
205+ {
206+ addNeuAc(cp); // NeuAcを追加した構造
207+
208+ Composition temp = new Composition(cp);
209+ if (Collections.frequency(temp,"kdn") < kdn_max) // 要素を探索し,個数を数える.
210+ {
211+ temp.add("kdn");
212+
213+ // 継承による変更部分
214+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
215+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
216+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
217+ temp_me.add("me");
218+ double mass_t = temp_me.getMass(monoavg, adduct);
219+ // 継承による変更部分(ここまで)
220+
221+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
222+ al_cp.add(temp);
223+ else if (mass_a > mass_t)
224+ addKDN(temp);
225+ }
226+ }
227+
228+ protected void addNeuAc(Composition cp) throws Exception
229+ {
230+ addNeuGc(cp); // NeuGcを追加した構造
231+
232+ Composition temp = new Composition(cp);
233+ if (Collections.frequency(cp,"neuac") < neuac_max) // 要素を探索し,個数を数える.
234+ {
235+ temp.add("neuac");
236+
237+ // 継承による変更部分
238+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
239+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
240+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
241+ temp_me.add("me");
242+ double mass_t = temp_me.getMass(monoavg, adduct);
243+ // 継承による変更部分(ここまで)
244+
245+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
246+ al_cp.add(temp);
247+ else if (mass_a > mass_t)
248+ addNeuAc(temp);
249+ }
250+ }
251+
252+ protected void addNeuGc(Composition cp) throws Exception
253+ {
254+ Composition temp = new Composition(cp);
255+
256+ if (Collections.frequency(temp,"neugc") < neugc_max) // 要素を探索し,個数を数える.
257+ {
258+ temp.add("neugc");
259+
260+ // 継承による変更部分
261+ Composition temp_me = new Composition(temp); // 新たなインスタンスを作成する.
262+ int count = temp_me.countHydroxy(); // メチル基が附加できるOH基の数を数える.
263+ for (int i = 0; i < count; i++) // OH基の数だけMe基を付加する.
264+ temp_me.add("me");
265+ double mass_t = temp_me.getMass(monoavg, adduct);
266+ // 継承による変更部分(ここまで)
267+
268+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
269+ al_cp.add(temp);
270+ else if (mass_a > mass_t)
271+ addNeuGc(temp);
272+ }
273+ }
274+
275+ /**
276+ * メチル化糖の組成予測テスト
277+ */
278+ private static void testPermetylatedGlycan() throws Exception
279+ {
280+ CompositionToolsMe cm = new CompositionToolsMe();
281+ cm.setCeramide(30, 44, 0);
282+ cm.setMass(1746.0537);
283+ for (Composition cp : cm.getComposition())
284+ System.out.println(cp);
285+ }
286+
287+ /**
288+ * メチル化したガングリオシドの組成予測テスト
289+ */
290+ private static void testPermethylatedGanglioside(double mass) throws Exception
291+ {
292+ double start = new Date().getTime();
293+
294+ CompositionToolsMe ci = new CompositionToolsMe();
295+ ci.setMsTolerance(0.5);
296+ ci.setComposition(new Composition("neuac"));
297+ ci.setCeramide(30, 44, 0);
298+ ci.setMass(mass);
299+ ci.setMax("hex", true); // 各糖の有無を指定する.
300+ ci.setMax("hexnac", true);
301+ ci.setMax("dhex", true);
302+ ci.setMax("pen", true);
303+ ci.setMax("kdn", false);
304+ ci.setMax("neuac", true);
305+ ci.setMax("neugc", false);
306+
307+ List<Composition> li = ci.getComposition();
308+ for (Composition cp : li)
309+ System.out.println(cp);
310+
311+ System.out.println("予測組成数: " + li.size());
312+ System.out.println("計算時間: " + (new Date().getTime() - start)/1000 + "sec");
313+ }
314+}
--- jp/ac/ritsumei/is/infobio/CompositionServlet.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/CompositionServlet.java (revision 1)
@@ -0,0 +1,444 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+import java.io.*;
5+import javax.servlet.*;
6+import javax.servlet.http.*;
7+
8+/**
9+ * 実測の<I>m/z</I> から糖鎖,糖脂質の組成を予測するServletクラスです.
10+ * @author 横井一仁
11+ * @version 20090102
12+ */
13+public class CompositionServlet extends HttpServlet
14+{
15+ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
16+ {
17+ response.setContentType("text/html");
18+ PrintWriter out = response.getWriter();
19+
20+ try
21+ {
22+ double mass_a, tolerance; // 実測m/z,許容誤差
23+ Composition known_cp; // 既知組成
24+ String adduct; // 付加イオン(デフォルトはNa+)
25+ boolean monoavg; // Monoisotopic(ture),Averaget(false)
26+ boolean present_hex, present_hexnac, present_dhex, present_pen; // 各糖の存在
27+ boolean present_hexme, present_hexnacme, present_dhexme, present_penme; // 各糖の存在
28+ int select; // 0…セラミド組成により計算,1…セラミドの炭素数により計算,2…糖鎖のみの分子として計算
29+ String known_cer; // セラミド組成を格納する.(セラミド,長鎖塩基,脂肪酸の区別はしない)
30+
31+ try
32+ {
33+ mass_a = Double.parseDouble(request.getParameter("mass_a")); // 引数がない場合の初期値
34+
35+ if (mass_a > 3000) // m/z3000以上は計算しない
36+ mass_a = 0;
37+ }
38+ catch (Exception e)
39+ {
40+ mass_a = 1493.8;
41+ }
42+ try
43+ {
44+ tolerance = Double.parseDouble(request.getParameter("tolerance"));
45+ }
46+ catch (Exception e)
47+ {
48+ tolerance = 1.0;
49+ }
50+ try
51+ {
52+ String temp = request.getParameter("known_cp");
53+ try
54+ {
55+ known_cp = new Composition(new Glycan(temp)); // Linucs形式として格納してみる.
56+ }
57+ catch (Exception e)
58+ {
59+ known_cp = new Composition(temp); // Linucs形式の格納に失敗したら,組成として格納
60+ }
61+ }
62+ catch (Exception e)
63+ {
64+ known_cp = new Composition("hex");
65+ }
66+ try
67+ {
68+ adduct = request.getParameter("adduct");
69+
70+ if (adduct == null) // 何も指定されなかった場合,
71+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
72+ }
73+ catch (Exception e)
74+ {
75+ adduct = MassCalc.Na_ION; // 左のイオンを初期付加イオンとする.
76+ }
77+ try
78+ {
79+ String temp = request.getParameter("monoavg");
80+ if (temp.equals("mono"))
81+ monoavg = true;
82+ else if (temp.equals("avg"))
83+ monoavg = false;
84+ else
85+ monoavg = true; // その他の場合Monoisotopicとする.
86+ }
87+ catch (Exception e)
88+ {
89+ monoavg = true; // その他の場合Monoisotopicとする.
90+ }
91+ try
92+ {
93+ present_pen = request.getParameter("present_pen").equals("yes");
94+ present_dhex = request.getParameter("present_dhex").equals("yes");
95+ present_hex = request.getParameter("present_hex").equals("yes");
96+ present_hexnac = request.getParameter("present_hexnac").equals("yes");
97+ present_penme = request.getParameter("present_penme").equals("yes");
98+ present_dhexme = request.getParameter("present_dhexme").equals("yes");
99+ present_hexme = request.getParameter("present_hexme").equals("yes");
100+ present_hexnacme = request.getParameter("present_hexnacme").equals("yes");
101+ }
102+ catch (Exception e)
103+ {
104+ present_pen = false; // 各糖が存在するかしないかを指定
105+ present_dhex = true;
106+ present_hex = true;
107+ present_hexnac = true;
108+ present_penme = false;
109+ present_dhexme = false;
110+ present_hexme = false;
111+ present_hexnacme = false;
112+ }
113+ try
114+ { // 0…セラミド組成により計算,1…セラミドの炭素数により計算,2…糖鎖のみの分子として計算
115+ select = Integer.parseInt(request.getParameter("select"));
116+ }
117+ catch (Exception e)
118+ {
119+ select = 0; // その他の場合は,セラミド付きの糖脂質として計算する.
120+ }
121+ try
122+ {
123+ known_cer = request.getParameter("known_cer").toLowerCase(); // 小文字にする("C12:0"->"c12:0")
124+
125+ if (known_cer == null)
126+ known_cer = "d14-20:1, c12-26:0,\nt14-20:0, h12-26:0";
127+ }
128+ catch (Exception e)
129+ {
130+ known_cer = "d14-20:1, c12-26:0,\nt14-20:0, h12-26:0";
131+ }
132+
133+ out.println("<HTML><HEAD><TITLE>Composition Predictor</TITLE></HEAD><BODY>"); // 入力部
134+ out.println("<FONT SIZE=+2>Composition Predictor</FONT><BR><BR>");
135+ out.println("<FORM>");
136+ out.println("Measured <I>m/z</I> : <INPUT TYPE=text NAME=mass_a VALUE=" + mass_a + " SIZE=16>");
137+ out.println("Tolerance (Da): <INPUT TYPE=text NAME=tolerance VALUE=" + tolerance + " SIZE=4>");
138+
139+ out.println("Adduct ion: <SELECT NAME=adduct>"+adduct); // 前回の内容を初期値とする.
140+ if (adduct.equals(MassCalc.Na_ION))
141+ out.println("<OPTION VALUE="+MassCalc.Na_ION+" SELECTED>Na+");
142+ else
143+ out.println("<OPTION VALUE="+MassCalc.Na_ION+">Na+");
144+ if (adduct.equals(MassCalc.H_ION))
145+ out.println("<OPTION VALUE="+MassCalc.H_ION+" SELECTED>H+");
146+ else
147+ out.println("<OPTION VALUE="+MassCalc.H_ION+">H+");
148+ if (adduct.equals(MassCalc.Li_ION))
149+ out.println("<OPTION VALUE="+MassCalc.Li_ION+" SELECTED>Li+");
150+ else
151+ out.println("<OPTION VALUE="+MassCalc.Li_ION+">Li+");
152+ if (adduct.equals(MassCalc.K_ION))
153+ out.println("<OPTION VALUE="+MassCalc.K_ION+" SELECTED>K+");
154+ else
155+ out.println("<OPTION VALUE="+MassCalc.K_ION+">K+");
156+ if (adduct.equals(MassCalc.H_NION))
157+ out.println("<OPTION VALUE="+MassCalc.H_NION+" SELECTED>H-");
158+ else
159+ out.println("<OPTION VALUE="+MassCalc.H_NION+">H-");
160+ if (adduct.equals(""))
161+ out.println("<OPTION VALUE='' SELECTED>No adduct (Molecular weight)");
162+ else
163+ out.println("<OPTION VALUE=''>No adduct (Molecular weight)");
164+ out.println("</SELECT>");
165+
166+ out.println("Mass mode: <SELECT NAME=monoavg>");
167+ if (monoavg)
168+ {
169+ out.println("<OPTION VALUE=mono SELECTED>Monoisotopic");
170+ out.println("<OPTION VALUE=avg>Average");
171+ }
172+ else
173+ {
174+ out.println("<OPTION VALUE=mono>Monoisotopic");
175+ out.println("<OPTION VALUE=avg SELECTED>Average");
176+ }
177+ out.println("</SELECT><BR>");
178+
179+
180+ out.println("Known composition: <INPUT TYPE=text NAME=known_cp VALUE='" + known_cp + "' SIZE=64><BR><BR>");
181+
182+ out.println("Monosaccharide residues present<BR>");
183+
184+ out.println("Pen: <SELECT NAME=present_pen>"); // Penの存在を指定
185+ if (present_pen)
186+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
187+ else
188+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
189+ out.println("</SELECT>");
190+
191+ out.println("dHex: <SELECT NAME=present_dhex>"); // dHexの存在を指定
192+ if (present_dhex)
193+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
194+ else
195+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
196+ out.println("</SELECT>");
197+
198+ out.println("Hex: <SELECT NAME=present_hex>"); // Hexの存在を指定
199+ if (present_hex)
200+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
201+ else
202+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
203+ out.println("</SELECT>");
204+
205+ out.println("HexNAc: <SELECT NAME=present_hexnac>"); // HexNAcの存在を指定
206+ if (present_hexnac)
207+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
208+ else
209+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
210+ out.println("</SELECT>");
211+
212+ out.println("PenMe: <SELECT NAME=present_penme>"); // PenMeの存在を指定
213+ if (present_penme)
214+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
215+ else
216+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
217+ out.println("</SELECT>");
218+
219+ out.println("dHexMe: <SELECT NAME=present_dhexme>"); // dHexMeの存在を指定
220+ if (present_dhexme)
221+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
222+ else
223+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
224+ out.println("</SELECT>");
225+
226+ out.println("HexMe: <SELECT NAME=present_hexme>"); // HexMeの存在を指定
227+ if (present_hexme)
228+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
229+ else
230+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
231+ out.println("</SELECT>");
232+
233+ out.println("HexNAcMe: <SELECT NAME=present_hexnacme>"); // HexNAcMeの存在を指定
234+ if (present_hexnacme)
235+ out.println("<OPTION VALUE=yes SELECTED>Yes\n<OPTION VALUE=no>No");
236+ else
237+ out.println("<OPTION VALUE=yes>Yes\n<OPTION VALUE=no SELECTED>No");
238+ out.println("</SELECT>");
239+
240+ out.println("<BR><BR>");
241+
242+ // セラミド組成入力部
243+ if (select == 0) // 0ならば,セラミド組成により計算する.
244+ out.println("<INPUT TYPE=radio NAME=select VALUE=0 CHECKED>Ceramide composition: ");
245+ else
246+ out.println("<INPUT TYPE=radio NAME=select VALUE=0>Ceramide composition: ");
247+
248+ out.println("<TEXTAREA NAME=known_cer ROWS=4 COLS=36>" + known_cer + "</TEXTAREA><BR>");
249+
250+ if (select == 2) // 2ならば,糖鎖のみの分子として計算する.
251+ out.println("<INPUT TYPE=radio NAME=select VALUE=2 CHECKED>Glycan only<BR>");
252+ else
253+ out.println("<INPUT TYPE=radio NAME=select VALUE=2>Glycan only<BR>");
254+
255+ out.println("<INPUT TYPE=submit>");
256+ out.println("</FORM>");
257+
258+ // m/z1700以上はモノアイソトピックマスを正しく選択しているかを警告する.
259+ if (mass_a > 1700)
260+ out.println("<FONT color=red>Confirm measured <I>m/z</I> is monoisotopic mass.</FONT><BR><BR>");
261+
262+ out.println("<B>Predicted Compositions</B><BR><TABLE border=1>"); // 表示部
263+ out.print("<TR>");
264+ out.print("<TH>Calculated <I>m/z</I></TH>");
265+ out.print("<TH>+-</TH>");
266+ out.print("<TH>Modif</TH>");
267+ out.print("<TH>Ceramide</TH>");
268+ if (present_pen || known_cp.contains("pen")) // 条件で指定した糖のみを表示する.
269+ out.print("<TH>Pen</TH>");
270+ if (present_dhex || known_cp.contains("dhex"))
271+ out.print("<TH>dHex</TH>");
272+ if (present_hex || known_cp.contains("hex"))
273+ out.print("<TH>Hex</TH>");
274+ if (present_hexnac || known_cp.contains("hexnac"))
275+ out.print("<TH>HexNAc</TH>");
276+ if (present_penme || known_cp.contains("penme"))
277+ out.print("<TH>PenMe</TH>");
278+ if (present_dhexme || known_cp.contains("dhexme"))
279+ out.print("<TH>dHexMe</TH>");
280+ if (present_hexme || known_cp.contains("hexme"))
281+ out.print("<TH>HexMe</TH>");
282+ if (present_hexnacme || known_cp.contains("hexnacme"))
283+ out.print("<TH>HexNAcMe</TH>");
284+
285+ out.print("<TH>Total</TH>");
286+ out.print("<TD>Permethylated <I>m/z</I></TD>");
287+ out.print("<TD>Possible series</TD>");
288+ out.println("</TR>");
289+
290+ CompositionTools ci = new CompositionTools();
291+ ci.setComposition(known_cp);
292+ ci.setMsTolerance(tolerance);
293+ ci.setMass(mass_a);
294+ ci.setMonoavg(monoavg); // モノアイソトピックマスで計算するか,アベレージで計算するかを指定
295+ ci.setAdduct(adduct); // 付加イオンを指定
296+ ci.setMax("pen", present_pen); // 各糖の最大値を設定する.
297+ ci.setMax("dhex", present_dhex);
298+ ci.setMax("hex", present_hex);
299+ ci.setMax("hexnac", present_hexnac);
300+ ci.setMax("penme", present_penme);
301+ ci.setMax("dhexme", present_dhexme);
302+ ci.setMax("hexme", present_hexme);
303+ ci.setMax("hexnacme", present_hexnacme);
304+
305+ if (select == 0) // 0ならば,セラミド組成により計算する.
306+ {
307+ List<String> ceramide = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
308+ List<String> lcb = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
309+ List<String> fa = new ArrayList<String>(); // 既知の脂肪酸組成を格納する.
310+
311+ for (String str : known_cer.split("[^\\w:-]")) // 単語構成文字と':','-'以外の文字列で分割
312+ if (str.matches("^[dt][ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // セラミドの場合
313+ ceramide.add(str);
314+ else if (str.matches("^[dt][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 長鎖塩基の場合
315+ lcb.add(str);
316+ else if (str.matches("^[ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 脂肪酸の場合
317+ fa.add(str);
318+
319+ ci.setCeramide(ceramide); // セラミド組成を登録
320+ ci.setLongChainBase(lcb); // 長鎖塩基組成を登録
321+ ci.setFattyAcid(fa); // 脂肪酸組成を登録
322+ }
323+
324+ for (Composition cp : ci.getComposition())
325+ {
326+ Composition cp_hex = new Composition(cp); // インスタンスをコピーする.
327+ cp_hex.toHexose(); // "Glc"などを"Hex"へ変換
328+
329+ int pen = Collections.frequency(cp_hex, "pen"); // 指定した糖の個数を数える.
330+ int dhex = Collections.frequency(cp_hex, "dhex");
331+ int hex = Collections.frequency(cp_hex, "hex");
332+ int hexnac = Collections.frequency(cp_hex, "hexnac");
333+ int penme = Collections.frequency(cp_hex, "penme");
334+ int dhexme = Collections.frequency(cp_hex, "dhexme");
335+ int hexme = Collections.frequency(cp_hex, "hexme");
336+ int hexnacme = Collections.frequency(cp_hex, "hexnacme");
337+ int total = pen + dhex + hex + hexnac + penme + dhexme + hexme + hexnacme; // 合計の糖数
338+ double mass_t = cp.getMass(monoavg, adduct);
339+ double difference = mass_a - mass_t;
340+
341+ Composition modif = new Composition(cp_hex); // 表に存在する以外の修飾基をmodifへ格納する.
342+ // 単糖を削除
343+ modif.removeAll(new Composition("pen, dhex, hex, hexnac, penme, dhexme, hexme, hexnacme"));
344+ if (select != 2) // セラミドが存在する場合,
345+ modif.remove(modif.getCeramide()); // セラミドを削除
346+
347+ out.print("<TR>");
348+ out.print(String.format("<TD align=right>%.4f</TD>", mass_t));
349+ out.print(String.format("<TD align=right>%.4f</TD>", difference));
350+
351+ if (modif.size() > 0) // 表に存在する以外の修飾基が存在する場合,
352+ out.print("<TD align=center>" + modif.toString() + "</TD>"); // 表示する.
353+ else // 存在しない場合は,
354+ out.print("<TD align=center>-</TD>"); // 表示しない.
355+
356+ if (select != 2) // 糖鎖のみの予測でない場合,
357+ out.print("<TD align=center>" + cp.getCeramide() + "</TD>"); // セラミドは存在する.
358+ else // 糖鎖のみの予測の場合,
359+ out.print("<TD align=center>-</TD>"); // セラミドは存在しない.
360+
361+ if (present_pen || known_cp.contains("pen")) // 条件で指定した糖のみを表示する.
362+ out.print("<TD align=right>" + pen + "</TD>"); // 各糖の個数
363+ if (present_dhex || known_cp.contains("dhex"))
364+ out.print("<TD align=right>" + dhex + "</TD>");
365+ if (present_hex || known_cp.contains("hex"))
366+ out.print("<TD align=right>" + hex + "</TD>");
367+ if (present_hexnac || known_cp.contains("hexnac"))
368+ out.print("<TD align=right>" + hexnac + "</TD>");
369+ if (present_penme || known_cp.contains("penme"))
370+ out.print("<TD align=right>" + penme + "</TD>");
371+ if (present_dhexme || known_cp.contains("dhexme"))
372+ out.print("<TD align=right>" + dhexme + "</TD>");
373+ if (present_hexme || known_cp.contains("hexme"))
374+ out.print("<TD align=right>" + hexme + "</TD>");
375+ if (present_hexnacme || known_cp.contains("hexnacme"))
376+ out.print("<TD align=right>" + hexnacme + "</TD>");
377+
378+ out.print("<TD align=right>" + total + "</TD>"); // 糖数の合計
379+
380+ try // メチル化後の糖脂質のm/zを出力
381+ {
382+ Composition methylated = new Composition(cp);
383+ int count = methylated.countHydroxy(); // メチル基が入るOH基の数を数える.
384+ methylated.addAll(new Composition("me*" + count)); // メチル基を追加する.
385+ out.print(String.format("<TD align=right>%.4f</TD>", methylated.getMass(monoavg, adduct)));
386+ }
387+ catch (Exception e)
388+ {
389+ out.println("<TD align=center>-</TD>");
390+ }
391+
392+ try // 可能性のある系列を表示する.
393+ {
394+ StringBuilder sb = new StringBuilder();
395+ if (cp.isGloboSeries())
396+ sb.append("Globo, ");
397+ if (cp.isLactoSeries())
398+ sb.append("Lacto, ");
399+ if (cp.isGanglioSeries())
400+ sb.append("Ganglio, ");
401+ if (cp.isLactoganglioSeries())
402+ sb.append("Lactoganglio, ");
403+ if (cp.isGalaSeries())
404+ sb.append("Gala, ");
405+ if (cp.isMucoSeries())
406+ sb.append("Muco, ");
407+ if (cp.isArthroSeries())
408+ sb.append("Arthro, ");
409+ if (cp.isMolluSeries())
410+ sb.append("Mollu, ");
411+ if (sb.length() > 2)
412+ out.print("<TD>" + sb.substring(0, sb.length()-2) + "</TD>"); // 最後の", "を削除して表示
413+ else
414+ out.print("<TD></TD>"); // 可能性のある系列が存在しなかった場合
415+ }
416+ catch (Exception e)
417+ {
418+ out.println("<TD>" + e + "</TD>");
419+ }
420+
421+ out.println("</TR>");
422+ }
423+ }
424+ catch (Exception e)
425+ {
426+ out.println("ERROR:" + e.getMessage());
427+ }
428+ out.println("</TABLE><BR>");
429+
430+ out.println("<Div Align=right><FONT color=gray>(c) Kazuhito Yokoi</FONT></Div><BR>");
431+ out.println("<A HREF=../>Back</A>"); // トップページへのリンク
432+
433+ out.println("<script type=\"text/javascript\">");
434+ out.println("var gaJsHost = ((\"https:\" == document.location.protocol) ? \"https://ssl.\" : \"http://www.\");");
435+ out.println("document.write(unescape(\"%3Cscript src='\" + gaJsHost + \"google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E\"));");
436+ out.println("</script>");
437+ out.println("<script type=\"text/javascript\">");
438+ out.println("try {");
439+ out.println("var pageTracker = _gat._getTracker(\"UA-1643740-14\");");
440+ out.println("pageTracker._trackPageview();");
441+ out.println("} catch(err) {}</script>");
442+ out.println("</BODY></HTML>"); // 終了タグ
443+ }
444+}
--- jp/ac/ritsumei/is/infobio/PredictionGa.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/PredictionGa.java (revision 1)
@@ -0,0 +1,417 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.concurrent.*;
4+
5+/**
6+ * メチル化後ガングリオシドのフラグメントイオンから構造を予測するクラスです.
7+ * @author 横井一仁
8+ * @version 20090124
9+ */
10+class CandidateGa extends Candidate
11+{
12+ Glycan before_gc; // メチル化前の糖鎖構造を格納
13+
14+ public CandidateGa(Glycan gc) throws Exception
15+ {
16+ super();
17+ before_gc = new Glycan(gc.toString()); // メチル化前の構造を格納しておく.
18+
19+ gc.methylation(); // メチル化を行う.
20+
21+ this.setNode(gc.getNode()); // メチル化後の構造を登録する.
22+ this.setEdge(gc.getEdge());
23+ this.setChildren(gc.getChildren());
24+
25+ fg.setGlycan(this);
26+ this.frags_t = fg.getComposition(); // それぞれのフラグメントを取得する.
27+ this.masses_t = new double[this.frags_t.size()]; // フラグメント数と同じサイズの配列を用意
28+
29+ int i = 0;
30+ for (Composition temp : this.frags_t) // フラグメントの分子量を計算しておく
31+ masses_t[i++] = temp.getMass(monoavg, adduct); // メチル化糖のm/zを登録する.
32+ }
33+
34+ /*
35+ * メチル化前の糖鎖構造を返します.
36+ * @return メチル化前の糖鎖構造
37+ */
38+ public synchronized Glycan getIntactGlycan() throws Exception
39+ {
40+ return before_gc;
41+ }
42+}
43+
44+/**
45+ * メチル化ガングリオシドの構造予測を行うクラスです.
46+ * @author 横井一仁
47+ * @version 20080725
48+ */
49+public class PredictionGa extends Prediction
50+{
51+ double precursor_me = 0.0; // メチル化後の親マス
52+ CompositionToolsMe cp_agg = new CompositionToolsMe(); // CompositionToolsをCompositionToolsMeにオーバーライド
53+
54+ /**
55+ * コンストラクタ
56+ */
57+ public PredictionGa()
58+ {
59+ super();
60+ }
61+
62+ /**
63+ * 予測された候補構造を返します.
64+ * @return スコアが高い順に予想構造を返します.
65+ */
66+ public java.util.List<? extends Candidate> getPrediction() throws Exception
67+ { // 指定された条件から候補構造を生成
68+ java.util.List<Composition> cps = getCandidateComposition(); // 候補組成を作成する.
69+ java.util.List<Glycan> candi = this.getCandidateGlycan(cps); // 候補構造を生成し,リストに格納する.
70+ java.util.List<CandidateGa> al = this.toCandidateMeInstance(candi); // Glycanの候補構造を,
71+ // CandidateGaの候補構造として登録する.
72+ CandidateGa.setFreq(this.getFreqency(al)); // 出現確率を計算し,CandidateMeクラスの
73+ // static変数として登録する.
74+ Collections.sort(al, new Comparator<CandidateGa>() // スコア順にソートする.
75+ {
76+ public int compare(CandidateGa cp1, CandidateGa cp2)
77+ {
78+ double sub = 0.0; // スコアの差
79+ try
80+ {
81+ double score1 = cp1.getScore();
82+ double score2 = cp2.getScore();
83+
84+ if (score1 == score2) // スコアが等しい構造は,分岐数の少ない
85+ sub = cp1.countLeaf() - cp2.countLeaf(); // (葉ノード数が少ない)構造を上位に表示
86+ else
87+ sub = score2 - score1;
88+
89+ }
90+ catch (Exception e)
91+ {
92+ System.err.println("Prediction.getPrediction(): score compare error");
93+ }
94+
95+ return (int)(sub*1024); // 精度を1024倍に上げる
96+ }
97+ });
98+
99+ return al;
100+ }
101+
102+ /**
103+ * 候補組成を生成し,リストに格納する.
104+ */
105+ protected java.util.List<Composition> getCandidateComposition() throws Exception
106+ { // メチル化前の親マスのみから組成を予測する.親クラスはフラグメントからも予測
107+ java.util.List<Composition> cps; // 考えられる組成を格納するリスト
108+
109+ cp_agg.setComposition(known_cp);
110+ cp_agg.setGlycan(known_gc);
111+ cp_agg.setMsTolerance(tolerance_ms);
112+
113+ if (precursor == 0.0) // 親マスの分子量が登録されていない場合,
114+ { // フラグメント分子量の最大実測値から計算する.
115+ Arrays.sort(masses_a); // 最大値を取り出すために昇順にソート.
116+ cp_agg.setMass(masses_a[masses_a.length-1]);
117+ cps = cp_agg.getComposition();
118+ }
119+ else // 親マスの分子量が登録されている場合
120+ {
121+ cp_agg.setMass(precursor);
122+ cps = cp_agg.getComposition();
123+ }
124+
125+ ListIterator<Composition> it = cps.listIterator();
126+ while (it.hasNext())
127+ {
128+ Composition cp = new Composition(it.next());
129+ System.out.println("candidate composition: " + cp);
130+ if (!cp.contains("neuac")) // シアル酸を持っていない組成を排除する.
131+ {
132+ it.remove();
133+ System.out.println(cp + " is removed.");
134+ }
135+ }
136+
137+ return cps;
138+ }
139+
140+ /**
141+ * Glycanインスタンスの候補構造を,CandidateGaインスタンスの候補構造とし,フラグメント化を行う.
142+ */
143+ protected java.util.List<CandidateGa> toCandidateMeInstance(java.util.List<Glycan> candi) throws Exception
144+ {
145+ java.util.List<CandidateGa> al = new ArrayList<CandidateGa>(); // スコア付けを行う候補構造
146+ long start = new Date().getTime(); // プログラム開始時刻
147+ int candi_size = candi.size(); // 候補構造数を格納
148+ ListIterator<Glycan> it2 = candi.listIterator(); // 候補構造のイテレータを取得
149+ for (int i = 1; it2.hasNext() && flag; i++) // 考えられる組成のとり得る構造をリストに格納
150+ {
151+ Glycan temp = it2.next();
152+ it2.remove(); // 不必要であるGlycanインスタンスを削除する.
153+
154+ percent = (int)(i * 99.0 / candi_size); // 処理が何%進んだかを格納
155+ //(途中で表示が消えるため99%)
156+ String messege = progress(i, candi_size, start); // オブザーバに送るメッセージを作成する.
157+ try
158+ {
159+ messege = messege + " [" + temp.toNormalFormat() + "]"; // ノーマルのフォーマットで格納する.
160+ }
161+ catch (Exception e)
162+ {
163+ messege = messege + " [" + temp.toString() + "]"; // 二分岐以上の構造はLinucs形式で格納する.
164+ }
165+ this.setChanged(); // 変更があったことを明示する.
166+ this.notifyObservers(messege); // 監視者に進行状況を通知
167+ this.clearChanged(); // 変更された状態でないことを明示する.
168+
169+ CandidateGa cd = new CandidateGa(temp);
170+ al.add(cd);
171+ }
172+
173+ if (!flag) // 処理が中断された場合,
174+ al.clear(); // CandidateMeインスタンスの候補構造を削除
175+ else // 処理が正常に完了した場合,
176+ {
177+ percent = 100; // ProgressMonitorを終了するために100%にする.
178+ this.setChanged(); // 変更があったことを明示する.
179+ this.notifyObservers(progress(candi.size(), candi.size(), start)); // 監視者に進行状況を通知
180+ this.clearChanged(); // 変更された状態でないことを明示する.
181+ }
182+
183+ return al;
184+ }
185+
186+ /**
187+ * Glycanインスタンスの候補構造を,Candidateインスタンスの候補構造とし,フラグメント化を行う.
188+ */
189+ protected java.util.List<CandidateGa> toCandidateMeInstance2(java.util.List<Glycan> candi) throws Exception
190+ { // マルチスレッド版
191+ java.util.List<CandidateGa> al = new ArrayList<CandidateGa>(); // スコア付けを行う候補構造
192+ long start = new Date().getTime(); // プログラム開始時刻
193+ int candi_size = candi.size(); // 候補構造数を格納
194+ ListIterator<Glycan> it2 = candi.listIterator(); // 候補構造のイテレータを取得
195+ for (int i = 1; it2.hasNext() && flag; i++) // 考えられる組成のとり得る構造をリストに格納
196+ {
197+ StringBuffer gc_messege = new StringBuffer(); // 現在処理中の糖鎖を文字列表示にて格納
198+ java.util.List<Glycan> gc_thread = new ArrayList<Glycan>(); // 1回の処理で並列計算させるGlycanインスタンス
199+ for (int j = 0; j < 8 && it2.hasNext(); j++) // 8スレッドを並列させるので,8個ずつ処理
200+ {
201+ Glycan temp = it2.next();
202+ try
203+ {
204+ gc_messege.append(temp.toNormalFormat() + ", "); // ノーマルのフォーマットで格納
205+ }
206+ catch (Exception e)
207+ {
208+ gc_messege.append(temp.toString() + ", "); // 二分岐以上の構造はLinucs形式で格納
209+ }
210+ gc_thread.add(temp); // マルチスレッドのタスクに追加
211+ it2.remove(); // 不必要であるGlycanインスタンスを削除
212+
213+ i++; // 処理済みの個数を増加させる.
214+ }
215+ i--; // for文の中で値が1つ多くなるため,削除
216+
217+ System.out.println("!"+i+"/"+candi_size);
218+ percent = (int)(i * 99.0 / candi_size); // 処理が何%進んだかを格納
219+ // 途中で表示が消えるため99%
220+ String messege = progress(i, candi_size, start); // オブザーバに送るメッセージ
221+ messege = messege + " [" + gc_messege.toString() + "]";
222+ this.setChanged(); // 変更があったことを明示する.
223+ this.notifyObservers(messege); // 監視者に進行状況を通知
224+ this.clearChanged(); // 変更された状態でないことを明示する.
225+
226+ java.util.List<Callable<CandidateGa>> tasks = new ArrayList<Callable<CandidateGa>>();
227+ // タスクを格納するリスト
228+ for (Glycan temp : gc_thread)
229+ {
230+ Callable<CandidateGa> task = new MultiThreadTool3(new Glycan(temp));
231+ tasks.add(task);
232+ }
233+ ExecutorService es = Executors.newFixedThreadPool(8); // 8スレッドで実行
234+ java.util.List<Future<CandidateGa>> futures = es.invokeAll(tasks); // タスクの実行
235+
236+ for (Future<CandidateGa> future : futures) // 実行結果の回収
237+ {
238+ CandidateGa cd = future.get();
239+ al.add(cd);
240+ }
241+ es.shutdown(); // 並列処理の終了
242+ }
243+
244+ if (!flag) // 処理が中断された場合,
245+ al.clear(); // Candidateインスタンスの候補構造を削除
246+ else // 処理が正常に完了した場合,
247+ {
248+ percent = 100; // ProgressMonitorを終了するために100%にする.
249+ this.setChanged(); // 変更があったことを明示する.
250+ this.notifyObservers(progress(candi.size(), candi.size(), start)); // 監視者に進行状況を通知
251+ this.clearChanged(); // 変更された状態でないことを明示する.
252+ }
253+
254+ return al;
255+ }
256+
257+ /**
258+ * モノアイソトープ,またはアベレージで計算するかを設定します.
259+ * @param monoavg モノアイソトピックまたはアベレージ.
260+ */
261+ public void setMonoavg(boolean monoavg) throws Exception
262+ {
263+ CandidateGa.setMonoavg(monoavg); // Candidateクラスのstatic変数として登録する.
264+ cp_agg.setMonoavg(monoavg); // 組成を予測するクラスのメソッドを利用して登録する.
265+ }
266+
267+ /**
268+ * 予測に用いる付加イオンを指定します.
269+ * @param adduct 付加イオン(デフォルトはNa+)
270+ */
271+ public void setAdduct(String adduct) throws Exception
272+ {
273+ CandidateGa.setAdduct(adduct); // Candidateクラスのstatic変数として登録する.
274+ cp_agg.setAdduct(adduct); // 組成を予測するクラスのメソッドを利用して登録する.
275+ }
276+
277+ /**
278+ * PSDスペクトルの実測値と理論値の許容誤差を登録します.
279+ * @param tolerance_psd 実測値と理論値の許容誤差
280+ */
281+ public void setPsdTolerance(double tolerance_psd) throws Exception
282+ {
283+ this.tolerance_psd = tolerance_psd; // クラスメンバとする.
284+ CandidateGa.setPsdTolerance(tolerance_psd); // Candidateクラスのstatic変数として登録する.
285+ }
286+
287+ /**
288+ * フラグメント分子量の実測値を登録します.
289+ * @param masses_a フラグメント分子量の実測値
290+ */
291+ public void setFragments(double[] masses_a)
292+ {
293+ this.masses_a = masses_a; // メンバ変数として格納
294+ CandidateGa.setMasses_a(masses_a); // Candidateクラスのstatic変数として登録する.
295+ }
296+
297+ /**
298+ * 予測に用いるスコア式を指定します.
299+ * @param formula スコア式
300+ */
301+ public void setScoringFormula(int formula)
302+ {
303+ CandidateGa.setScoringFormula(formula); // Candidateクラスのstatic変数として登録する.
304+ }
305+
306+ /**
307+ * 出現確率分布のウィンドウサイズを指定します.
308+ * @param window ウィンドウサイズ
309+ */
310+ public void setWindowSize(int window)
311+ {
312+ CandidateGa.setWindowSize(window); // Candidateクラスのstatic変数として登録する.
313+ }
314+
315+ /**
316+ * 現在登録されている出現確率分布のウィンドウサイズを取得します.
317+ * @return ウィンドウサイズ
318+ */
319+ public int getWindowSize()
320+ {
321+ return CandidateGa.getWindowSize(); // Candidateクラスのstatic変数を呼び出す.
322+ }
323+
324+
325+ /**
326+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
327+ * @param lcb 長鎖塩基組成
328+ */
329+ public void setLongChainBase(java.util.List<String> lcb) throws Exception
330+ {
331+ cp_agg.setLongChainBase(lcb);
332+ }
333+
334+ /**
335+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
336+ * @param fa 脂肪酸組成
337+ */
338+ public void setFattyAcid(java.util.List<String> fa) throws Exception
339+ {
340+ cp_agg.setFattyAcid(fa);
341+ }
342+
343+ /**
344+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
345+ * @param min 炭素数の最小値
346+ * @param max 炭素数の最大値
347+ */
348+ public void setLongChainBase(int min, int max) throws Exception
349+ {
350+ cp_agg.setLongChainBase(min, max);
351+ }
352+
353+ /**
354+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
355+ * @param min 炭素数の最小値
356+ * @param max 炭素数の最大値
357+ */
358+ public void setFattyAcid(int min, int max, int bond) throws Exception
359+ {
360+ cp_agg.setFattyAcid(min, max, bond);
361+ }
362+
363+ /**
364+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
365+ * @param ceramide セラミド組成
366+ */
367+ public void setCeramide(java.util.List<String> ceramide) throws Exception
368+ {
369+ cp_agg.setCeramide(ceramide);
370+ }
371+
372+ /**
373+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
374+ * @param min 炭素数の最小値
375+ * @param max 炭素数の最大値
376+ * @param bond 脂肪酸の二重結合の最大値
377+ */
378+ public void setCeramide(int min, int max, int bond)
379+ {
380+ cp_agg.setCeramide(min, max, bond);
381+ }
382+
383+ /**
384+ * 予測で考慮する各糖の糖数を指定します.
385+ * @param str 糖数を指定する糖
386+ * @param max 指定する糖数
387+ */
388+ public void setMax(String str, int max) throws Exception
389+ {
390+ cp_agg.setMax(str, max);
391+ }
392+
393+ /**
394+ * 予測で考慮する各糖の糖数を指定します.
395+ * @param str 指定する糖
396+ * @param bl 糖を存在させるかを指定
397+ */
398+ public void setMax(String str, boolean bl) throws Exception
399+ {
400+ cp_agg.setMax(str, bl);
401+ }
402+}
403+
404+class MultiThreadTool3 implements Callable<CandidateGa>
405+{
406+ Glycan gc; // 並列処理のために保存しておく候補構造
407+
408+ public MultiThreadTool3(Glycan gc) throws Exception
409+ {
410+ this.gc = gc; // 候補構造を登録
411+ }
412+
413+ public CandidateGa call() throws Exception
414+ {
415+ return new CandidateGa(gc); // フラグメント化後の分子量の計算済みの候補構造を返す.
416+ }
417+}
\ No newline at end of file
--- jp/ac/ritsumei/is/infobio/Glycan.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/Glycan.java (revision 1)
@@ -0,0 +1,525 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+
5+/**
6+ * 糖鎖構造のデータを扱うクラスです.
7+ * @author 横井一仁
8+ * @version 20080514
9+ */
10+public class Glycan
11+{
12+ String node = ""; // 格納するデータ
13+ String edge = ""; // 結合の種類
14+ ArrayList<Glycan> al = new ArrayList<Glycan>(); // 結合する子ノードを格納するリスト
15+
16+ /**
17+ * コンストラクタ
18+ */
19+ public Glycan()
20+ {
21+
22+ }
23+
24+ /**
25+ * 渡されたGlycanインスタンスから糖鎖構造を構築します.
26+ * @param gc Glycanインスタンス
27+ */
28+ public Glycan(Glycan gc) throws Exception
29+ {
30+ Glycan temp = new Glycan(gc.toString());
31+ this.setNode(temp.getNode()); // 構造を登録する.
32+ this.setEdge(temp.getEdge());
33+ this.setChildren(temp.getChildren());
34+ }
35+
36+ /**
37+ * 渡された文字列から糖鎖構造を構築します.
38+ * @param str Linucs形式で表した糖鎖構造("th38:0-Glc(-Fuc)-GalNAc-GlcNAc-Rha"なども入力可能)
39+ */
40+ public Glycan(String str) throws Exception
41+ {
42+ str = str.replaceAll("\\s", ""); // 空白文字を削除(\sは改行も含む)
43+ str = str.toLowerCase(); // 全て小文字に変換
44+
45+ Pattern pt = Pattern.compile("^\\[(.*?)\\]\\[(.*?)\\]\\{(.*)\\}$"); // 節情報と辺情報を切り出し,格納
46+ Matcher mt = pt.matcher(str);
47+
48+ if (mt.matches()) // まず,Linucs形式で構文解析する.
49+ {
50+ edge = mt.group(1); // 1つ目の[]内の文字列
51+ node = mt.group(2); // 2つ目の[]内の文字列
52+ String child = mt.group(3); // 最後の{}内の文字列
53+
54+ for (int i = 0, j = 0; j <= child.length(); j++)
55+ {
56+ String temp = child.substring(i, j);
57+
58+ if (isLinucs(temp))
59+ {
60+ al.add(new Glycan(temp));
61+ i = j; // 次の構造へ移行する.
62+ }
63+ }
64+ }
65+ else // Linucs形式でない場合
66+ {
67+ throw new Exception("Linucs format parse error : " + str);
68+ }
69+ }
70+
71+ /**
72+ * Linucs形式であるかを判定します.
73+ * @param str Linucs形式の文字列
74+ */
75+ private boolean isLinucs(String str)
76+ {
77+ String temp = "";
78+
79+ for (int i = 0; i < str.split("\\{").length; i++) // 入れ子は"{"の数以下となる.
80+ {
81+ // "[^\\[\\]\\{\\}]"により,"[]{}"以外を指定.
82+ String regex = "\\[([^\\[\\]\\{\\}])*?\\]\\[([^\\[\\]\\{\\}])*?\\]\\{" + temp + "\\}";
83+
84+ if (str.matches("^" + regex + "$"))
85+ return true;
86+
87+ temp = "(" + regex + ")*?";
88+ }
89+
90+ return false;
91+ }
92+
93+ /**
94+ * 登録されている単糖を変更します.
95+ * @param node 節情報の文字列
96+ */
97+ public void setNode(String node)
98+ {
99+ this.node = node;
100+ }
101+
102+ /**
103+ * 登録されている結合情報を変更します.
104+ * @param edge 辺情報の文字列
105+ */
106+ public void setEdge(String edge)
107+ {
108+ this.edge = edge;
109+ }
110+
111+ /**
112+ * 登録されている単糖を返します.
113+ * @return 節情報の文字列
114+ */
115+ public String getNode()
116+ {
117+ return node;
118+ }
119+
120+ /**
121+ * 結合情報を返します.
122+ * @return 辺情報の文字列
123+ */
124+ public String getEdge()
125+ {
126+ return edge;
127+ }
128+
129+ /**
130+ * 結合情報が登録されているかを返します.
131+ * @return 節情報が存在するか
132+ */
133+ public boolean hasNode()
134+ {
135+ String temp = this.getNode();
136+ if (temp == null || temp.equals("") || temp.equals("0+0") || temp.equals("0-0"))
137+ return false;
138+ else
139+ return true;
140+ }
141+
142+ /**
143+ * 結合情報が登録されているかを返します.
144+ * @return 辺情報が存在するか
145+ */
146+ public boolean hasEdge()
147+ {
148+ String temp = this.getEdge();
149+ if (temp == null || temp.equals("") || temp.equals("0+0") || temp.equals("0-0"))
150+ return false;
151+ else
152+ return true;
153+ }
154+
155+ /**
156+ * セラミドを含んでいるかを返します.
157+ * @return セラミドを含んでいるか
158+ */
159+ public boolean hasCeramide() throws Exception
160+ {
161+ if (this.getNode().matches("^([dt])([ch][0-9]+:[0-9])$")) // ルートノードにセラミドが存在した場合
162+ return true;
163+ else
164+ {
165+ boolean flag = false; // return用フラッグ
166+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
167+ if (gc.hasCeramide()) // 子ノードに1つでもセラミドが存在した場合,
168+ flag = true; // trueとして返すために,親ノードに伝える.
169+ return flag;
170+ }
171+ }
172+
173+ /**
174+ * 構造をLinucs形式で返します.
175+ * @return Linucs形式の文字列
176+ */
177+ public String toString()
178+ {
179+ if (al.isEmpty())
180+ return Composition.toFixSignage("[" + getEdge() + "][" + getNode() + "]{}"); // 正しい表記で出力
181+ else // 子ノードがある場合,再帰する.
182+ {
183+ Iterator it = al.iterator();
184+ String temp = "";
185+
186+ while (it.hasNext()) // "{}"内の文字列を繋ぎ合わせる.
187+ temp = temp + ((Glycan)it.next()).toString();
188+
189+ return Composition.toFixSignage("[" + getEdge() + "][" + getNode() + "]{" + temp + "}"); // 正しい表記で出力
190+ }
191+ }
192+
193+ /**
194+ * 木構造を線形表示で返すメソッド
195+ * @return 木構造を"th38:0-Glc(-Fuc)-GalNAc-GlcNAc-Rha"の線形表示で返す.
196+ */
197+ public String toNormalFormat() throws Exception
198+ {
199+ GlycanTools gi = new GlycanTools();
200+ return Composition.toFixSignage(gi.toNormalFormat(this)); // 正しい表記で出力
201+ }
202+
203+ /**
204+ * 木構造における現在の要素が葉であるかを返します.
205+ * @return 葉であるかを返す.
206+ */
207+ public boolean isLeaf()
208+ {
209+ return al.isEmpty();
210+ }
211+
212+ /**
213+ * 葉以外に指定した要素が存在しないかを返します.
214+ * @return 存在しないかを返す.
215+ */
216+ public boolean containsOnlyLeaf(String str) throws Exception // 末端のみにFucMeが存在する構造はtrue
217+ {
218+ boolean flag = true;
219+
220+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
221+ if (!gc.isLeaf() && gc.getNode().equals(str))
222+ return false;
223+ else if (!gc.containsOnlyLeaf(str)) // 再帰
224+ flag = false; // 再帰で1回でもfalseが返されたら,再帰元の関数はfalseを返す.
225+
226+ return flag; // 再帰で葉以外に指定した要素が存在しなかった場合返される.
227+ }
228+
229+ /**
230+ * Glc,Gal,ManをHexへ,GlcNAc,GalNAcをHexNAcへ変換します.
231+ */
232+ public void toHexose()
233+ {
234+ node = node.replaceAll("glc|man|gal", "hex"); // Hexへ変換
235+ node = node.replaceAll("lfuc|fuc|rha", "dhex"); // dHexへ変換
236+ node = node.replaceAll("xyl|ara", "pen"); // penへ変換
237+
238+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
239+ gc.toHexose();
240+ }
241+
242+ /**
243+ * 子ノードを返します.
244+ * @return 子ノード
245+ */
246+ public List<Glycan> getChildren()
247+ {
248+ return al;
249+ }
250+
251+ /**
252+ * 子ノードを書き換えます.
253+ * @param li 書き換える子ノード
254+ */
255+ public void setChildren(List<Glycan> li)
256+ {
257+ al.clear(); // 子ノードを削除
258+ al.addAll(li); // 引数の子ノードを追加
259+ }
260+
261+ /**
262+ * 単糖の数を返します.
263+ * @return 構造内のノード数
264+ */
265+ public int size() throws Exception
266+ {
267+ int sum = 1; // 再帰により,この1を順次sumへ加算していく.
268+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
269+ sum += gc.size(); // 再帰
270+
271+ return sum;
272+ }
273+
274+ /**
275+ * 構造内の葉ノード数を返します.
276+ * @return 構造内の葉ノード数
277+ */
278+ public int countLeaf()
279+ {
280+ int sum = 0; // 再帰により,sumへ加算していく.
281+
282+ if (this.isLeaf())
283+ sum++;
284+
285+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
286+ sum += gc.countLeaf(); // 再帰
287+
288+ return sum;
289+ }
290+
291+ /**
292+ * 理論上の<I>m/z</I> を返します.
293+ * @param monoisotopic モノアイソトピックかアベレージかをMassCalc.MONO_MASSで指定
294+ * @param adduct 付加イオンをMassCalc.Na_IONで指定
295+ * @return 理論上の<I>m/z</I>
296+ */
297+ public double getMass(boolean monoisotopic, String adduct) throws Exception
298+ {
299+ MassCalc mc = new MassCalc(monoisotopic, adduct);
300+ return mc.getMass(this);
301+ }
302+
303+ /**
304+ * 構造内に指定した文字列が存在するかを返します.
305+ * @param str 検索したい文字列
306+ * @return 構造内に文字列が存在するか
307+ */
308+ public boolean contains(String str) throws Exception
309+ {
310+ Composition cp = new Composition(this); // 組成を作成
311+ return cp.contains(str);
312+ }
313+
314+ /**
315+ * 糖鎖構造に対し、辞書順に再構築を行います.
316+ */
317+ public void reconstruct()
318+ {
319+ ArrayList<Glycan> al = new ArrayList<Glycan>(); // 結合する子ノードを格納するリスト(後に書き換えるため)
320+
321+ for (Glycan gc : this.getChildren()) // 子ノードがあるならば,さらに探索を行う.
322+ {
323+ al.add(gc); // 後に書き換えるために保存する.
324+ gc.reconstruct(); // 再帰
325+ }
326+
327+ Collections.sort(al, new Comparator<Glycan>() // 探索した帰りに辞書順にソートし,ノードの順番を書き換える.
328+ {
329+ public int compare(Glycan gc1, Glycan gc2)
330+ {
331+ return gc1.toString().compareTo(gc2.toString());
332+ }
333+ });
334+
335+ this.setChildren(al); // alの内容に書き換える.
336+ }
337+
338+ /**
339+ * このクラスをコレクションへ格納できるようにequalsメソッドをオーバーライドします.
340+ * @param gc 比較対象となるGlycanクラス
341+ * @return それぞれをLinucs形式へ変換し,String型における比較結果を返す.
342+ */
343+ public boolean equals(Object gc) // オーバーライドなので引数の型はObjectでなくてはならない.
344+ {
345+ try
346+ {
347+ Glycan temp1 = new Glycan(this.toString()); // Glycanインスタンスをコピーする.
348+ Glycan temp2 = new Glycan(((Glycan)gc).toString()); // jvm1.5以下ではオブジェクトの型変換が必要.
349+ temp1.reconstruct(); // それぞれのノードを辞書順に並び変えた後,
350+ temp2.reconstruct(); // 比較を行う.
351+
352+ return temp1.toString().equals(temp2.toString());
353+ }
354+ catch (Exception e)
355+ {
356+ System.out.println("Exception at Glycan.equals(Glycan.java) " + e); // 例外が発生したら,
357+ return false; // 同じ糖鎖構造であってもfalseを返す.
358+ }
359+ }
360+
361+ /**
362+ * このクラスをコレクションへ格納できるようにhashCodeメソッドをオーバーライドします.
363+ * @return それぞれをLinucs形式へ変換し,String型におけるhashCodeメソッドの値を返す.
364+ */
365+ public int hashCode()
366+ {
367+ try
368+ {
369+ Glycan temp = new Glycan(this.toString()); // Glycanインスタンスをコピーする.
370+ temp.reconstruct(); // ノードを辞書順に並び変えた後,hashCode()を行う.
371+ return temp.toString().hashCode();
372+ }
373+ catch (Exception e)
374+ {
375+ System.out.println("Exception at Glycan.hashCode(Glycan.java)");
376+ return 0; // 例外が発生したら,0を返す.
377+ }
378+ }
379+
380+ /**
381+ * フラグメントをGlycanとして返します.
382+ * @return GlycanのSet
383+ */
384+ public List<Glycan> getGlycanFragment() throws Exception
385+ {
386+ Fragmentation fg = new Fragmentation();
387+ fg.setGlycan(new Glycan(this.toString()));
388+ return fg.getGlycan();
389+ }
390+
391+ /**
392+ * フラグメントをCompositionとして返します.
393+ * @return CompositionのSet
394+ */
395+ public List<Composition> getCompositionFragment() throws Exception
396+ {
397+ Fragmentation fg = new Fragmentation();
398+ fg.setGlycan(new Glycan(this.toString()));
399+ return fg.getComposition();
400+ }
401+
402+ /**
403+ * 子ノードとしてGlycanを追加します.
404+ * @param gc 追加するGlycanクラス
405+ */
406+ public void addChild(Glycan gc)
407+ {
408+ al.add(gc);
409+ }
410+
411+ /**
412+ * 指定した子ノードを削除します.
413+ * @param gc 削除するGlycanクラス
414+ */
415+ public boolean removeChild(Glycan gc)
416+ {
417+ return al.remove(gc); // 成功したらtrueを返す.
418+ }
419+
420+ /**
421+ * 全メチル化を行います.
422+ */
423+ public void methylation() throws Exception // 還元末端側が糖鎖の場合,
424+ { // 還元末端にメチル基が入ることを考慮するために関数を2重化
425+ this.methylation(false); // 親ノードが存在しない(=false)として実行.
426+ }
427+
428+ /**
429+ * 全メチル化を行います.
430+ * @parm flag 親ノードが存在するか
431+ */
432+ private void methylation(boolean flag) throws Exception
433+ {
434+ Pattern pt1 = Pattern.compile("^(xyl|ara|pen|dhex|fuc|rha|hex|glc|gal|man|hexnac|glcnac|galnac|hexa|kdn|neuac|neugc)([0-9]*)((me)?)$");
435+ Matcher mt1 = pt1.matcher(node); // ↑アセチル基には未対応
436+ Pattern pt2 = Pattern.compile("^([dt])([ch])([0-9]+):([0-9])$");
437+ Matcher mt2 = pt2.matcher(node);
438+
439+ if (mt1.matches()) // 糖のメチル化
440+ {
441+ int count = 0; // メチル基が入る個数
442+ if (mt1.group(1).matches("^(xyl|ara|pen)$")) // ペントースの場合は,
443+ count = 3 - this.getChildren().size(); // 修飾基の付加できる部分は最大3ヶ所
444+ else if (mt1.group(1).matches("^(dhex|fuc|rha)$")) // デオキシヘキソースの場合は,
445+ count = 3 - this.getChildren().size(); // 修飾基の付加できる部分は最大3ヶ所
446+ else if (mt1.group(1).matches("^(hex|glc|gal|man|hexnac|glcnac|galnac|hexa)$")) // その他の場合は,
447+ count = 4 - this.getChildren().size(); // 最大4ヶ所
448+ else if (mt1.group(1).matches("^(neuac|kdn)$")) // NeuAc,KDNは,最大6ヶ所
449+ count = 6 - this.getChildren().size();
450+ else if (mt1.group(1).matches("^(neugc)$")) // NeuGcは,NeuAcからさらにOH基が1つ多いため,最大7ヶ所
451+ count = 7 - this.getChildren().size();
452+ else
453+ throw new Exception("Regular expression error in above program: + " + mt1.group(1));
454+
455+ if (!flag) // 親ノードが存在しない糖は還元末端側にメチル基が入る.
456+ count++;
457+
458+ node = mt1.group(1) + count + "me";
459+ }
460+ else if (mt2.matches()) // セラミドのメチル化(長鎖塩基のNにもメチル基が入る)
461+ {
462+ int count = Integer.parseInt(mt2.group(3)); // セラミドの炭素数を格納
463+ if (mt2.group(1).equals("d")) // ジヒドロキシスフィンゴシンの場合,
464+ count += 2; // メチル基が2つ増加(=炭素数が2つ増加)
465+ else if (mt2.group(1).equals("t")) // トリヒドロキシスフィンゴシンの場合,
466+ count += 3; // メチル基が3つ増加(=炭素数が3つ増加)
467+
468+ if (mt2.group(2).equals("h")) // ヒドロキシ脂肪酸の場合,
469+ count++; // メチル基が1つ増加(=炭素数が1つ増加)
470+
471+ node = mt2.group(1) + mt2.group(2) + count + ":" + mt2.group(4);
472+ }
473+ else // 正規表現と一致しなかった場合
474+ throw new Exception("Unknown Composition: " + node);
475+
476+ for (Glycan gc : this.getChildren()) // 子ノードにおいてもメチル化を行う.
477+ gc.methylation(true); // 親ノードが存在する(=true)として再帰.
478+ }
479+
480+
481+ /**
482+ * 指定した構造から伸長した構造であるかを返します.
483+ * @param gc 検索対象とする糖鎖構造
484+ * @return 伸長した構造であるかを返す.
485+ */
486+ public boolean contains(Glycan gc) throws Exception
487+ {
488+ if (gc == null) // 引数がnullの場合はfalse
489+ return false;
490+
491+ if (this.getNode().equals(gc.getNode())) // ノード名が一致した場合
492+ {
493+ ArrayList<Glycan> al1 = new ArrayList<Glycan>(); // 子ノードを削除をするため,
494+ ArrayList<Glycan> al2 = new ArrayList<Glycan>(); // ArrayList<Glycan>を用意.
495+ for (Glycan gc1 : this.getChildren())
496+ al1.add(gc1); // それぞれの子ノードを格納.
497+ for (Glycan gc2 : gc.getChildren())
498+ al2.add(gc2);
499+
500+ if (al1.size() == 0 && al2.size() == 0) // ノード名が一致しており,ともに子ノードを持たない場合は
501+ return true; // 以下のif(!flag)によりflaseとなるため,trueを返しておく.
502+ else if (al1.size() >= al2.size()) // 引数であるGlycanの子ノード数の方が小さい場合か,等しい場合
503+ {
504+ for (Glycan temp : al2) // 引数のGlycanの子ノードを調べる.
505+ {
506+ Iterator<Glycan> it1 = al1.iterator();
507+ boolean flag = false; // 引数であるGlycanの子ノードの要素を全て持っていない場合false
508+ while (it1.hasNext() && !flag) // 余分に削除するのを避けるため,!flagを用いる.
509+ if (temp.contains(it1.next()))
510+ {
511+ flag = true; // 一致する要素が左が1つ,右が2つ以上の場合,
512+ it1.remove(); // 間違って判定されるので削除しておく.
513+ }
514+ if (!flag)
515+ return false; // 引数であるGlycanの子ノードの要素を全て持っていない場合false
516+ }
517+ return true; // flaseが返されずこの行へ来た時のみtrue
518+ }
519+ else
520+ return false; // 引数であるGlycanの子ノード数の方が大きい場合はfalse
521+ }
522+ else
523+ return false; // ノード名が一致しない場合はfalse
524+ }
525+}
--- jp/ac/ritsumei/is/infobio/PredictionGUIGa.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/PredictionGUIGa.java (revision 1)
@@ -0,0 +1,314 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.text.*;
3+import java.awt.*;
4+import java.awt.event.*;
5+import javax.swing.*;
6+import java.util.*;
7+import javax.swing.table.*;
8+import java.util.concurrent.*;
9+import java.lang.management.*;
10+
11+/**
12+ * メチル化後ガングリオシドのフラグメントイオンから構造を予測するクラスです.(GUI版)
13+ * @author 横井一仁
14+ * @version 20081122
15+ */
16+public class PredictionGUIGa extends PredictionGUI
17+{
18+ PredictionGUIGa() throws Exception
19+ {
20+ super();
21+ jf.setTitle("Structure Predictor (ganglioside ver)"); // タイトルの変更
22+ }
23+
24+ /*
25+ * 実測値を入力する部分のJPanelを取得します.
26+ */
27+ protected JPanel getInputJPanel()
28+ {
29+ JPanel west_center = new JPanel(); // 実測値入力部
30+ west_center.setLayout(new BorderLayout()); // ウィンドウのWESTに貼り付けるパネルのCENTER(ウィンドウの左上)
31+ west_center.add(new JLabel("Fragment mass (permethylated):"), BorderLayout.NORTH);
32+ // メチル化後GM1のフラグメント
33+ query_ta = new JTextArea("111.1\n154.0\n228.2\n259.5\n306.2\n343.8\n365.9\n375.8\n397.8\n415.7\n434.7\n"
34+ + "457.6\n463.6\n486.6\n575.5\n588.2\n604.8\n675.8\n778.6\n794.4\n810.6\n819.5\n"
35+ + "834.4\n848.9\n866.3\n898.2\n1009.4\n1023.7\n1039.7\n1241.6\n1257.7\n1273.6\n"
36+ + "1385.3\n1400.4\n1414.8\n1474.0\n1488.1\n1502.7\n1862.6\n1877.2");
37+ west_center.add(new JScrollPane(query_ta), BorderLayout.CENTER); // JTextAreaへスクロールバーをつける.
38+
39+ return west_center;
40+ }
41+
42+ /*
43+ * 実験的な予測条件を設定する部分のJPanelを取得します.
44+ */
45+ protected JPanel getExperimentalConditionJPanel()
46+ {
47+ JPanel west_south_north = new JPanel(); // 予測条件入力部 ウィンドウのWESTに貼り付けるパネルのSOUTH
48+ // ウィンドウの左下
49+ // JComboBoxの初期選択項目を指定する.
50+ pen_cb.setSelectedItem("No"); // Penのデフォルトは"No"
51+ dhex_cb.setSelectedItem("Yes"); // dHexのデフォルトは"Yes"
52+ hex_cb.setSelectedItem("Yes"); // Hexのデフォルトは"Yes"
53+ hexnac_cb.setSelectedItem("Yes"); // HexNAcのデフォルトは"Yes"
54+ penme_cb.setSelectedItem("No"); // PenMeのデフォルトは"No"
55+ dhexme_cb.setSelectedItem("No"); // dHexMeのデフォルトは"No"
56+ hexme_cb.setSelectedItem("No"); // HexMeのデフォルトは"No"
57+ hexnacme_cb.setSelectedItem("No"); // HexNAcMeのデフォルトは"No"
58+
59+ formula_cb.setSelectedItem("TFIDF"); // スコア計算式のデフォルトは"TFIDF"
60+
61+ west_south_north.setLayout(new GridLayout(12, 2)); // 縦の数×横の数
62+ west_south_north.add(new JLabel("Fragment tolerance: "));
63+ west_south_north.add(psd_tolerance_tf);
64+ west_south_north.add(new JLabel("Permethylated mass: "));
65+ precursor_mass_tf = new JTextField("1877.1972"); // メチル化後の親マスを登録(GM1)
66+ west_south_north.add(precursor_mass_tf);
67+ west_south_north.add(new JLabel("Precursor tolerance: "));
68+ west_south_north.add(precursor_tolerance_tf);
69+ west_south_north.add(new JLabel("Adduct ion: "));
70+ west_south_north.add(adduct_cb);
71+ west_south_north.add(new JLabel("Pen: "));
72+ west_south_north.add(pen_cb);
73+ west_south_north.add(new JLabel("dHex: "));
74+ west_south_north.add(dhex_cb);
75+ west_south_north.add(new JLabel("Hex: "));
76+ west_south_north.add(hex_cb);
77+ west_south_north.add(new JLabel("HexNAc: "));
78+ west_south_north.add(hexnac_cb);
79+ west_south_north.add(new JLabel("PenMe: "));
80+ west_south_north.add(penme_cb);
81+ west_south_north.add(new JLabel("dHexMe: "));
82+ west_south_north.add(dhexme_cb);
83+ west_south_north.add(new JLabel("HexMe: "));
84+ west_south_north.add(hexme_cb);
85+ west_south_north.add(new JLabel("HexNAcMe: "));
86+ west_south_north.add(hexnacme_cb);
87+
88+ return west_south_north;
89+ }
90+
91+ /*
92+ * Startをクリックした時に実行されるスレッド
93+ */
94+ public void run()
95+ {
96+ System.out.println("PredictionGa mode...");
97+ try
98+ {
99+ PredictionGa pd_agg = new PredictionGa(); // 継承の代わりに集約を用いる.
100+ pd_agg.addObserver(this); // 進行状況をこのクラスへ伝えるために,
101+ // このクラスをオブザーバとする.
102+ // テキストエリアから実測値を取得
103+ String[] strs = query_ta.getText().split("[^\\.\\d]"); // '.'と数字以外の文字列で切り出す.
104+ java.util.List<Double> massli = new ArrayList<Double>(); // 可変長配列を用意する.
105+ for (String str : strs)
106+ {
107+ try
108+ {
109+ massli.add(Double.parseDouble(str));
110+ }
111+ catch (Exception e) // 数字以外の文字が入っていた場合の時,
112+ { // 無視したことを報告
113+ System.err.println(e);
114+ }
115+ }
116+ double[] frags = new double[massli.size()]; // Listと同じ大きさの配列を用意
117+ Iterator<Double> massit = massli.iterator();
118+ for (int i = 0; massit.hasNext(); i++) // double[]型のfragsへ配列の型変換
119+ frags[i] = massit.next();
120+ pd_agg.setFragments(frags); // フラグメントの実測値の配列を登録
121+
122+ try // プレカーサーマスを登録
123+ {
124+ pd_agg.setPrecursorMass(Double.parseDouble(precursor_mass_tf.getText()));
125+ }
126+ catch (Exception e) // プレカーサーマスを登録しなかった場合,
127+ { // PSDフラグメントの最大値を
128+ System.err.println("Precursor mass is null."); // プレカーサーマスとして計算
129+ }
130+
131+ try // プレカーサーマスの許容誤差を登録
132+ {
133+ pd_agg.setMsTolerance(Double.parseDouble(precursor_tolerance_tf.getText())); // 許容誤差を格納
134+ }
135+ catch (Exception e)
136+ {
137+ throw new Exception("'Precursor tolerance' contains error.\n" + e);
138+ }
139+
140+ try // PSDフラグメントの許容誤差を登録
141+ {
142+ pd_agg.setPsdTolerance(Double.parseDouble(psd_tolerance_tf.getText())); // 許容誤差を格納
143+ }
144+ catch (Exception e)
145+ {
146+ throw new Exception("'PSD tolerance' contains error.\n" + e);
147+ }
148+
149+ try // 付加イオンを登録
150+ { // 選択された付加イオンを取得する.
151+ String temp = (String)adduct_cb.getSelectedItem(); // 表の部分でm/zを取得するのに必要なため,
152+ if (temp.equals("Na+")) // adductはグローバル変数としている.
153+ adduct = MassCalc.Na_ION;
154+ else if (temp.equals("H+"))
155+ adduct = MassCalc.H_ION;
156+ else if (temp.equals("Li+"))
157+ adduct = MassCalc.Li_ION;
158+ else if (temp.equals("K+"))
159+ adduct = MassCalc.K_ION;
160+ else if (temp.equals("H-"))
161+ adduct = MassCalc.H_NION;
162+ else if (temp.equals("no adduct"))
163+ adduct = "";
164+ else
165+ throw new Exception(temp + " is unknown adduct ion.");
166+
167+ pd_agg.setAdduct(adduct);
168+ }
169+ catch (Exception e)
170+ {
171+ throw new Exception("'Adduct ion' contains error.\n" + e);
172+ }
173+
174+ try // 既知構造を登録
175+ {
176+ pd_agg.setGlycan(new Glycan(known_gc_tf.getText())); // Linucs形式から既知構造を登録
177+ }
178+ catch (Exception e1) // Linucs形式の読み込みに失敗した場合,
179+ { // ノーマル形式の読み込みを試す.
180+ try
181+ {
182+ GlycanTools gi = new GlycanTools();
183+ pd_agg.setGlycan(gi.readNormalFormat(known_gc_tf.getText())); // 既知構造を登録
184+ }
185+ catch (Exception e2)
186+ {
187+ throw new Exception("'Known structure' contains error.\n" + e1 + e2);
188+ }
189+ }
190+
191+ try // 各糖の最大数を登録
192+ {
193+ pd_agg.setMax("pen", ((String)pen_cb.getSelectedItem()).equals("Yes"));
194+ pd_agg.setMax("dhex", ((String)dhex_cb.getSelectedItem()).equals("Yes"));
195+ pd_agg.setMax("hex", ((String)hex_cb.getSelectedItem()).equals("Yes"));
196+ pd_agg.setMax("hexnac", ((String)hexnac_cb.getSelectedItem()).equals("Yes"));
197+ pd_agg.setMax("penme", ((String)penme_cb.getSelectedItem()).equals("Yes"));
198+ pd_agg.setMax("dhexme", ((String)dhexme_cb.getSelectedItem()).equals("Yes"));
199+ pd_agg.setMax("hexme", ((String)hexme_cb.getSelectedItem()).equals("Yes"));
200+ pd_agg.setMax("hexnacme", ((String)hexnacme_cb.getSelectedItem()).equals("Yes"));
201+
202+ pd_agg.setMax("neuac", true); // ガングリオシドの予測なのでNeuAcを指定
203+ }
204+ catch (Exception e)
205+ {
206+ throw new Exception("'max' contains error.\n" + e);
207+ }
208+
209+ try // セラミド組成を登録
210+ {
211+ java.util.List<String> ceramide = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
212+ java.util.List<String> lcb = new ArrayList<String>(); // 既知の長鎖塩基組成を格納する.
213+ java.util.List<String> fa = new ArrayList<String>(); // 既知の脂肪酸組成を格納する.
214+
215+ for (String str : ceramide_tf.getText().split("[^\\w:-]")) // 単語構成文字と':','-'以外の文字列で分割
216+ if (str.matches("^[dt][ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // セラミドの場合
217+ ceramide.add(str);
218+ else if (str.matches("^[dt][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 長鎖塩基の場合
219+ lcb.add(str);
220+ else if (str.matches("^[ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 脂肪酸の場合
221+ fa.add(str);
222+
223+ pd_agg.setCeramide(ceramide); // セラミド組成を登録
224+ pd_agg.setLongChainBase(lcb); // 長鎖塩基組成を登録
225+ pd_agg.setFattyAcid(fa); // 脂肪酸組成を登録
226+ }
227+ catch (Exception e)
228+ {
229+ throw new Exception("'Ceramide' contains error.\n" + e);
230+ }
231+
232+ try // スコアリングの式を登録
233+ {
234+ String temp = (String)formula_cb.getSelectedItem(); // 選択されたスコアリングの式を取得する.
235+ if (temp.equals("POSITIVE"))
236+ pd_agg.setScoringFormula(Candidate.POSITIVE_SCORING);
237+ else if (temp.equals("TFIDF"))
238+ pd_agg.setScoringFormula(Candidate.TFIDF_SCORING);
239+ else if (temp.equals("PENALTY01"))
240+ pd_agg.setScoringFormula(Candidate.PENALTY01_SCORING);
241+ else if (temp.equals("PENALTY001"))
242+ pd_agg.setScoringFormula(Candidate.PENALTY001_SCORING);
243+ else if (temp.equals("PMF"))
244+ pd_agg.setScoringFormula(Candidate.PMF_SCORING);
245+ else if (temp.equals("GEOMETRICAVG"))
246+ pd_agg.setScoringFormula(Candidate.GEOMETRICAVG_SCORING);
247+ else
248+ throw new Exception(temp + " is unknown adduct ion.");
249+ }
250+ catch (Exception e)
251+ {
252+ throw new Exception("'Scoring' contains error.\n" + e);
253+ }
254+
255+ try // 出現確率分布のウィンドウサイズを登録
256+ {
257+ pd_agg.setWindowSize(1);
258+ }
259+ catch (Exception e)
260+ {
261+ throw new Exception("'Window size' contains error.\n" + e);
262+ }
263+ // 出力部
264+ java.util.List<? extends Candidate> cds = pd_agg.getPrediction();
265+ Iterator<? extends Candidate> it = cds.iterator();
266+ DefaultTableModel tm = new DefaultTableModel(title, 0);
267+ for (int i = 0; i < 50 && it.hasNext(); i++) // 上位50候補を表示
268+ {
269+ Candidate cd = it.next();
270+
271+ String[] table = new String[4]; // カラムの追加時は,配列の大きさに注意する.
272+ table[0] = String.format("%.4f", cd.getScore());
273+
274+ try
275+ {
276+ table[1] = ((CandidateGa)cd).getIntactGlycan().toNormalFormat(); // ノーマルのフォーマットで格納
277+ }
278+ catch (Exception e)
279+ {
280+ table[1] = ((CandidateGa)cd).getIntactGlycan().toString(); // 二分岐以上はLinucs形式で格納
281+ }
282+
283+ table[2] = String.format("%.4f", cd.getOccupancy());
284+ table[3] = String.format("%.4f", ((CandidateGa)cd).getIntactGlycan().getMass(monoavg, adduct));
285+ tm.addRow(table);
286+ }
287+ result_ta.setModel(tm);
288+ RowSorter<TableModel> rs = new TableRowSorter<TableModel>(tm); // ソート可能なテーブルにする.
289+ result_ta.setRowSorter(rs);
290+ super.resetTableColumnSize(); // カラム幅を指定する.
291+
292+ java.awt.Toolkit.getDefaultToolkit().beep(); // 終了する時にビープ音を鳴らす.
293+
294+ UIManager.put("OptionPane.messageDialogTitle", "Messege"); // "タイトルを"Messege"に変更
295+ UIManager.put("OptionPane.okButtonText", "OK"); // "了解"の部分を"OK"に変更
296+ JOptionPane.showMessageDialog(jf, "Calclation is finished.\n" + pm.getNote() + "\n"
297+ + "Candidate structure: " + cds.size());
298+ start.setEnabled(true); // ボタンを押せるようにする.
299+ reset.setEnabled(true);
300+ }
301+ catch (Exception e) // 処理中に例外が発生した場合,
302+ { // 警告を表示し処理を中断
303+ JOptionPane.showMessageDialog(jf, "ERROR: " + e);
304+ e.printStackTrace();
305+ start.setEnabled(true); // ボタンを押せるようにする.
306+ reset.setEnabled(true);
307+ }
308+ }
309+
310+ public static void main(String[] args) throws Exception
311+ {
312+ new PredictionGUIGa();
313+ }
314+}
--- jp/ac/ritsumei/is/infobio/Isotope.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/Isotope.java (revision 1)
@@ -0,0 +1,110 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.io.*;
3+import java.util.*;
4+import javax.servlet.*;
5+import javax.servlet.http.*;
6+import org.jfree.chart.*;
7+import org.jfree.data.*;
8+import org.jfree.data.xy.*;
9+import org.jfree.data.general.*;
10+import org.jfree.chart.*;
11+import org.jfree.chart.plot.*;
12+import org.jfree.chart.axis.*;
13+import org.jfree.ui.*;
14+
15+class IsotopeXYDataset extends AbstractSeriesDataset implements XYDataset
16+{
17+ double[] mass = {812.0, 813.0, 814.0, 815.0, 816.0};
18+ double[] intensity = {0.1, 0.8, 0.7, 0.8, 1.0};
19+ double fwhm = 5000.0; // 半値幅(高いほど分解能が良い)
20+
21+ public IsotopeXYDataset(double[] mass, double[] intensity)
22+ {
23+ this.mass = mass;
24+ this.intensity = intensity;
25+ }
26+
27+ public int getItemCount(int series)
28+ {
29+ return 200; // 媒介変数の数
30+ }
31+
32+ public double getXValue(int series, int item)
33+ {
34+ return ((double)item) / 100.0 + mass[series] - 1.0; // 1.0Da手前から表示
35+ }
36+
37+ /**
38+ * シリーズ,媒介変数を指定に応じたYの値.
39+ */
40+ public double getYValue(int series, int item)
41+ {
42+ double x = ((double)item) / 100.0 + mass[series] - 1.0; // 1.0Da手前から表示
43+ return Math.exp(-1.0 * Math.pow((x - mass[series]) / (x / 10000), 2)) * intensity[series] * 100;
44+ }
45+
46+ /**
47+ * 表示するグラフ数を返す.
48+ */
49+ public int getSeriesCount()
50+ {
51+ return mass.length; // 配列に入っているグラフを表示する.
52+ }
53+
54+ public Comparable getSeriesKey(int key)
55+ {
56+ if (key == 0)
57+ return "Monoisotopic";
58+ else if (key == 1)
59+ return "1st isotopic";
60+ else if (key == 2)
61+ return "2nd isotopic";
62+ else if (key == 3)
63+ return "3rd isotopic";
64+ else
65+ return key + "th isotopic";
66+ }
67+
68+ public Number getX(int series, int item) {return getXValue(series, item);}
69+ public Number getY(int series, int item) {return getYValue(series, item);}
70+ public DomainOrder getDomainOrder() {return DomainOrder.NONE;}
71+}
72+
73+/**
74+ * 同位体イオンのイオン化強度を表示するServletクラスです.
75+ * @author 横井一仁
76+ * @version 20081216
77+ */
78+public class Isotope extends HttpServlet
79+{
80+ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
81+ {
82+ List<Double> li_mass = new ArrayList<Double>();
83+ List<Double> li_intensity = new ArrayList<Double>();
84+
85+ String str;
86+ for (int i = 0; (str = request.getParameter("mass" + i)) != null; i++) // 引数から読み取る.
87+ li_mass.add(Double.parseDouble(str));
88+
89+ for (int i = 0; (str = request.getParameter("intensity" + i)) != null; i++)
90+ li_intensity.add(Double.parseDouble(str));
91+
92+ double[] mass = new double[li_mass.size()]; // リストから配列へ変換
93+ Iterator<Double> it_mass = li_mass.iterator();
94+ for (int i = 0; it_mass.hasNext(); i++)
95+ mass[i] = it_mass.next();
96+
97+ double[] intensity = new double[li_intensity.size()]; // リストから配列へ変換
98+ Iterator<Double> it_intensity = li_intensity.iterator();
99+ for (int i = 0; it_intensity.hasNext(); i++)
100+ intensity[i] = it_intensity.next();
101+
102+ XYDataset xy = new IsotopeXYDataset(mass, intensity);
103+ JFreeChart jc = ChartFactory.createXYLineChart("", "m/z", "Intensity (%)",
104+ xy, PlotOrientation.VERTICAL,
105+ true, true, true);
106+ response.setContentType("image/png"); // PNG形式で画像を出力
107+ ServletOutputStream so = response.getOutputStream();
108+ ChartUtilities.writeChartAsPNG(so, jc, 500, 300); // 500×300ピクセル
109+ }
110+}
--- jp/ac/ritsumei/is/infobio/PredictionMe.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/PredictionMe.java (revision 1)
@@ -0,0 +1,392 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+
4+/**
5+ * メチル化後糖脂質のフラグメントイオンから構造を予測するクラスです.
6+ * @author 横井一仁
7+ * @version 20090128
8+ */
9+class CandidateMe extends Candidate
10+{
11+ Glycan before_gc; // メチル化前の糖鎖構造を格納
12+ static double precursor_me; // メチル化後のプレカーサーマス
13+
14+ public CandidateMe(Glycan gc) throws Exception
15+ {
16+ super(); // 何もしないスーパークラスのコンストラクタ
17+ before_gc = new Glycan(gc.toString()); // メチル化前の構造を格納しておく.
18+
19+ gc.methylation(); // メチル化を行う.
20+
21+ this.setNode(gc.getNode()); // メチル化後の構造を登録する.
22+ this.setEdge(gc.getEdge());
23+ this.setChildren(gc.getChildren());
24+
25+ double ceramide_remove; // メチル化後の理論値と実測値から,
26+ if (precursor_me != 0.0) // セラミドの分子量がどれだけ減少したかを計算する.
27+ ceramide_remove = this.getMass(monoavg, adduct) - precursor_me;
28+ else // メチル化後の実測値が登録されていない場合は,例外
29+ throw new Exception("Error: Set mathylated precursor mass, use setPrecursorMeMass()");
30+
31+ fg.setGlycan(this);
32+ this.frags_t = fg.getComposition(); // それぞれのフラグメントを取得
33+ this.masses_t = new double[this.frags_t.size()]; // フラグメント数と同じサイズの配列を用意
34+
35+ int i = 0;
36+ for (Composition temp : this.frags_t) // フラグメントの分子量を計算しておく
37+ if (temp.hasCeramide()) // セラミドが存在する場合は,誤差を考慮
38+ masses_t[i++] = temp.getMass(monoavg, adduct) - ceramide_remove;
39+ else
40+ masses_t[i++] = temp.getMass(monoavg, adduct); // そのままメチル化糖のm/zを登録する.
41+ }
42+
43+ /**
44+ * メチル化後の親マスを登録します.
45+ * @param precursor_me メチル化後の親マス
46+ */
47+ public static void setPrecursorMeMass(double precursor_me)
48+ {
49+ CandidateMe.precursor_me = precursor_me; // メンバ変数として格納
50+ }
51+
52+ /*
53+ * メチル化前の糖鎖構造を返します.
54+ * @return メチル化前の糖鎖構造
55+ */
56+ public Glycan getIntactGlycan()
57+ {
58+ return before_gc;
59+ }
60+}
61+
62+/**
63+ * メチル化糖の構造予測を行うクラスです.
64+ * @author 横井一仁
65+ * @version 20080725
66+ */
67+public class PredictionMe extends Prediction
68+{
69+ double precursor_me = 0.0; // メチル化後の親マス
70+ CompositionToolsMe cm_agg = new CompositionToolsMe(); // インタクトのプレカーサーマスが入力なしの場合に用いる.
71+
72+ /**
73+ * コンストラクタ
74+ */
75+ public PredictionMe()
76+ {
77+ super();
78+ }
79+
80+ /**
81+ * モノアイソトープ,またはアベレージで計算するかを設定します.
82+ * @param monoavg モノアイソトピックまたはアベレージ.
83+ */
84+ public void setMonoavg(boolean monoavg) throws Exception
85+ {
86+ Candidate.setMonoavg(monoavg); // Candidateクラスのstatic変数として登録
87+ cp_agg.setMonoavg(monoavg); // 組成を予測するクラスのメソッドを利用して登録
88+ cm_agg.setMonoavg(monoavg); // 組成を予測するクラスのメソッドを利用して登録
89+ }
90+
91+ /**
92+ * 予測に用いる付加イオンを指定します.
93+ * @param adduct 付加イオン(デフォルトはNa+)
94+ */
95+ public void setAdduct(String adduct) throws Exception
96+ {
97+ Candidate.setAdduct(adduct); // Candidateクラスのstatic変数として登録
98+ cp_agg.setAdduct(adduct); // 組成を予測するクラスのメソッドを利用して登録
99+ cm_agg.setAdduct(adduct); // 組成を予測するクラスのメソッドを利用して登録
100+ }
101+
102+ /**
103+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
104+ * @param lcb 長鎖塩基組成
105+ */
106+ public void setLongChainBase(java.util.List<String> lcb) throws Exception
107+ {
108+ cp_agg.setLongChainBase(lcb);
109+ cm_agg.setLongChainBase(lcb);
110+ }
111+
112+ /**
113+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
114+ * @param fa 脂肪酸組成
115+ */
116+ public void setFattyAcid(java.util.List<String> fa) throws Exception
117+ {
118+ cp_agg.setFattyAcid(fa);
119+ cm_agg.setFattyAcid(fa);
120+ }
121+
122+ /**
123+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
124+ * @param min 炭素数の最小値
125+ * @param max 炭素数の最大値
126+ */
127+ public void setLongChainBase(int min, int max) throws Exception
128+ {
129+ cp_agg.setLongChainBase(min, max);
130+ cm_agg.setLongChainBase(min, max);
131+ }
132+
133+ /**
134+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
135+ * @param min 炭素数の最小値
136+ * @param max 炭素数の最大値
137+ */
138+ public void setFattyAcid(int min, int max, int bond) throws Exception
139+ {
140+ cp_agg.setFattyAcid(min, max, bond);
141+ cm_agg.setFattyAcid(min, max, bond);
142+ }
143+
144+ /**
145+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
146+ * @param ceramide セラミド組成
147+ */
148+ public void setCeramide(java.util.List<String> ceramide) throws Exception
149+ {
150+ cp_agg.setCeramide(ceramide);
151+ cm_agg.setCeramide(ceramide);
152+ }
153+
154+ /**
155+ * 糖鎖組成の予測に用いるセラミド組成を登録します.
156+ * @param min 炭素数の最小値
157+ * @param max 炭素数の最大値
158+ * @param bond 脂肪酸の二重結合の最大値
159+ */
160+ public void setCeramide(int min, int max, int bond)
161+ {
162+ cp_agg.setCeramide(min, max, bond);
163+ cm_agg.setCeramide(min, max, bond);
164+ }
165+
166+ /**
167+ * 予測で考慮する各糖の糖数を指定します.
168+ * @param str 糖数を指定する糖
169+ * @param max 指定する糖数
170+ */
171+ public void setMax(String str, int max) throws Exception
172+ {
173+ cp_agg.setMax(str, max);
174+ cm_agg.setMax(str, max);
175+ }
176+
177+ /**
178+ * 予測で考慮する各糖の糖数を指定します.
179+ * @param str 指定する糖
180+ * @param bl 糖を存在させるかを指定
181+ */
182+ public void setMax(String str, boolean bl) throws Exception
183+ {
184+ cp_agg.setMax(str, bl);
185+ cm_agg.setMax(str, bl);
186+ }
187+
188+ /**
189+ * メチル化後の親マスを登録します.
190+ * @param precursor_me メチル化後の親マス
191+ */
192+ public void setPrecursorMeMass(double precursor_me)
193+ {
194+ this.precursor_me = precursor_me; // メンバ変数として格納
195+ CandidateMe.setPrecursorMeMass(precursor_me); // CandidateMeのスタティック変数としても登録
196+ }
197+
198+ // 候補組成を生成し,リストに格納する.
199+ protected java.util.List<Composition> getCandidateCompositionMe() throws Exception
200+ {
201+ System.out.print("canndidate compositions are predicting from only premethylaed precursor mass, ");
202+ System.out.println("because intact precusor mass is null.");
203+ java.util.List<Composition> cps; // 考えられる組成を格納するリスト
204+
205+ cm_agg.setComposition(known_cp);
206+ cm_agg.setGlycan(known_gc);
207+ cm_agg.setMsTolerance(tolerance_ms);
208+ cm_agg.setMass(precursor_me);
209+ cps = cm_agg.getComposition();
210+
211+ return cps;
212+ }
213+
214+ /**
215+ * 予測された候補構造を返します.
216+ * @return スコアが高い順に予想構造を返します.
217+ */
218+ public java.util.List<? extends Candidate> getPrediction() throws Exception
219+ { // 指定された条件から候補構造を生成します.
220+ java.util.List<Composition> cps;
221+ if (precursor == 0.0) // インタクトのプレカーサーマスが登録されていない場合,
222+ cps = getCandidateCompositionMe(); // メチル化後のプレカーサーマスのみから候補組成を作成
223+ else
224+ cps = getCandidateComposition(); // 両方存在している場合は,両方から予測
225+
226+ java.util.List<Glycan> candi = this.getCandidateGlycan(cps); // 候補構造を生成し,リストに格納
227+ java.util.List<CandidateMe> al = this.toCandidateMeInstance(candi); // Glycanの候補構造を,
228+ // CandidateMeの候補構造として登録
229+ CandidateMe.setFreq(this.getFreqency(al)); // 出現確率を計算し,
230+ // CandidateMeクラスのstatic変数として登録
231+ Collections.sort(al, new Comparator<CandidateMe>() // スコア順にソート
232+ {
233+ public int compare(CandidateMe cp1, CandidateMe cp2)
234+ {
235+ double sub = 0.0; // スコアの差
236+ try
237+ {
238+ double score1 = cp1.getScore();
239+ double score2 = cp2.getScore();
240+
241+ if (score1 == score2) // スコアが等しい構造は,分岐数の少ない
242+ sub = cp1.countLeaf() - cp2.countLeaf(); // (葉ノード数が少ない)構造を上位に表示
243+ else
244+ sub = score2 - score1;
245+
246+ }
247+ catch (Exception e)
248+ {
249+ System.err.println("Prediction.getPrediction(): score compare error");
250+ }
251+
252+ return (int)(sub*1024); // 精度を1024倍に上げる
253+ }
254+ });
255+
256+ return al;
257+ }
258+
259+ /**
260+ * 候補組成を生成し,リストに格納する.
261+ */
262+ protected java.util.List<Composition> getCandidateComposition() throws Exception
263+ { // メチル化前の親マスのみから組成を予測する.親クラスはフラグメントからも予測
264+ java.util.List<Composition> cps; // 考えられる組成を格納するリスト
265+
266+ cp_agg.setComposition(known_cp);
267+ cp_agg.setGlycan(known_gc);
268+ cp_agg.setMsTolerance(tolerance_ms);
269+
270+ if (precursor == 0.0) // 親マスの分子量が登録されていない場合,
271+ { // フラグメント分子量の最大実測値から計算
272+ Arrays.sort(masses_a); // 最大値を取り出すために昇順にソート
273+ cp_agg.setMass(masses_a[masses_a.length-1]);
274+ cps = cp_agg.getComposition();
275+ }
276+ else // 親マスの分子量が登録されている場合
277+ {
278+ cp_agg.setMass(precursor);
279+ cps = cp_agg.getComposition();
280+ }
281+
282+ ListIterator<Composition> it = cps.listIterator();
283+ while (it.hasNext())
284+ {
285+ Composition cp = new Composition(it.next());
286+
287+ int count = cp.countHydroxy();
288+ for (int i = 0; i < count; i++) // ヒドロキシル基の個数分のメチル基を付加
289+ cp.add("me");
290+
291+ double mass = cp.getMass(true, MassCalc.Na_ION); // 理論上のメチル化物と実測のメチル化物との誤差が,
292+ if (Math.abs(mass - precursor_me) > 20.0) // 指定した条件以上の組成を候補組成から除外する.
293+ {
294+ System.out.println(cp + "is removed." + mass + "-" + precursor_me + "=" + (mass - precursor_me));
295+ it.remove(); // メチル基1つ分のため,許容誤差は14〜28Daの範囲の値20.0
296+ }
297+ }
298+
299+ return cps;
300+ }
301+
302+ /**
303+ * Glycanインスタンスの候補構造を,CandidateMeインスタンスの候補構造とし,フラグメント化を行う.
304+ */
305+ protected java.util.List<CandidateMe> toCandidateMeInstance(java.util.List<Glycan> candi) throws Exception
306+ {
307+ java.util.List<CandidateMe> al = new ArrayList<CandidateMe>(); // スコア付けを行う候補構造
308+ long start = new Date().getTime(); // プログラム開始時刻
309+ int candi_size = candi.size(); // 候補構造数を格納
310+ ListIterator<Glycan> it2 = candi.listIterator(); // 候補構造のイテレータを取得
311+ for (int i = 1; it2.hasNext() && flag; i++) // 考えられる組成のとり得る構造をリストに格納
312+ {
313+ Glycan temp = it2.next();
314+ it2.remove(); // 不必要であるGlycanインスタンスを削除
315+
316+ percent = (int)(i * 99.0 / candi_size); // 処理が何%進んだか(表示が消えるため99%)
317+ String messege = progress(i, candi_size, start); // オブザーバに送るメッセージを作成する.
318+ try
319+ {
320+ messege = messege + " [" + temp.toNormalFormat() + "]"; // ノーマルのフォーマットで格納する.
321+ }
322+ catch (Exception e)
323+ {
324+ messege = messege + " [" + temp.toString() + "]"; // 二分岐以上の構造はLinucs形式で格納する.
325+ }
326+ this.setChanged(); // 変更があったことを明示する.
327+ this.notifyObservers(messege); // 監視者に進行状況を通知
328+ this.clearChanged(); // 変更された状態でないことを明示する.
329+
330+ CandidateMe cd = new CandidateMe(temp);
331+ al.add(cd);
332+ }
333+
334+ if (!flag) // 処理が中断された場合,
335+ al.clear(); // CandidateMeインスタンスの候補構造を削除
336+ else // 処理が正常に完了した場合,
337+ {
338+ percent = 100; // ProgressMonitorを終了するために100%にする.
339+ this.setChanged(); // 変更があったことを明示する.
340+ this.notifyObservers(progress(candi.size(), candi.size(), start)); // 監視者に進行状況を通知
341+ this.clearChanged(); // 変更された状態でないことを明示する.
342+ }
343+
344+ return al;
345+ }
346+
347+ /**
348+ * フラグメントの出現確率の計算値を返します.
349+ */
350+ public double[] getFreqency(java.util.List<? extends Candidate> al) throws Exception
351+ {
352+ double[] freq; // returnする確率分布
353+
354+ if (precursor_me == 0.0) // 親マスの分子量が登録されていない場合,
355+ { // フラグメント分子量の最大実測値から計算
356+ Arrays.sort(masses_a); // 最大値を取り出すために昇順にソート.
357+ freq = new double[(int)(masses_a[masses_a.length-1]/this.getWindowSize())+100]; // 1Daずつ出現頻度を計算
358+ }
359+ else // 親マスの分子量が登録されている場合
360+ freq = new double[(int)(precursor_me/this.getWindowSize())+100]; // 1Daずつ出現頻度を計算する.
361+
362+ for (Candidate cd : al)
363+ {
364+ boolean[] check = new boolean[freq.length]; // 1構造で重複しないようにするフラッグ
365+
366+ double[] masses = cd.getFragMasses();
367+ for (int i = 0; i < masses.length; i++) // それぞれのフラグメントを取得し,
368+ { // フラグメントが存在したらtrueとする.
369+ if ((int)(masses[i]/this.getWindowSize()) > 0)
370+ check[(int)(masses[i]/this.getWindowSize()) - 1] = true; // 前のフラッグを立てる.
371+
372+ check[(int)(masses[i]/this.getWindowSize())] = true; // 現在の位置のフラッグを立てる.
373+
374+ if (i+1 < freq.length)
375+ check[(int)(masses[i]/this.getWindowSize()) + 1] = true; // 後ろのフラッグも立てる.
376+ }
377+
378+ for (int i = 0; i < freq.length; i++) // フラッグを出現確率の配列へコピー
379+ if (check[i]) // フラグメントが存在したら1個増加
380+ freq[i] += 1.0;
381+ }
382+
383+ double max = 1.0; // 0で割らないために初期値は1
384+ for (double temp : freq) // 最大値を探す.
385+ max = Math.max(temp,max);
386+
387+ for (int i = 0; i < freq.length; i++) // 最大値で割ることで
388+ freq[i] = freq[i] / max; // 0.0〜1.0をとるように変換
389+
390+ return freq;
391+ }
392+}
--- jp/ac/ritsumei/is/infobio/CompositionTools.java (nonexistent)
+++ jp/ac/ritsumei/is/infobio/CompositionTools.java (revision 1)
@@ -0,0 +1,1034 @@
1+package jp.ac.ritsumei.is.infobio;
2+import java.util.*;
3+import java.util.regex.*;
4+import java.io.*;
5+
6+/**
7+ * 実測の<I>m/z</I> から糖鎖,糖脂質の組成を予測するクラスです.
8+ * @author 横井一仁
9+ * @version 20081221
10+ */
11+public class CompositionTools extends Observable // 進行状況の監視を可能とする.
12+{
13+ ArrayList<Composition> al_cp = new ArrayList<Composition>(); // Compositionを格納する.
14+ double mass_a = 0.0; // m/zの実測値
15+ double[] masses_a; // m/zの実測値(複数のフラグメントから予測する場合に用いる)
16+ double tolerance_ms = 0.5; // 指定がなければ,0.5とする.
17+ double tolerance_psd = 1.0; // 実測値と理論値の許容誤差(PSD)
18+ Set<String> ceramide = new HashSet<String>(); // 既知のセラミド組成を格納する.
19+ Set<String> lcb = new HashSet<String>(); // 既知の長鎖塩基組成を格納する.
20+ Set<String> fa = new HashSet<String>(); // 既知の脂肪酸組成を格納する.
21+ Glycan known_gc; // 既知構造
22+ Composition known_cp; // 既知組成
23+ String adduct = MassCalc.Na_ION; // 付加イオン(デフォルトはNa+)
24+ boolean monoavg = MassCalc.MONO_MASS; // Monoisotopic(ture), Average(false)
25+ int hex_max = 10 ;
26+ int hexnac_max = 10 ;
27+ int dhex_max = 10 ;
28+ int pen_max = 0 ;
29+ int hexme_max = 0 ;
30+ int hexnacme_max = 0 ;
31+ int dhexme_max = 0 ;
32+ int penme_max = 0 ;
33+ int kdn_max = 0 ;
34+ int neuac_max = 0 ;
35+ int neugc_max = 0 ;
36+
37+ /**
38+ * 予測された組成を返します.
39+ * @return 質量誤差の少ない順に格納して返します.
40+ */
41+ public List<Composition> getComposition() throws Exception
42+ {
43+ if (masses_a != null && masses_a.length > 0) // 複数のフラグメントが入力されている場合
44+ return getCompositionFromMultiple();
45+ else
46+ {
47+ if (mass_a != 0.0) // mass_aにのみm/zが登録されている場合
48+ return getCompositionFromSingle();
49+ else // 予測に必要なm/zが登録されていない時,空のリストを返す.
50+ {
51+ System.err.println("CompositionTools returns null composition.");
52+ return new ArrayList<Composition>();
53+ }
54+ }
55+ }
56+
57+ /**
58+ * 指定された条件から組成を予測します.(指定された<I>m/z</I> が複数存在する場合)
59+ * @return Compositionを格納したList
60+ */
61+ private List<Composition> getCompositionFromMultiple() throws Exception
62+ {
63+ al_cp.clear(); // クラスの再利用の時のために要素を全て削除する.
64+
65+ CompositionTools ci = new CompositionTools(); // 組成を予測するインスタンスを作成する.
66+ ci.setComposition(known_cp); // 既知組成を登録
67+ ci.setGlycan(known_gc); // 既知構造を登録
68+ ci.setCeramide(new ArrayList<String>(ceramide)); // 既知セラミド組成を登録(SetをArrayListに変換)
69+ ci.setMsTolerance(tolerance_ms); // 許容誤差を登録
70+ ci.setAdduct(adduct); // 付加イオンを登録
71+ ci.setMonoavg(monoavg); // MonoisotopicかAverageを選択
72+ ci.setMax("hex", hex_max); // 各糖の最大数を指定する.
73+ ci.setMax("hexnac", hexnac_max);
74+ ci.setMax("dhex", dhex_max);
75+ ci.setMax("pen", pen_max);
76+ ci.setMax("hexme", hexme_max);
77+ ci.setMax("hexnacme", hexnacme_max);
78+ ci.setMax("dhexme", dhexme_max);
79+ ci.setMax("penme", penme_max);
80+ ci.setMax("kdn", kdn_max);
81+ ci.setMax("neuac", neuac_max);
82+ ci.setMax("neugc", neugc_max);
83+
84+ int length; // 配列の何番目まで読み込むかを指定する.
85+ if (mass_a != 0.0) // 予測したい質量が入力されている場合は,
86+ {
87+ ci.setMass(mass_a); // そのm/zから予測を行う.
88+ length = masses_a.length; // 全てのフラグメントを読み込む
89+ }
90+ else // 入力されていない場合は,
91+ {
92+ Arrays.sort(masses_a); // フラグメントのm/zが登録されいる配列を昇順にソートし,
93+ ci.setMass(masses_a[masses_a.length-1]); // 最大のm/zから組成を予測
94+ length = masses_a.length - 1; // 最後のフラグメントは読み込まない.
95+ }
96+
97+ Map<Integer, List<Composition>> mp = new HashMap<Integer, List<Composition>>(); // 各フラグメントの組成を格納
98+ for (int i = 0; i < length; i++) // 各フラグメントの組成を予測
99+ {
100+ List<Composition> li = new ArrayList<Composition>(); // 格納用のList
101+ CompositionTools ci2;
102+
103+ if (ceramide != null && ceramide.size() != 0) // セラミドが登録されている場合
104+ { // フラグメントを糖脂質として組成予測を行う.
105+ ci2 = new CompositionTools(); // 組成を予測するインスタンスを作成する.
106+ ci2.setCeramide(new ArrayList<String>(ceramide)); // 既知セラミド組成を登録(SetをArrayListに変換)
107+ ci2.setMsTolerance(tolerance_psd); // 許容誤差を登録(PSDであることに注意!)
108+ ci2.setAdduct(adduct); // 付加イオンを登録
109+ ci2.setMonoavg(monoavg); // MonoisotopicかAverageを選択
110+ ci2.setMass(masses_a[i]);
111+ ci2.setMax("hex", hex_max); // 各糖の最大数を指定する.
112+ ci2.setMax("hexnac", hexnac_max);
113+ ci2.setMax("dhex", dhex_max);
114+ ci2.setMax("pen", pen_max);
115+ ci2.setMax("hexme", hexme_max);
116+ ci2.setMax("hexnacme", hexnacme_max);
117+ ci2.setMax("dhexme", dhexme_max);
118+ ci2.setMax("penme", penme_max);
119+ ci2.setMax("kdn", kdn_max);
120+ ci2.setMax("neuac", neuac_max);
121+ ci2.setMax("neugc", neugc_max);
122+ li.addAll(ci2.getComposition()); // 以上の条件から組成を予測する.
123+ }
124+ // フラグメントを糖鎖として組成予測を行う.
125+ ci2 = new CompositionTools(); // 組成を予測するインスタンスを作成する.
126+ ci2.setMsTolerance(tolerance_psd); // 許容誤差を登録(PSDであることに注意!)
127+ ci2.setAdduct(adduct); // 付加イオンを登録
128+ ci2.setMonoavg(monoavg); // MonoisotopicかAverageを選択
129+ ci2.setMass(masses_a[i]);
130+ ci2.setMax("hex", hex_max); // 各糖の最大数を指定する.
131+ ci2.setMax("hexnac", hexnac_max);
132+ ci2.setMax("dhex", dhex_max);
133+ ci2.setMax("pen", pen_max);
134+ ci2.setMax("hexme", hexme_max);
135+ ci2.setMax("hexnacme", hexnacme_max);
136+ ci2.setMax("dhexme", dhexme_max);
137+ ci2.setMax("penme", penme_max);
138+ ci2.setMax("kdn", kdn_max);
139+ ci2.setMax("neuac", neuac_max);
140+ ci2.setMax("neugc", neugc_max);
141+ li.addAll(ci2.getComposition()); // 以上の条件から組成を予測する.
142+ // フラグメントを脱水した糖鎖として組成予測を行う.
143+ ci2 = new CompositionTools(); // 組成を予測するインスタンスを作成する.
144+ Composition temp_cp = new Composition(); // 脱水した糖鎖に対応するために新しいインスタンスを生成
145+ temp_cp.add("-h2o"); // 脱水した糖鎖に対応するために"-h2o"を追加
146+ ci2.setComposition(temp_cp); // 既知組成を登録
147+ ci2.setMsTolerance(tolerance_psd); // 許容誤差を登録(PSDであることに注意!)
148+ ci2.setAdduct(adduct); // 付加イオンを登録
149+ ci2.setMonoavg(monoavg); // MonoisotopicかAverageを選択
150+ ci2.setMass(masses_a[i]);
151+ ci2.setMax("hex", hex_max); // 各糖の最大数を指定する.
152+ ci2.setMax("hexnac", hexnac_max);
153+ ci2.setMax("dhex", dhex_max);
154+ ci2.setMax("pen", pen_max);
155+ ci2.setMax("hexme", hexme_max);
156+ ci2.setMax("hexnacme", hexnacme_max);
157+ ci2.setMax("dhexme", dhexme_max);
158+ ci2.setMax("penme", penme_max);
159+ ci2.setMax("kdn", kdn_max);
160+ ci2.setMax("neuac", neuac_max);
161+ ci2.setMax("neugc", neugc_max);
162+ for (Composition temp : ci2.getComposition()) // 以上の条件から組成を予測し,
163+ {
164+ temp.remove("-h2o"); // 水分子を削除した後,
165+ li.add(temp); // リストへ追加.
166+ }
167+
168+ mp.put(i, li); // 以上の3種類のフラグメント組成をマップに格納する
169+ }
170+
171+ // 以下のプログラムは,3段階に分けて組成を予測している.
172+ // まず実測フラグメントから考えられる組成を1/4以上持つ,親マスから計算した組成をリストに格納する.
173+ // そして,1/4以上持つ組成が存在しない場合は,1/8以上持つ組成を格納する.
174+ // 1/4も1/8も全ての組成が満たさない場合は,最終手段で1つ以上組成を持っているものを格納する.
175+ ArrayList<Composition> al_cp1 = new ArrayList<Composition>(); // 補欠組成1
176+ ArrayList<Composition> al_cp2 = new ArrayList<Composition>(); // 補欠組成2
177+ for (Composition cp : ci.getComposition()) // 以上の条件から組成を予測する.
178+ {
179+ int count = 0; // 候補組成がフラグメントから得た組成を,いくつ持っているかをカウントする.
180+
181+ for (int key : mp.keySet())
182+ {
183+ Iterator<Composition> it = mp.get(key).iterator();
184+ boolean flag = true; // while文を抜けるためのフラッグ
185+ while (it.hasNext() && flag)
186+ {
187+ Composition temp = new Composition(cp);
188+ temp.toHexose(); // "Glc", "Gal"などを"Hex"へ変換
189+ if (temp.containsAll(it.next())) // cpに登録されている組成が,it.next()の組成を全て持っている時
190+ {
191+ count++; // 一致したフラグメントの個数をカウントし,
192+ flag = false; // while文を抜け,次のフラグメントとのマッチングを行う.
193+ }
194+ }
195+ }
196+
197+ if (count >= (int)(length / 2) + 1) // フラグメントから得た組成をx個以上もつ組成を候補組成とする.
198+ al_cp.add(cp); // フラグメント2本のうち1本は試料由来であるという条件
199+ else if (count >= (int)(length / 4) + 1) // フラグメント4本のうち1本は試料由来であるという条件
200+ al_cp1.add(cp); // 出力する組成が存在しない場合に追加する補欠組成とする.
201+ else if (count > 0) // 一致するフラグメントが1つ以上存在した場合は,
202+ al_cp2.add(cp); // 出力する組成が存在しない場合に追加する補欠組成とする.
203+ }
204+
205+ if (al_cp.size() == 0) // フラグメント2本のうち1本は試料由来であるという条件の組成が存在しなかった時,
206+ al_cp.addAll(al_cp1); // フラグメント4本のうち1本は試料由来であるという条件の組成を追加する.
207+
208+ if (al_cp.size() == 0) // それでも条件を満たす組成が存在しなかった時,
209+ al_cp.addAll(al_cp2); // 一致するフラグメントが1つ以上存在した組成を追加する.
210+
211+ return al_cp;
212+ }
213+
214+ /**
215+ * 指定された条件から組成を予測します.(指定された<I>m/z</I> が1つの場合)
216+ * @return Compositionを格納したList
217+ */
218+ private List<Composition> getCompositionFromSingle() throws Exception
219+ {
220+ al_cp.clear(); // クラスの再利用の時のために要素を全て削除する.
221+
222+ Composition cp = new Composition();
223+ if (known_cp != null) // 既知組成が登録されている場合
224+ cp.addAll(known_cp);
225+ else if (known_gc != null) // 既知構造が登録されている場合
226+ cp.addAll(new Composition(known_gc));
227+
228+ double mass_t = cp.getMass(monoavg, adduct);
229+
230+ if (ceramide != null && ceramide.size() != 0) // セラミドが登録されている場合
231+ {
232+ if (mass_a > mass_t)
233+ addCer(cp); // セラミドから検索する.
234+ }
235+ else // セラミドが登録されていない場合は,糖鎖モードとする.
236+ {
237+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
238+ al_cp.add(cp);
239+ else if (mass_a > mass_t)
240+ addHex(cp); // Hexから検索する.
241+ }
242+
243+ final double temp_a = mass_a; // 内部クラスで用いる変数は,finalで宣言する必要がある.
244+ Collections.sort(al_cp, new Comparator<Composition>() // ソートを行う.
245+ {
246+ public int compare(Composition cp1, Composition cp2)
247+ {
248+ double sub = 0.0;
249+
250+ try
251+ {
252+ sub = Math.abs(cp1.getMass(monoavg, adduct) - temp_a)
253+ - Math.abs(cp2.getMass(monoavg, adduct) - temp_a);
254+ } catch (Exception e) {/**/}
255+
256+ return (int)(sub*1024); // compareメソッドの返り値がint型しか受け付けないので1024倍して精度を上げる.
257+ }
258+ });
259+
260+ ceramide.clear(); // 次回の実行する時に同じ組成を2回追加しないように
261+ lcb.clear(); // 既知のセラミド組成,長鎖塩基組成,脂肪酸組成を削除しておく.
262+ fa.clear(); // (これにより,次回実行時に通常通りセラミドを追加できる)
263+
264+ return al_cp;
265+ }
266+
267+ protected void addCer(Composition cp) throws Exception
268+ {
269+ for (String str : ceramide)
270+ {
271+ Composition temp = new Composition(str); // セラミドを登録.
272+ temp.addAll(cp);
273+
274+ double mass_t = temp.getMass(monoavg, adduct);
275+
276+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
277+ al_cp.add(temp);
278+ else
279+ addHex(temp);
280+ }
281+ }
282+
283+ protected void addHex(Composition cp) throws Exception
284+ {
285+ addHexNAc(cp); // HexNAcを追加した構造
286+
287+ Composition temp = new Composition(cp);
288+ if (Collections.frequency(temp,"hex") < hex_max) // 要素を探索し,個数を数える.
289+ {
290+ temp.add("hex");
291+ double mass_t = temp.getMass(monoavg, adduct);
292+
293+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
294+ al_cp.add(temp);
295+ else if (mass_a > mass_t)
296+ addHex(temp);
297+ }
298+ }
299+
300+ protected void addHexNAc(Composition cp) throws Exception
301+ {
302+ adddHex(cp); // dHexを追加した構造
303+
304+ Composition temp = new Composition(cp);
305+ if (Collections.frequency(temp,"hexnac") < hexnac_max) // 要素を探索し,個数を数える.
306+ {
307+ temp.add("hexnac");
308+ double mass_t = temp.getMass(monoavg, adduct);
309+
310+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
311+ al_cp.add(temp);
312+ else if (mass_a > mass_t)
313+ addHexNAc(temp);
314+ }
315+ }
316+
317+ protected void adddHex(Composition cp) throws Exception
318+ {
319+ addPen(cp); // dHexMeを追加した構造
320+
321+ Composition temp = new Composition(cp);
322+ if (Collections.frequency(cp,"dhex") < dhex_max) // 要素を探索し,個数を数える.
323+ {
324+ temp.add("dhex");
325+ double mass_t = temp.getMass(monoavg, adduct);
326+
327+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
328+ al_cp.add(temp);
329+ else if (mass_a > mass_t)
330+ adddHex(temp);
331+ }
332+ }
333+
334+ protected void addPen(Composition cp) throws Exception
335+ {
336+ addHexMe(cp); // HexMeを追加した構造
337+
338+ Composition temp = new Composition(cp);
339+ if (Collections.frequency(temp,"pen") < pen_max) // 要素を探索し,個数を数える.
340+ {
341+ temp.add("pen");
342+ double mass_t = temp.getMass(monoavg, adduct);
343+
344+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
345+ al_cp.add(temp);
346+ else if (mass_a > mass_t)
347+ addPen(temp);
348+ }
349+ }
350+
351+ protected void addHexMe(Composition cp) throws Exception
352+ {
353+ addHexNAcMe(cp); // HexNAcMeを追加した構造
354+
355+ Composition temp = new Composition(cp);
356+ if (Collections.frequency(temp,"hexme") < hexme_max) // 要素を探索し,個数を数える.
357+ {
358+ temp.add("hexme");
359+ double mass_t = temp.getMass(monoavg, adduct);
360+
361+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
362+ al_cp.add(temp);
363+ else if (mass_a > mass_t)
364+ addHexMe(temp);
365+ }
366+ }
367+
368+ protected void addHexNAcMe(Composition cp) throws Exception
369+ {
370+ adddHexMe(cp); // dHexMeを追加した構造
371+
372+ Composition temp = new Composition(cp);
373+ if (Collections.frequency(temp,"hexnacme") < hexnacme_max) // 要素を探索し,個数を数える.
374+ {
375+ temp.add("hexnacme");
376+ double mass_t = temp.getMass(monoavg, adduct);
377+
378+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
379+ al_cp.add(temp);
380+ else if (mass_a > mass_t)
381+ addHexNAcMe(temp);
382+ }
383+ }
384+
385+ protected void adddHexMe(Composition cp) throws Exception
386+ {
387+ addPenMe(cp); // PenMeを追加した構造
388+
389+ Composition temp = new Composition(cp);
390+ if (Collections.frequency(cp,"dhexme") < dhexme_max) // 要素を探索し,個数を数える.
391+ {
392+ temp.add("dhexme");
393+ double mass_t = temp.getMass(monoavg, adduct);
394+
395+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
396+ al_cp.add(temp);
397+ else if (mass_a > mass_t)
398+ adddHexMe(temp);
399+ }
400+ }
401+
402+ protected void addPenMe(Composition cp) throws Exception
403+ {
404+ addKDN(cp); // KDNを追加した構造
405+
406+ Composition temp = new Composition(cp);
407+ if (Collections.frequency(temp,"penme") < penme_max) // 要素を探索し,個数を数える.
408+ {
409+ temp.add("penme");
410+ double mass_t = temp.getMass(monoavg, adduct);
411+
412+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
413+ al_cp.add(temp);
414+ else if (mass_a > mass_t)
415+ addPenMe(temp);
416+ }
417+ }
418+
419+ protected void addKDN(Composition cp) throws Exception
420+ {
421+ addNeuAc(cp); // NeuAcを追加した構造
422+
423+ Composition temp = new Composition(cp);
424+ if (Collections.frequency(temp,"kdn") < kdn_max) // 要素を探索し,個数を数える.
425+ {
426+ temp.add("kdn");
427+ double mass_t = temp.getMass(monoavg, adduct);
428+
429+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
430+ al_cp.add(temp);
431+ else if (mass_a > mass_t)
432+ addKDN(temp);
433+ }
434+ }
435+
436+ protected void addNeuAc(Composition cp) throws Exception
437+ {
438+ addNeuGc(cp); // NeuGcを追加した構造
439+
440+ Composition temp = new Composition(cp);
441+ if (Collections.frequency(cp,"neuac") < neuac_max) // 要素を探索し,個数を数える.
442+ {
443+ temp.add("neuac");
444+ double mass_t = temp.getMass(monoavg, adduct);
445+
446+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
447+ al_cp.add(temp);
448+ else if (mass_a > mass_t)
449+ addNeuAc(temp);
450+ }
451+ }
452+
453+ protected void addNeuGc(Composition cp) throws Exception
454+ {
455+ Composition temp = new Composition(cp);
456+
457+ if (Collections.frequency(temp,"neugc") < neugc_max) // 要素を探索し,個数を数える.
458+ {
459+ temp.add("neugc");
460+ double mass_t = temp.getMass(monoavg, adduct);
461+
462+ if (Math.abs(mass_a - mass_t) < tolerance_ms) // 実測値と理論値との差が許容誤差以下ならば,追加
463+ al_cp.add(temp);
464+ else if (mass_a > mass_t)
465+ addNeuGc(temp);
466+ }
467+ }
468+
469+ /**
470+ * モノアイソトープ,またはアベレージで計算するかを設定します.
471+ * @param monoavg モノアイソトピックまたはアベレージ.
472+ */
473+ public void setMonoavg(boolean monoavg) throws Exception
474+ {
475+ this.monoavg = monoavg; // クラスメンバとする.
476+ }
477+
478+ /**
479+ * 予測に用いる付加イオンを指定します.
480+ * @param adduct 付加イオン(デフォルトはNa+)
481+ */
482+ public void setAdduct(String adduct) throws Exception
483+ {
484+ this.adduct = adduct; // クラスメンバとする.
485+ }
486+
487+ /**
488+ * 予測で考慮する各糖の糖数を指定します.
489+ * @param str 糖数を指定する糖
490+ * @param max 指定する糖数
491+ */
492+ public void setMax(String str, int max) throws Exception
493+ { // デフォルトはhex_max = 10, hexnac_max = 10, dhex_max = 10, dhexme_max = 0, pen_max = 0
494+ if (str.equals("hex"))
495+ hex_max = max;
496+ else if (str.equals("hexnac"))
497+ hexnac_max = max;
498+ else if (str.equals("dhex"))
499+ dhex_max = max;
500+ else if (str.equals("pen"))
501+ pen_max = max;
502+ else if (str.equals("hexme"))
503+ hexme_max = max;
504+ else if (str.equals("hexnacme"))
505+ hexnacme_max = max;
506+ else if (str.equals("dhexme"))
507+ dhexme_max = max;
508+ else if (str.equals("penme"))
509+ penme_max = max;
510+ else if (str.equals("kdn"))
511+ kdn_max = max;
512+ else if (str.equals("neuac"))
513+ neuac_max = max;
514+ else if (str.equals("neugc"))
515+ neugc_max = max;
516+ else
517+ throw new Exception("Unknown glycan cannot setMax(): " + str);
518+ }
519+
520+ /**
521+ * 予測で考慮する各糖の糖数を指定します.(糖数は自動入力)
522+ * @param str 糖数を指定する糖
523+ */
524+ public void setMax(String str, boolean present) throws Exception
525+ {
526+ double temp = 0.0; // 予測に用いるm/zを格納する.
527+
528+ if (mass_a != 0.0) // プレカーサーマスのm/zが登録されている場合,
529+ temp = mass_a;
530+ else if (masses_a != null)
531+ {
532+ Arrays.sort(masses_a); // フラグメントのm/zが登録されいる配列を昇順にソートし,
533+ temp = masses_a[masses_a.length-1]; // 最大のm/zから組成を予測
534+ }
535+
536+ if (present && temp != 0.0) // 予測したいm/zが登録されている場合は,その値から最大数を算出
537+ {
538+ if (str.equals("hex"))
539+ hex_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
540+ else if (str.equals("hexnac"))
541+ hexnac_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
542+ else if (str.equals("dhex"))
543+ dhex_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
544+ else if (str.equals("pen"))
545+ pen_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
546+ else if (str.equals("hexme"))
547+ hexme_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
548+ else if (str.equals("hexnacme"))
549+ hexnacme_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
550+ else if (str.equals("dhexme"))
551+ dhexme_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
552+ else if (str.equals("penme"))
553+ penme_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
554+ else if (str.equals("kdn"))
555+ kdn_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
556+ else if (str.equals("neuac"))
557+ neuac_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
558+ else if (str.equals("neugc"))
559+ neugc_max = (int)(temp / new Composition(str).getMass(monoavg, "")) + 1;
560+ else
561+ throw new Exception("Unknown glycan cannot setMax(): " + str);
562+ }
563+ else if (!present) // 糖が存在しないと指定された場合
564+ {
565+ if (str.equals("hex")) // 糖数を0とする.
566+ hex_max = 0;
567+ else if (str.equals("hexnac"))
568+ hexnac_max = 0;
569+ else if (str.equals("dhex"))
570+ dhex_max = 0;
571+ else if (str.equals("pen"))
572+ pen_max = 0;
573+ else if (str.equals("hexme"))
574+ hexme_max = 0;
575+ else if (str.equals("hexnacme"))
576+ hexnacme_max = 0;
577+ else if (str.equals("dhexme"))
578+ dhexme_max = 0;
579+ else if (str.equals("penme"))
580+ penme_max = 0;
581+ else if (str.equals("kdn"))
582+ kdn_max = 0;
583+ else if (str.equals("neuac"))
584+ neuac_max = 0;
585+ else if (str.equals("neugc"))
586+ neugc_max = 0;
587+ else
588+ throw new Exception("Unknown glycan cannot setMax(): " + str);
589+ }
590+ else // 登録されていない場合は,最大糖数を10とする.
591+ {
592+ if (str.equals("hex"))
593+ hex_max = 10;
594+ else if (str.equals("hexnac"))
595+ hexnac_max = 10;
596+ else if (str.equals("dhex"))
597+ dhex_max = 10;
598+ else if (str.equals("pen"))
599+ pen_max = 10;
600+ else if (str.equals("hexme"))
601+ hexme_max = 10;
602+ else if (str.equals("hexnacme"))
603+ hexnacme_max = 10;
604+ else if (str.equals("dhexme"))
605+ dhexme_max = 10;
606+ else if (str.equals("penme"))
607+ penme_max = 10;
608+ else if (str.equals("kdn"))
609+ kdn_max = 10;
610+ else if (str.equals("neuac"))
611+ neuac_max = 10;
612+ else if (str.equals("neugc"))
613+ neugc_max = 10;
614+ else
615+ throw new Exception("Unknown glycan cannot setMax(): " + str);
616+ }
617+ }
618+
619+ /**
620+ * 既知糖鎖構造を追加します.
621+ * @param known_gc 既知構造
622+ */
623+ public void setGlycan(Glycan known_gc)
624+ {
625+ this.known_gc = known_gc;
626+ }
627+
628+ /**
629+ * 既知組成を追加します.
630+ * @param known_cp 既知組成
631+ */
632+ public void setComposition(Composition known_cp)
633+ {
634+ this.known_cp = known_cp;
635+ }
636+
637+ /**
638+ * 糖鎖組成の予測に用いるm/zを登録します.
639+ * @param mass_a 組成を予測したいm/z
640+ */
641+ public void setMass(double mass_a)
642+ {
643+ this.mass_a = mass_a;
644+ }
645+
646+ /**
647+ * 糖鎖組成の予測に用いるm/zを登録します.(複数のm/zから組成まを予測する場合)
648+ * @param masses_a 組成を予測したいm/zの配列
649+ */
650+ public void setMass(double[] masses_a)
651+ {
652+ this.masses_a = masses_a;
653+ }
654+
655+ /**
656+ * 糖鎖組成の予測に用いる許容誤差を登録します.
657+ * @param tolerance_ms 許容誤差
658+ */
659+ public void setMsTolerance(double tolerance_ms)
660+ {
661+ this.tolerance_ms = tolerance_ms;
662+ }
663+
664+ /**
665+ * PSDスペクトルの実測値と理論値の許容誤差を登録します.
666+ * @param tolerance_psd 実測値と理論値の許容誤差
667+ */
668+ public void setPsdTolerance(double tolerance_psd) throws Exception
669+ {
670+ this.tolerance_psd = tolerance_psd; // クラスメンバとする.
671+ }
672+
673+ /**
674+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
675+ * @param lcb 長鎖塩基組成
676+ */
677+ public void setLongChainBase(List<String> lcb) throws Exception
678+ {
679+ for (String str : lcb) // 指定された長鎖塩基組成を登録
680+ if (str.matches("^[dt][0-9]+:[0-9]$")) // 通常の形式の場合
681+ this.lcb.add(str);
682+ else if (str.matches("^[dt][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 個数に幅があった場合
683+ {
684+ Pattern pt = Pattern.compile("^([dt])([0-9]+)(-([0-9]+))*:([0-9])(-([0-9]))*$");
685+ Matcher mt = pt.matcher(str); //( 1 )( 2 )(3( 4 )) ( 5 )(6( 7 ))でグループ化される.
686+
687+ if (mt.matches())
688+ {
689+ String temp = mt.group(1); // "([dt])"を取得
690+ int corbons_min = Integer.parseInt(mt.group(2)); // 最小炭素数(またはデフォルトの炭素数)
691+ int corbons_max = corbons_min; // 何も指定されない場合は,デフォルトの炭素数
692+ if (mt.group(4) != null)
693+ corbons_max = Integer.parseInt(mt.group(4)); // 最大炭素数を取得
694+ int bonds_min = Integer.parseInt(mt.group(5)); // 最小二重結合数(またはデフォルトの二重結合数)
695+ int bonds_max = bonds_min; // 何も指定されない場合は,デフォルトの二重結合数
696+ if (mt.group(7) != null)
697+ bonds_max = Integer.parseInt(mt.group(7)); // 最大二重結合数を取得
698+
699+ for (int corbons = corbons_min; corbons <= corbons_max; corbons++)
700+ for (int bonds = bonds_min; bonds <= bonds_max; bonds++)
701+ {
702+ StringBuilder sb = new StringBuilder(temp);
703+ sb.append(corbons);
704+ sb.append(":");
705+ sb.append(bonds);
706+ this.lcb.add(sb.toString()); // 1つずつ追加
707+ }
708+ }
709+ }
710+ else
711+ throw new Exception("Unknown lcb: " + str);
712+
713+ if (fa.size() > 0) // 脂肪酸が登録されている場合,
714+ setCeramide(); // 全セラミド組成を計算し,格納する.
715+ }
716+
717+ /**
718+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
719+ * @param fa 脂肪酸組成
720+ */
721+ public void setFattyAcid(List<String> fa) throws Exception
722+ {
723+ for (String str : fa) // 指定された脂肪酸組成を登録
724+ if (str.matches("^[ch][0-9]+:[0-9]$")) // 通常の形式の場合
725+ this.fa.add(str);
726+ else if (str.matches("^[ch][0-9]+(-[0-9]+)?:[0-9](-[0-9])?$")) // 個数に幅があった場合
727+ {
728+ Pattern pt = Pattern.compile("^([ch])([0-9]+)(-([0-9]+))*:([0-9])(-([0-9]))*$");
729+ Matcher mt = pt.matcher(str); // ( 1 )( 2 )(3( 4 )) ( 5 )(6( 7 ))でグループ化される.
730+
731+ if (mt.matches())
732+ {
733+ String temp = mt.group(1); // "([ch])"を取得
734+ int corbons_min = Integer.parseInt(mt.group(2)); // 最小炭素数(またはデフォルトの炭素数)
735+ int corbons_max = corbons_min; // 何も指定されない場合は,デフォルトの炭素数
736+ if (mt.group(4) != null)
737+ corbons_max = Integer.parseInt(mt.group(4)); // 最大炭素数を取得
738+ int bonds_min = Integer.parseInt(mt.group(5)); // 最小二重結合数(またはデフォルトの二重結合数)
739+ int bonds_max = bonds_min; // 何も指定されない場合は,デフォルトの二重結合数
740+ if (mt.group(7) != null)
741+ bonds_max = Integer.parseInt(mt.group(7)); // 最大二重結合数を取得
742+
743+ for (int corbons = corbons_min; corbons <= corbons_max; corbons++)
744+ for (int bonds = bonds_min; bonds <= bonds_max; bonds++)
745+ {
746+ StringBuilder sb = new StringBuilder(temp);
747+ sb.append(corbons);
748+ sb.append(":");
749+ sb.append(bonds);
750+ this.fa.add(sb.toString()); // 1つずつ追加
751+ }
752+ }
753+ }
754+ else
755+ throw new Exception("Unknown fa: " + str);
756+
757+ if (lcb.size() > 0) // 長鎖塩基が登録されている場合,
758+ setCeramide(); // 全セラミド組成を計算し,格納する.
759+ }
760+
761+ /**
762+ * 糖鎖組成の予測に用いる長鎖塩基組成を登録します.
763+ * @param min 炭素数の最小値
764+ * @param max 炭素数の最大値
765+ */
766+ public void setLongChainBase(int min, int max) throws Exception
767+ {
768+ boolean flag = true;
769+
770+ for (int i = 0, num = 0; flag; i++)
771+ {
772+ StringBuilder line = new StringBuilder(8); // lineに文字列を追加していく。
773+ num = i; // iの値を格納
774+
775+ // ノーマル型長鎖塩基かフィト型長鎖塩基か {0|1}
776+ int lcbDoubleBonds = 0;
777+ switch (num % 2) {
778+ case 0 : line.append("d");
779+ lcbDoubleBonds++;
780+ break;
781+ case 1 : line.append("t");
782+ break;
783+ }
784+ num /= 2;
785+
786+ // セラミドの炭素数 [max-min]
787+ line.append(min + num % (max - min + 1));
788+ num /= max - min + 1;
789+
790+ line.append(":");
791+
792+ // 長鎖塩基、脂肪酸の二重結合 [0-1],[0-1]
793+ line.append(lcbDoubleBonds);
794+ num /= 2;
795+
796+ if (num == 0)
797+ lcb.add(line.toString()); // セラミド組成をHashSetに追加
798+ else
799+ flag = false; // for文を抜ける.
800+ }
801+
802+ if (fa.size() > 0) // 脂肪酸が登録されている場合,
803+ setCeramide(); // 全セラミド組成を計算し,格納する.
804+ }
805+
806+ /**
807+ * 糖鎖組成の予測に用いる脂肪酸組成を登録します.
808+ * @param min 炭素数の最小値
809+ * @param max 炭素数の最大値
810+ */
811+ public void setFattyAcid(int min, int max, int bond) throws Exception
812+ {
813+ boolean flag = true;
814+
815+ for (int i = 0, num = 0; flag; i++)
816+ {
817+ StringBuilder line = new StringBuilder(8); // lineに文字列を追加していく。
818+ num = i; // iの値を格納
819+
820+ // ノーマル脂肪酸かヒドロキシ脂肪酸か {0|1}
821+ switch (num % 2) {
822+ case 0 : line.append("c");
823+ break;
824+ case 1 : line.append("h");
825+ break;
826+ }
827+ num /= 2;
828+
829+ // セラミドの炭素数 [max-min]
830+ line.append(min + num % (max - min + 1));
831+ num /= max - min + 1;
832+
833+ line.append(":");
834+
835+ // 長鎖塩基、脂肪酸の二重結合 [0-1],[0-1]
836+ line.append(num % (bond + 1));
837+ num /= bond + 1;
838+
839+ if (num == 0)
840+ fa.add(line.toString()); // セラミド組成をHashSetに追加
841+ else
842+ flag = false; // for文を抜ける.
843+ }
844+
845+ if (lcb.size() > 0) // 長鎖塩基が登録されている場合,
846+ setCeramide(); // 全セラミド組成を計算し,格納する.
847+ }
848+
849