jpayne@68
|
1 package tax;
|
jpayne@68
|
2
|
jpayne@68
|
3 import java.io.Serializable;
|
jpayne@68
|
4 import java.util.Comparator;
|
jpayne@68
|
5
|
jpayne@68
|
6 import shared.Tools;
|
jpayne@68
|
7
|
jpayne@68
|
8 /**
|
jpayne@68
|
9 * Represents a taxonomic identifier, such as a specific genus.
|
jpayne@68
|
10 * Includes the name, NCBI numeric id, parent id, and taxonomic level.
|
jpayne@68
|
11 * @author Brian Bushnell
|
jpayne@68
|
12 * @date Mar 6, 2015
|
jpayne@68
|
13 *
|
jpayne@68
|
14 */
|
jpayne@68
|
15 public class TaxNode implements Serializable{
|
jpayne@68
|
16
|
jpayne@68
|
17 /**
|
jpayne@68
|
18 *
|
jpayne@68
|
19 */
|
jpayne@68
|
20 private static final long serialVersionUID = -4618526038942239246L;
|
jpayne@68
|
21
|
jpayne@68
|
22 /*--------------------------------------------------------------*/
|
jpayne@68
|
23 /*---------------- Initialization ----------------*/
|
jpayne@68
|
24 /*--------------------------------------------------------------*/
|
jpayne@68
|
25
|
jpayne@68
|
26 public TaxNode(int id_, String name_){
|
jpayne@68
|
27 this(id_, -1, -1, -1, name_);
|
jpayne@68
|
28 }
|
jpayne@68
|
29
|
jpayne@68
|
30 public TaxNode(int id_, int parent_, int level_, int levelExtended_, String name_){
|
jpayne@68
|
31 id=id_;
|
jpayne@68
|
32 pid=parent_;
|
jpayne@68
|
33 level=level_;
|
jpayne@68
|
34 levelExtended=levelExtended_;
|
jpayne@68
|
35 setOriginalLevel(levelExtended);
|
jpayne@68
|
36 name=name_;
|
jpayne@68
|
37 }
|
jpayne@68
|
38
|
jpayne@68
|
39 /*--------------------------------------------------------------*/
|
jpayne@68
|
40 /*---------------- Methods ----------------*/
|
jpayne@68
|
41 /*--------------------------------------------------------------*/
|
jpayne@68
|
42
|
jpayne@68
|
43 /**
|
jpayne@68
|
44 * @param split
|
jpayne@68
|
45 * @param idx
|
jpayne@68
|
46 * @return True if the node's name matches the
|
jpayne@68
|
47 */
|
jpayne@68
|
48 public boolean matchesName(String[] split, int idx, TaxTree tree) {
|
jpayne@68
|
49 if(idx<0){return true;}
|
jpayne@68
|
50 if(!split[idx].equalsIgnoreCase(name)){return false;}
|
jpayne@68
|
51 return tree.getNode(pid).matchesName(split, idx-1, tree);
|
jpayne@68
|
52 }
|
jpayne@68
|
53
|
jpayne@68
|
54 @Override
|
jpayne@68
|
55 public String toString(){
|
jpayne@68
|
56 return "("+id+","+pid+","+countRaw+","+countSum+",'"+levelStringExtended(false)+"',"+(canonical() ? "T" : "F")+",'"+name+"')";
|
jpayne@68
|
57 }
|
jpayne@68
|
58
|
jpayne@68
|
59 public boolean equals(TaxNode b){
|
jpayne@68
|
60 if(id!=b.id || pid!=b.pid || levelExtended!=b.levelExtended || flag!=b.flag){return false;}
|
jpayne@68
|
61 if(name==b.name){return true;}
|
jpayne@68
|
62 if((name==null) != (b.name==null)){return false;}
|
jpayne@68
|
63 return name.equals(b.name);
|
jpayne@68
|
64 }
|
jpayne@68
|
65
|
jpayne@68
|
66 public long incrementRaw(long amt){
|
jpayne@68
|
67 if(amt==0){return countRaw;}
|
jpayne@68
|
68 if(verbose){System.err.println("incrementRaw("+amt+") node: "+this);}
|
jpayne@68
|
69 countRaw+=amt;
|
jpayne@68
|
70 assert(countRaw>=0) : "Overflow! "+countRaw+", "+amt;
|
jpayne@68
|
71 return countRaw;
|
jpayne@68
|
72 }
|
jpayne@68
|
73
|
jpayne@68
|
74 public long incrementSum(long amt){
|
jpayne@68
|
75 if(amt==0){return countSum;}
|
jpayne@68
|
76 if(verbose){System.err.println("incrementSum("+amt+") node: "+this);}
|
jpayne@68
|
77 countSum+=amt;
|
jpayne@68
|
78 assert(countSum>=0 || amt<0) : "Overflow! "+countSum+", "+amt;
|
jpayne@68
|
79 return countSum;
|
jpayne@68
|
80 }
|
jpayne@68
|
81
|
jpayne@68
|
82 public boolean isSimple(){
|
jpayne@68
|
83 return TaxTree.isSimple(levelExtended);
|
jpayne@68
|
84 }
|
jpayne@68
|
85
|
jpayne@68
|
86 public boolean isSimple2(){
|
jpayne@68
|
87 return TaxTree.isSimple2(levelExtended);
|
jpayne@68
|
88 }
|
jpayne@68
|
89
|
jpayne@68
|
90 // public String levelString(){return level<0 ? "unknown" : TaxTree.levelToString(level);}
|
jpayne@68
|
91
|
jpayne@68
|
92 public String levelStringExtended(boolean original){
|
jpayne@68
|
93 int x=(original ? originalLevel() : levelExtended);
|
jpayne@68
|
94 return x<0 ? "unknown" : TaxTree.levelToStringExtended(x);
|
jpayne@68
|
95 }
|
jpayne@68
|
96
|
jpayne@68
|
97 public String levelToStringShort() {return level<0 ? "x" : TaxTree.levelToStringShort(level);}
|
jpayne@68
|
98
|
jpayne@68
|
99
|
jpayne@68
|
100
|
jpayne@68
|
101 public boolean isUnclassified(){
|
jpayne@68
|
102 return name.startsWith("unclassified");
|
jpayne@68
|
103 }
|
jpayne@68
|
104
|
jpayne@68
|
105 public boolean isEnvironmentalSample(){
|
jpayne@68
|
106 return name.startsWith("environmental");
|
jpayne@68
|
107 }
|
jpayne@68
|
108
|
jpayne@68
|
109 /*--------------------------------------------------------------*/
|
jpayne@68
|
110 /*---------------- Nested Classes ----------------*/
|
jpayne@68
|
111 /*--------------------------------------------------------------*/
|
jpayne@68
|
112
|
jpayne@68
|
113 public static class CountComparator implements Comparator<TaxNode>{
|
jpayne@68
|
114
|
jpayne@68
|
115 @Override
|
jpayne@68
|
116 public int compare(TaxNode a, TaxNode b) {
|
jpayne@68
|
117 long x=b.countSum-a.countSum;
|
jpayne@68
|
118 // System.err.println("x="+x+" -> "+Tools.longToInt(x));
|
jpayne@68
|
119 if(x!=0){return Tools.longToInt(x);}
|
jpayne@68
|
120 return a.levelExtended==b.levelExtended ? a.id-b.id : a.levelExtended-b.levelExtended;
|
jpayne@68
|
121 }
|
jpayne@68
|
122
|
jpayne@68
|
123 }
|
jpayne@68
|
124
|
jpayne@68
|
125 /*--------------------------------------------------------------*/
|
jpayne@68
|
126 /*---------------- Getters ----------------*/
|
jpayne@68
|
127 /*--------------------------------------------------------------*/
|
jpayne@68
|
128
|
jpayne@68
|
129 @Override
|
jpayne@68
|
130 public final int hashCode(){return id;}
|
jpayne@68
|
131
|
jpayne@68
|
132 /*--------------------------------------------------------------*/
|
jpayne@68
|
133
|
jpayne@68
|
134 public boolean canonical(){
|
jpayne@68
|
135 return (flag&CANON_MASK)==CANON_MASK;
|
jpayne@68
|
136 }
|
jpayne@68
|
137
|
jpayne@68
|
138 public boolean levelChanged(){
|
jpayne@68
|
139 return originalLevel()!=levelExtended;
|
jpayne@68
|
140 }
|
jpayne@68
|
141
|
jpayne@68
|
142 public int originalLevel(){
|
jpayne@68
|
143 int x=(int)(flag&ORIGINAL_LEVEL_MASK);
|
jpayne@68
|
144 return x==ORIGINAL_LEVEL_MASK ? -1 : x;
|
jpayne@68
|
145 }
|
jpayne@68
|
146
|
jpayne@68
|
147 public boolean cellularOrganisms(){
|
jpayne@68
|
148 return id==TaxTree.CELLULAR_ORGANISMS_ID;
|
jpayne@68
|
149 }
|
jpayne@68
|
150
|
jpayne@68
|
151 // public int numChildren(){
|
jpayne@68
|
152 // return numChildren;
|
jpayne@68
|
153 // }
|
jpayne@68
|
154 //
|
jpayne@68
|
155 // public int minParentLevelExtended(){
|
jpayne@68
|
156 // return minParentLevelExtended;
|
jpayne@68
|
157 // }
|
jpayne@68
|
158 //
|
jpayne@68
|
159 // public int maxChildLevelExtended(){
|
jpayne@68
|
160 // return maxChildLevelExtended;
|
jpayne@68
|
161 // }
|
jpayne@68
|
162
|
jpayne@68
|
163 int minAncestorLevelIncludingSelf(){
|
jpayne@68
|
164 return levelExtended<1 ? minParentLevelExtended : levelExtended;
|
jpayne@68
|
165 }
|
jpayne@68
|
166
|
jpayne@68
|
167 int maxDescendantLevelIncludingSelf(){
|
jpayne@68
|
168 return levelExtended<1 ? maxChildLevelExtended : levelExtended;
|
jpayne@68
|
169 }
|
jpayne@68
|
170
|
jpayne@68
|
171 public String simpleName(){
|
jpayne@68
|
172 if(name==null){return null;}
|
jpayne@68
|
173 StringBuilder sb=new StringBuilder();
|
jpayne@68
|
174 char last='?';
|
jpayne@68
|
175 for(int i=0; i<name.length(); i++){
|
jpayne@68
|
176 char c=name.charAt(i);
|
jpayne@68
|
177 if((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='1' && c<='0')){
|
jpayne@68
|
178 sb.append(c);
|
jpayne@68
|
179 last=c;
|
jpayne@68
|
180 }else{
|
jpayne@68
|
181 if(sb.length()>0 && last!=' '){sb.append(' ');}
|
jpayne@68
|
182 last=' ';
|
jpayne@68
|
183 }
|
jpayne@68
|
184 }
|
jpayne@68
|
185 String s=sb.toString().trim();
|
jpayne@68
|
186 return s.replace(' ', '_');
|
jpayne@68
|
187 }
|
jpayne@68
|
188
|
jpayne@68
|
189 public boolean isRanked() {return levelExtended!=TaxTree.NO_RANK_E;}
|
jpayne@68
|
190
|
jpayne@68
|
191 /*--------------------------------------------------------------*/
|
jpayne@68
|
192 /*---------------- Setters ----------------*/
|
jpayne@68
|
193 /*--------------------------------------------------------------*/
|
jpayne@68
|
194
|
jpayne@68
|
195 public void setCanonical(boolean b){
|
jpayne@68
|
196 if(b){flag=flag|CANON_MASK;}
|
jpayne@68
|
197 else{flag=flag&~CANON_MASK;}
|
jpayne@68
|
198 }
|
jpayne@68
|
199
|
jpayne@68
|
200 public void setOriginalLevel(int x){
|
jpayne@68
|
201 flag=(flag&~ORIGINAL_LEVEL_MASK)|(x&ORIGINAL_LEVEL_MASK);
|
jpayne@68
|
202 }
|
jpayne@68
|
203
|
jpayne@68
|
204 /** Return true if changed */
|
jpayne@68
|
205 boolean discussWithParent(TaxNode parent){
|
jpayne@68
|
206 final int oldChildLevel=parent.maxChildLevelExtended;
|
jpayne@68
|
207 final int oldParentLevel=minParentLevelExtended;
|
jpayne@68
|
208 parent.maxChildLevelExtended=Tools.max(parent.maxChildLevelExtended, maxDescendantLevelIncludingSelf());
|
jpayne@68
|
209 minParentLevelExtended=Tools.min(parent.minAncestorLevelIncludingSelf(), minParentLevelExtended);
|
jpayne@68
|
210 return oldChildLevel!=parent.maxChildLevelExtended || oldParentLevel!=minParentLevelExtended;
|
jpayne@68
|
211 }
|
jpayne@68
|
212
|
jpayne@68
|
213 /*--------------------------------------------------------------*/
|
jpayne@68
|
214 /*---------------- Fields ----------------*/
|
jpayne@68
|
215 /*--------------------------------------------------------------*/
|
jpayne@68
|
216
|
jpayne@68
|
217 public final int id;
|
jpayne@68
|
218 public final String name;
|
jpayne@68
|
219 public int pid;
|
jpayne@68
|
220 public int level;
|
jpayne@68
|
221 public int levelExtended;
|
jpayne@68
|
222
|
jpayne@68
|
223 public int numChildren=0;
|
jpayne@68
|
224 public int minParentLevelExtended=TaxTree.LIFE_E;
|
jpayne@68
|
225 public int maxChildLevelExtended=TaxTree.NO_RANK_E;
|
jpayne@68
|
226
|
jpayne@68
|
227 private long flag=0;
|
jpayne@68
|
228
|
jpayne@68
|
229 public long countRaw=0;
|
jpayne@68
|
230 public long countSum=0;
|
jpayne@68
|
231
|
jpayne@68
|
232 /*--------------------------------------------------------------*/
|
jpayne@68
|
233 /*---------------- Constants ----------------*/
|
jpayne@68
|
234 /*--------------------------------------------------------------*/
|
jpayne@68
|
235
|
jpayne@68
|
236 private static final long ORIGINAL_LEVEL_MASK=63; //bits 0-5
|
jpayne@68
|
237 private static final long CANON_MASK=64; //bit 6
|
jpayne@68
|
238
|
jpayne@68
|
239 /*--------------------------------------------------------------*/
|
jpayne@68
|
240 /*---------------- Statics ----------------*/
|
jpayne@68
|
241 /*--------------------------------------------------------------*/
|
jpayne@68
|
242
|
jpayne@68
|
243 public static final boolean verbose=false;
|
jpayne@68
|
244 public static final CountComparator countComparator=new CountComparator();
|
jpayne@68
|
245
|
jpayne@68
|
246
|
jpayne@68
|
247 }
|