Mercurial > repos > rliterman > csp2
diff CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/sketch/Comparison.java @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/opt/bbmap-39.01-1/current/sketch/Comparison.java Tue Mar 18 16:23:26 2025 -0400 @@ -0,0 +1,803 @@ +package sketch; + +import java.util.Comparator; +import java.util.Locale; + +import aligner.Aligner; +import prok.GeneCaller; +import shared.Tools; +import tax.TaxNode; + +public final class Comparison extends SketchObject implements Comparable<Comparison> { + + /*--------------------------------------------------------------*/ + /*---------------- Constructors ----------------*/ + /*--------------------------------------------------------------*/ + +// public Comparison(CompareBuffer buffer){ +// this(buffer, null, null); +// } + +// public Comparison(Sketch a_, Sketch b_){ +// this(null, a_, b_); +// } + + public Comparison(CompareBuffer buffer, Sketch a_, Sketch b_){ + + a=a_; + b=b_; + + if(buffer!=null){setFrom(buffer);} + + if(b!=null){ + taxName=b.taxName(); + taxID=b.taxID; + } + +// System.err.println(this); +// System.err.println(b.present); + } + + /*--------------------------------------------------------------*/ + /*---------------- Mutators ----------------*/ + /*--------------------------------------------------------------*/ + + public void setFrom(CompareBuffer buffer){ + hits=buffer.hits(); + multiHits=buffer.multiHits(); + unique2=buffer.unique2(); + unique3=buffer.unique3(); + noHits=buffer.noHits(); + + contamHits=buffer.contamHits(); + contam2Hits=buffer.contam2Hits(); + multiContamHits=buffer.multiContamHits(); + + refDivisor=buffer.refDivisor(); + queryDivisor=buffer.queryDivisor(); + + refSize=buffer.refSize(); + querySize=buffer.querySize(); + + depth=buffer.depth(); + depth2=buffer.depth2(); + float x=buffer.avgRefHits(); + if(x>0){avgRefHits=x;} +// volume=volume0(); + score=score0(); + + hits1=buffer.hits1(); + qSeen1=buffer.qSeen1(); + rSeen1=buffer.rSeen1(); + } + + public void recompare(CompareBuffer buffer, int[][] taxHits, int contamLevel){ + +// for(int[] row : taxHits){ +// if(row!=null){ +// System.err.println(Arrays.toString(row)); +// } +// }//Tested; correctly indicates most rows have octopus but some have other things. + + assert(a.merged()); +// int oldContam2=contam2Hits; + int x=a.countMatches(b, buffer, a.compareBitSet(), false, taxHits, contamLevel); + assert(x==hits); + setFrom(buffer); +// contam2Hits=oldContam2; + } + + /*--------------------------------------------------------------*/ + /*---------------- Methods ----------------*/ + /*--------------------------------------------------------------*/ + + @Override + public boolean equals(Object b){ + if(b==null || b.getClass()!=this.getClass()){return false;} + return scoreComparator.compare(this, (Comparison)b)==0; + } + +// //WKID +// public float wkid(){return idMinDivisor();} +// public float idMinDivisor(){ +// return hits/(float)minDivisor(); +// } + +// public float k1Fraction(){ +// return a.k1Fraction(); +// } + +// //KID +// public float kid(){return idMaxDivisor();} +// public float idMaxDivisor(){ +// return hits/(float)maxDivisor(); +// } + + public float idQueryDivisor(){ + return hits/(float)(Tools.max(1, refDivisor)); + } + + public float idRefDivisor(){ + return hits/(float)(Tools.max(1, refDivisor)); + } + + public float completeness(){ + float complt=Tools.min(1, (queryDivisor-contamHits)/(float)Tools.max(1, refDivisor)); + return complt; +// float c2=hits/(float)refDivisor; +// assert(queryDivisor-contamHits>=hits); +// assert(c1>=c2); +// System.err.println(hits+", "+contamHits+", "+refDivisor+", "+queryDivisor+", "+c1+", "+c2); +// return Tools.max(c1, c2); +// float kid=idMaxDivisor(), wkid=idMinDivisor(); +// return kid==0 ? 0 : kid/wkid; + } + + public float contamFraction(){ + return Tools.min(1, contamHits/(float)Tools.max(1, queryDivisor)); + } + + public float contam2Fraction(){ + return Tools.min(1, contam2Hits/(float)Tools.max(1, queryDivisor)); + } + + public float uContamFraction() { + int uContamHits=contamHits-multiContamHits; + return Tools.min(1, uContamHits/(float)Tools.max(1, queryDivisor)); + } + + + + /*--------------------------------------------------------------*/ + + final float wkid(){ + final int div=minDivisor(); + return hits/(float)div; + } + final float kid(){ + final int div=maxDivisor(); + return hits/(float)div; + } + final float aniOld(){ + float wkid=wkid(); +// final float ani=wkidToAni(wkid, k1Fraction()); + final float ani=wkidToAni(wkid); + return ani; + } + final float ani(){ + if(hits<1){return 0;} + final float ani; + if(k2>0 && useToValue2){ + float ani1=ani1(); + float ani2=ani2(); +// ani=0.5f*(ani1+ani2); + ani=0.5f*(Tools.max(0.9f*ani2, ani1)+Tools.max(0.8f*ani1, ani2)); +// return (ani1*qSeen1+ani2*qSeen2())/queryDivisor; + +// System.err.println("ani="+ani+"aniOld="+aniOld()+", ani1="+ani1()+", ani2="+ani2()+", anid="+(float)aniDual()+"\n" +//// +"gf="+(float)gf+", wkid1="+wkid1+", wkid2="+wkid2+"\n" +// + "k1f="+k1Fraction()+", hits="+hits+", hits1="+hits1+", hits2="+hits2()+", qSeen1()="+qSeen1()+", rSeen1()="+rSeen1()+"\n" +// + "qSeen2()="+qSeen2()+", rSeen2()="+rSeen2()+", minDivisor1()="+minDivisor1()+", minDivisor2()="+minDivisor2()+"\n"); + }else{ + ani=aniOld(); + } + return ani; + } + + final float wkid1(){ + final int div=minDivisor1(); + return hits1()/(float)div; + } + final float kid1(){ + final int div=maxDivisor1(); + return hits1()/(float)div; + } + final float ani1(){ + float wkid=wkid1(); + final float ani=wkidToAniExact(wkid, k); + return ani; + } + + final float wkid2(){ + final int div=minDivisor2(); + return hits2()/(float)div; + } + final float kid2(){ + final int div=maxDivisor2(); + return hits2()/(float)div; + } + final float ani2(){ + assert(k2>0); + float wkid=wkid2(); + final float ani=wkidToAniExact(wkid, k2); + return ani; + } + + final float aniDual(){ + assert(k2>0); + float wkid1=wkid1(); + float wkid2=wkid2(); + float ratio=(wkid1/wkid2); + float exp=1f/(k-k2);//TODO - make this initialized + double ani=Math.pow(ratio, exp); + double gf=wkid2/Math.pow(ani, k2); + +// System.err.println("ani="+ani()+"aniOld="+aniOld()+", ani1="+ani1()+", ani2="+ani2()+", anid="+(float)ani+"\n" +// +"gf="+(float)gf+", wkid1="+wkid1+", wkid2="+wkid2+"\n" +// + "k1f="+k1Fraction()+", hits="+hits+", hits1="+hits1+", hits2="+hits2()+", qSeen1()="+qSeen1()+", rSeen1()="+rSeen1()+"\n" +// + "qSeen2()="+qSeen2()+", rSeen2()="+rSeen2()+", minDivisor1()="+minDivisor1()+", minDivisor2()="+minDivisor2()+"\n"); + + return (float)ani; + } + + /*--------------------------------------------------------------*/ + + int hits1(){return hits1;} + int qSeen1(){return qSeen1;} + int rSeen1(){return rSeen1;} + int minDivisor1(){return Tools.max(1, Tools.min(qSeen1, rSeen1));} + int maxDivisor1(){return Tools.max(1, qSeen1, rSeen1);} + + int hits2(){return hits-hits1;} + int qSeen2(){return queryDivisor-qSeen1;} + int rSeen2(){return refDivisor-rSeen1;} + int minDivisor2(){return Tools.max(1, Tools.min(qSeen2(), rSeen2()));} + int maxDivisor2(){return Tools.max(1, qSeen2(), rSeen2());} + + /*--------------------------------------------------------------*/ + +// public float aniOld(){ +// if(hits<1){return 0;} +// +//// double wkid=aniFromWKID ? idMinDivisor() : idMaxDivisor(); +// double wkid=idMinDivisor(); +// return wkidToAni(wkid, k1Fraction()); +// +//// final float rID=hits/(float)(refDivisor); +//// final float qID=hits/(float)(queryDivisor-contamHits); +//// final float wkid2=Tools.max(qID, rID); +//// final float ani=wkidToAni(wkid2); +//// +////// System.err.println("rid: "+wkidToAni(rID)+", qid: "+wkidToAni(qID)+", qid2: "+wkidToAni(hits/(float)(queryDivisor))); +//// +//// return ani; +// } + + int minDivisor(){return Tools.max(1, Tools.min(refDivisor, queryDivisor));} + int maxDivisor(){return Tools.max(1, refDivisor, queryDivisor);} + + private float score0_old(){ + long est=useSizeEstimate ? genomeSizeEstimate() : genomeSizeKmers(); + float wkid=wkid(); + float kid=kid(); + float complt=completeness(); + float contam=contamFraction(); + float refHits=Tools.max(avgRefHits, 1f); + float refHitMult=1f+(0.6f/(float)Math.sqrt(refHits+1)); + return (float)((Math.log(hits+2)*.25f+0.5f)*(refHitMult*0.2*Math.log(hits+2+(1.2*uHits()+0.25*unique2()+0.1*unique3())) + *Math.sqrt(40*(20000+hits+uHits())*(wkid*kid*Math.pow(est*complt, 0.2)*(1-contam*0.1)))+0.1)); + } + + private float score0(){ + final long est=useSizeEstimate ? genomeSizeEstimate() : genomeSizeKmers(); + final float wkid=wkid(); + final float kid=kid(); + final float ani=ani(); + final float complt=completeness(); + final float contam=contamFraction(); + final float refHits=Tools.max(avgRefHits, 1f); + final float refHitMult=1f+(0.6f/(float)Math.sqrt(refHits+1)); + final float uhits=uHits(); + final float uhits2=unique2(); + final float uhits3=unique3(); + final float contamMult=(1-contam*0.95f); + final float estMult=(float)(Math.pow(est, 0.2)*Math.sqrt(complt)); + final float aniMult=(float)(ani*Math.sqrt(wkid*kid)); + + final float hitsSum=1+hits+uhits+0.5f*uhits2+0.25f*uhits3; + + final float score=(float)(Math.log(Tools.max(1.2f, hits-1))*hitsSum*refHitMult*contamMult*aniMult*estMult);//+(Math.log(hitsSum+1)*wkid*complt)); + return (float)(8*Math.sqrt(score)); + } + + private long range(){//TODO Make sure these are calculated correctly; it seems like one divisor might be 1 higher than necessary. + long maxA=a.keys[Tools.max(0, queryDivisor-1)]; + long maxB=b.keys[Tools.max(0, refDivisor-1)]; +// assert(false) : Tools.max(0, queryDivisor-1)+", "+Tools.max(0, refDivisor-1)+ +// ", "+a.array[Tools.max(0, queryDivisor-1)]+", "+b.array[Tools.max(0, refDivisor-1)]+", "+Tools.max(maxA, maxB);//+"\n\n"+Arrays.toString(a.array)+"\n\n"+Arrays.toString(b.array); + return Tools.min(maxA, maxB); + } + + private static double eValue(int hits, int minDiv, int maxDiv, long range){ + if(hits>=range || maxDiv>=range){return 1.0;} + double probHit=maxDiv/(double)range;//Saturation of range +// double probNoHit=1-probHit; + double eValue=Math.pow(probHit, hits); //This is a simplification, assuming hits are very improbable. + //Note that this does not take into account minDiv, the number of attempts... but it should. +// System.err.println("hits="+hits+", minDiv="+minDiv+", maxDiv="+maxDiv+", range="+range+", eValue="+eValue); + return eValue; + } + + public double eValue(){ + double eValue=eValue1()*eValue2(); +// System.err.println("eValue="+eValue); + return eValue; + } + + public double eValue1(){ + long range0=range(); + int missingBits=64-(aminoOrTranslate() ? 5 : 2)*k; + double quantizer=1.0/(aminoOrTranslate() ? Math.pow(2, missingBits*aaBitValue) : 1L<<missingBits); + int hits=hits1; + int minDiv=Tools.min(qSeen1, rSeen1); + int maxDiv=Tools.max(qSeen1, rSeen1); + long range=Tools.max((long)Math.ceil(range0*quantizer), maxDiv); + return eValue(hits, minDiv, maxDiv, range); + } + + public double eValue2(){ + if(k2<1){return 1.0;} + + long range0=range(); + int missingBits=64-(aminoOrTranslate() ? 5 : 2)*k2; + double quantizer=1.0/(aminoOrTranslate() ? Math.pow(2, missingBits*aaBitValue) : 1L<<missingBits); + int hits=hits2(); + int minDiv=Tools.min(qSeen2(), rSeen2()); + int maxDiv=Tools.max(qSeen2(), rSeen2()); + long range=Tools.max((long)Math.ceil(range0*quantizer), maxDiv); +// assert(false) : missingBits+", "+quantizer+", "+range0+", "+range+", "+eValue(hits, minDiv, maxDiv, range); + return eValue(hits, minDiv, maxDiv, range); + } + + public String scoreS(){ + float x=score; + return format3(x); + } + + public double depth(boolean observedToActual){ + return observedToActual ? Tools.observedToActualCoverage(depth) : depth; + } + + public double depth2(boolean observedToActual){ + return observedToActual ? Tools.observedToActualCoverage(depth2) : depth2; + } + + public String depthS(boolean observedToActual){ + float x=depth; + if(observedToActual){x=(float)Tools.observedToActualCoverage(x);} + return format3(x); + } + + public float avgRefHits(){ + return avgRefHits; + } + + public String avgRefHitsS(){ + return format2(avgRefHits); + } + + public String depth2S(boolean observedToActual){ + float x=depth2; + if(observedToActual){ + x=(float)(Tools.observedToActualCoverage(depth)*(depth2/depth)); + } + return format3(x); + } + + public String volumeS(){ + double x=volume()*0.001; + return format3(x); + } + + static String format3(double x){ + if(x>=999.95){ + return(""+(long)Math.round(x)); + }else if(x>=99.995){ + return String.format(Locale.ROOT, "%.1f", x); + }else if(x>=9.9995){ + return String.format(Locale.ROOT, "%.2f", x); + } + return String.format(Locale.ROOT, "%.3f", x); + } + + static String format2(double x){ + if(x>=999.95){ + return(""+(long)Math.round(x)); + }else if(x>=99.995){ + return String.format(Locale.ROOT, "%.1f", x); + }else if(x>=9.9995){ + return String.format(Locale.ROOT, "%.2f", x); + } + return String.format(Locale.ROOT, "%.2f", x); + } + + float volume(){ + return Tools.max(1f, depth)*hits; + } + + @Override + public String toString(){ + return "hits="+hits+", refDivisor="+refDivisor+", queryDivisor="+queryDivisor+", refSize="+refSize+", querySize="+querySize+ + ", contamHits="+contamHits+", contam2Hits="+contam2Hits+", multiContamHits="+multiContamHits+", depth="+depth+", depth2="+depth2+", volume="+volume()+ + ", hits="+hits+", multiHits="+multiHits+", unique2="+unique2+", unique3="+unique3+", noHits="+noHits+", taxID="+taxID+", taxName="+taxName; + } + + /*--------------------------------------------------------------*/ + /*---------------- Getters ----------------*/ + /*--------------------------------------------------------------*/ + +// public boolean passesFilter(TaxFilter white, TaxFilter black){ +// if(white==null && black==null){return true;} +// int id=taxID(); +// String s=name(); +// return passesFilter(white, id, s) && passesFilter(black, id, s); +// } +// +// private boolean passesFilter(TaxFilter filter, int id, String s){ +// if(filter==null){return true;} +// if(id>0 && !filter.passesFilter(id)){return false;} +// if(s!=null && !filter.passesFilterByNameOnly(s)){return false;} +// return true; +// } + + public String name(){return taxName!=null ? taxName : name0()!=null ? name0() : fname()!=null ? fname() : ""+taxID();} + public String taxName(){return taxName;} + String name0(){return b.name0();} + String fname(){return b.fname();} + +// public int taxID(){return b.taxID<minFakeID ? b.taxID : 0;} + public int taxID(){return (taxID<minFakeID && taxID>=0) ? taxID : -1;} + long imgID(){return (b.imgID>0 ? b.imgID : -1);} + + long genomeSizeBases(){return b.genomeSizeBases;} + long genomeSizeKmers(){return b.genomeSizeKmers;} + long genomeSequences(){return b.genomeSequences;} + long genomeSizeEstimate(){return b.genomeSizeEstimate();} + float gc(){return b.gc();} + boolean hasGC(){return b.baseCounts!=null;} + + public boolean hasSSU() { + return (a.r16S()!=null && b.r16S()!=null) || (a.r18S()!=null && b.r18S()!=null); + } + public boolean hasSSUIdentity() { + return ssuIdentity>=0; + } + public boolean needsAlignment() { + return hasSSU() && !hasSSUIdentity(); + } + public boolean hasQueryTaxID() { + return a.taxID>0 && a.taxID<minFakeID; + } + + + public int uHits() {return hits-multiHits;} + + /** Common ancestor TaxID, if both Sketches have a TaxID */ + public int commonAncestor() { + if(a.taxID<1 || b.taxID<1){return -1;} + assert(taxtree!=null); + int id=taxtree.commonAncestor(a.taxID, b.taxID); + return id; + } + + /** Common ancestor node tax level, if both Sketches have a TaxID */ + public String commonAncestorLevel() { + int id=commonAncestor(); + if(id<1){return ".";} + TaxNode tn=taxtree.getNode(id); + while(!tn.isRanked() && tn.pid!=tn.id){tn=taxtree.getNode(tn.pid);} + String s=tn.levelStringExtended(false); + return s; + } + + /** Common ancestor node tax level, if both Sketches have a TaxID */ + public int commonAncestorLevelInt() { + int id=commonAncestor(); + if(id<1){return 0;} + TaxNode tn=taxtree.getNode(id); + while(!tn.isRanked() && tn.pid!=tn.id){tn=taxtree.getNode(tn.pid);} + return tn.levelExtended; + } + + /*--------------------------------------------------------------*/ + /*---------------- Comparators ----------------*/ + /*--------------------------------------------------------------*/ + + + + static class ScoreComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + { + float pa=a.score, pb=b.score; + if(pa>pb){ + return 1; + }else if (pa<pb){ + return -1; + } + } + + int x=a.hits-b.hits; + if(x!=0){return x;} + x=b.minDivisor()-a.minDivisor(); + if(x!=0){return x;} + x=b.maxDivisor()-a.maxDivisor(); + if(x!=0){return x;} + x=b.refDivisor-a.refDivisor; + if(x!=0){return x;} + x=a.taxID()-b.taxID(); + if(x!=0){return x;} + if(a.name0()!=null && b.name0()!=null){ + return a.name0().compareTo(b.name0()); + } + if(a.taxName()!=null && b.taxName()!=null){ + return a.taxName().compareTo(b.taxName()); + } + return 0; + } + + @Override + public String toString(){return "sortByScore";} + + } + + static class DepthComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float da=Tools.max(0.1f, a.depth-0.5f), db=Tools.max(0.1f, b.depth-0.5f); + final float sa, sb; + if(sqrt){ + sa=da*(float)Math.sqrt(a.score); + sb=db*(float)Math.sqrt(b.score); + }else{ + sa=da*a.score; + sb=db*b.score; + } + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByDepth";} + + } + + static class Depth2Comparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float da=Tools.max(0.1f, a.depth2-0.8f), db=Tools.max(0.1f, b.depth2-0.8f); + final float sa, sb; + if(sqrt){ + sa=da*(float)Math.sqrt(a.score); + sb=db*(float)Math.sqrt(b.score); + }else{ + sa=da*a.score; + sb=db*b.score; + } + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByDepth2";} + + } + + static class VolumeComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float da=a.volume(), db=b.volume(); + final float sa, sb; + if(sqrt){ + sa=da*(float)Math.sqrt(a.score); + sb=db*(float)Math.sqrt(b.score); + }else{ + sa=da*a.score; + sb=db*b.score; + } + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByVolume";} + + } + + static class KIDComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float sa=a.kid(), sb=b.kid(); + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByKID";} + + } + + static class WKIDComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float sa=a.wkid(), sb=b.wkid(); + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByWKID";} + + } + + static class SSUComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { +// if((a.has16S() || a.has18S()) && !a.hasSSUIdentity()){ +// synchronized(a){a.ssuIdentity();} +// assert(a.hasSSUIdentity()); +// } +// if((b.has16S() || b.has18S()) && !b.hasSSUIdentity()){ +// synchronized(b){b.ssuIdentity();} +// assert(b.hasSSUIdentity()); +// } + + if(a.hasSSUIdentity() && b.hasSSUIdentity()){ + final float sa=a.ssuIdentity(), sb=b.ssuIdentity(); + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + }else if(a.hasSSUIdentity()){ + return 1; + }else if(b.hasSSUIdentity()){ + return -1; + }else{ + return scoreComparator.compare(a, b); + } + + } + + @Override + public String toString(){return "sortBySSU";} + + } + + static class HitsComparator implements Comparator<Comparison>{ + + @Override + public int compare(Comparison a, Comparison b) { + final float sa=a.hits(), sb=b.hits(); + return sa>sb ? 1 : sa<sb ? -1 : scoreComparator.compare(a, b); + } + + @Override + public String toString(){return "sortByHits";} + + } + + @Override + public int compareTo(Comparison b) { + assert(false) : "Please use comparators instead."; + return scoreComparator.compare(this, b); + } + + @Override + public int hashCode() { + assert(false) : "TODO"; + return super.hashCode(); + } + + public static final ScoreComparator scoreComparator=new ScoreComparator(); + public static final DepthComparator depthComparator=new DepthComparator(); + public static final Depth2Comparator depth2Comparator=new Depth2Comparator(); + public static final VolumeComparator volumeComparator=new VolumeComparator(); + public static final KIDComparator KIDComparator=new KIDComparator(); + public static final SSUComparator SSUComparator=new SSUComparator(); + public static final WKIDComparator WKIDComparator=new WKIDComparator(); + public static final HitsComparator HitsComparator=new HitsComparator(); + private static final boolean sqrt=false; + private static final double aaBitValue=0.86438561897747246957406388589788; //(log(20)/log(2))/5; + + /*--------------------------------------------------------------*/ + + int hits(){return hits;} + int multiHits(){return multiHits;} + int noHits(){return noHits;} + int unique2(){return unique2;} + int unique3(){return unique3;} + + float depth(){return depth;} + float depth2(){return depth2;} + float score(){return score;} + + int contamHits(){return contamHits;} + int contam2Hits(){return contam2Hits;} + int multiContamHits(){return multiContamHits;} + + int queryDivisor(){return queryDivisor;} + int refDivisor(){return refDivisor;} + + int querySize(){return querySize;} + int refSize(){return refSize;} + + int ssuType(){return has18S() ? 18 : has16S() ? 16 : 0;} + int ssuLen(){return has18S() ? b.r18SLen() : has16S() ? b.r16SLen() : 0;} + boolean has16S(){return a.r16S()!=null && b.r16S()!=null;} + boolean has18S(){return a.r18S()!=null && b.r18S()!=null;} + + float ssuIdentity(){ + if(ssuIdentity>0){return ssuIdentity;} + if(has18S()){ssuIdentity=calcIdentity(a.r18S(), b.r18S());} + else if(has16S()){ssuIdentity=calcIdentity(a.r16S(), b.r16S());} + return ssuIdentity; + } + + private static float calcIdentity(byte[] ssuA, byte[] ssuB){ + //assert(false); + if(ssuA.length>ssuB.length){ + byte[] c=ssuA; + ssuA=ssuB; + ssuB=c; + } + if(useSSA){ + Aligner ssa=(useSSA3 ? GeneCaller.getSSA3() : GeneCaller.getSSA()); + int[] max=ssa.fillUnlimited(ssuA, ssuB, 0, ssuB.length-1, 0); + if(max==null){return 0;} + + final int rows=max[0]; + final int maxCol=max[1]; + final int maxState=max[2]; + + //returns {score, bestRefStart, bestRefStop} + //padded: {score, bestRefStart, bestRefStop, padLeft, padRight}; + int[] score=ssa.score(ssuA, ssuB, 0, ssuB.length-1, rows, maxCol, maxState); + int rstart=score[1]; + int rstop=score[2]; + +// byte[] match=ssa.traceback(ssuA, ssuB, 0, ssuB.length-1, rows, maxCol, maxState); +// float id=Read.identity(match); + float id=ssa.tracebackIdentity(ssuA, ssuB, 0, ssuB.length-1, rows, maxCol, maxState, null); + return id; + }else{ + GlocalAligner ga=new GlocalAligner(); + return ga.alignForward(ssuA, ssuB); + } + } + + /*--------------------------------------------------------------*/ + /*---------------- Fields ----------------*/ + /*--------------------------------------------------------------*/ + + public Sketch a, b; + + String taxName; + int taxID; + + private int hits; + private int multiHits; + private int unique2; + private int unique3; + private int noHits; + + private float depth; + private float depth2; + private float avgRefHits; + private float score; + + private int contamHits; + private int contam2Hits; + private int multiContamHits; + + private int refDivisor; + private int queryDivisor; + + private int refSize; + private int querySize; + + private int hits1; + private int qSeen1; + private int rSeen1; + + private float ssuIdentity=-1; + +}