From f1c772ceea77fdccf7744e0caacb99717f0009c6 Mon Sep 17 00:00:00 2001 From: Karthik Gururaj Date: Thu, 16 Jan 2014 21:40:04 -0800 Subject: [PATCH] Same log message as before - forgot -a option 1. Moved computeLikelihoods from PairHMM to native implementation 2. Disabled debug - debug code still left (hopefully, not part of bytecode) 3. Added directory PairHMM_JNI in the root which holds the C++ library that contains the PairHMM AVX implementation. See PairHMM_JNI/JNI_README first --- PairHMM_JNI/.gitignore | 2 +- PairHMM_JNI/JNI_README | 34 ++- PairHMM_JNI/libJNILoglessPairHMM.so | Bin 66472 -> 77757 bytes ...e_sting_utils_pairhmm_JNILoglessPairHMM.cc | 22 +- .../PairHMMLikelihoodCalculationEngine.java | 7 +- .../utils/pairhmm/JNILoglessPairHMM.java | 276 +++++++++++------- .../sting/utils/pairhmm/PairHMM.java | 16 +- 7 files changed, 238 insertions(+), 119 deletions(-) diff --git a/PairHMM_JNI/.gitignore b/PairHMM_JNI/.gitignore index cb70b53a7..9722ad970 100644 --- a/PairHMM_JNI/.gitignore +++ b/PairHMM_JNI/.gitignore @@ -1,6 +1,6 @@ .svn *.o -*.so +#*.so tests .deps hmm_Mohammad diff --git a/PairHMM_JNI/JNI_README b/PairHMM_JNI/JNI_README index 2a02d41ce..9fc3aa8d1 100644 --- a/PairHMM_JNI/JNI_README +++ b/PairHMM_JNI/JNI_README @@ -1 +1,33 @@ -TEST +Implementation overview: +Created a new Java class called JNILoglessPairHMM which extends LoglessPairHMM and +overrides functions from both LoglessPairHMM and PairHMM. +1. Constructor: Call base class constructors. Then, load the JNI library located in this +directory and call a global init function in the library to determine fields ids for the +members of classes JNIReadDataHolder and JNIHaplotypeDataHolders +2. initialize(): Override and do nothing as all matrix manipulation is done in the native +library. +3. computeLikelihoods(): Copies array references for readBases/quals etc and +haplotypeBases to arrays of JNIReadDataHolder and JNIHaplotypeDataHolders classes. Invokes +the JNI function to perform the computation and updates the likelihoodMap. + +Note: Lots of debug code still left in the files, however, debug code is not executed +(hopefully, not even compiled into bytecode) because the debug flags are set to false. + +On the C++ side, the primary function called is +Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM_jniComputeLikelihoods. It +uses standard JNI calls to get and return data from/to the Java class JNILoglessPairHMM. +The last argument to the function is the maximum number of OpenMP threads to use while +computing PairHMM in C++. This option is set when the native function call is made from +JNILoglessPairHMM computeLikelihoods - currently it is set to 12 (no logical reason). + +Compiling: +Make sure you have icc (Intel C compiler) available. Currently, gcc does not seem to +support all AVX intrinsics. +Type 'make'. This should create a library called libJNILoglessPairHMM.so .Comment out +OMPCFLAGS if OpenMP is not desired. + +Running: +If libJNILoglessPairHMM.so is compiled using icc, make sure that the Intel Composer XE +libraries are in your LD_LIBRARY_PATH : +source /bin/compilervars.sh intel64 +See run.sh in this directory on how to invoke HaplotypeCaller with the native library diff --git a/PairHMM_JNI/libJNILoglessPairHMM.so b/PairHMM_JNI/libJNILoglessPairHMM.so index f7a3569bfa382d5e2f7267714e18d538eb9df1ee..435034f78de8b6b51001484dd15d775e3fdae892 100755 GIT binary patch literal 77757 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

`3 z)K5DKj`A=`h{N~9O(srRX;fO;ZsM6yzEVbuxZ3nh(d5nPLSH6}kD)^h>+ax95$M

N)P8c#tC~LTMP7I;S0QzfJ077eSi$iKzHrx< z6fHX0RZ;#FTy;>gCyj%bo^Cp?!I1*?7kLxqlMcsqE$z)$M@M=i>&ei_+>=w#0{;A& zqcN*tTf~v`89Y>5DZDT|aR$2=nqUpr?kQtIS*lSu-M-zxOjEBis!?^GxiaKVC0U_&&R6y8DAZh z%jrBKUJyXyi9PhlP7~)-Z5UDx$KkdvjNfcOtGc0HUQNQq2y98Ni{FgzX5-K<-P28j zy|EF8(R5v<(og4nmenbpN?R8Nv?h(BD@lv+8KbYx^GzLXY+5fm3C48r>~MI4Drrr3 zGDn;_w>pwdOq}*Y{(@DTwBO~?NDPPcb;@pA>&^9@gllfn!~v)>;oKx6v}HYm|G!Sv B5<36@ delta 28358 zcmbt-dz?*G8~;9+;TV^5j9~_YgG0k;%$UJ&TxK+CZ_a2!rQBaCN^%)e$-xZS9fx7j z2x$`Kl`>IplDsqSAq|z3(xlryu7g66^ZPz)uRZphdVjw^e#>Xiv!CzttoyUpde+*< z-XDK&-|&LHFg~U-UE(2ACsOXACGETT?PWS^P)Txgz=FRua5;qBQRW6myqkzr=-@=U zUQ4G&JS$j=CyRJ;nHwDOZX%MK6mHWc-zzP%-_oH-x|+&>u$n2B2mP-MSpGru$mHhD zS6mxz94_p*x;Cd7n z)vGS9Nx1TGb;8wElKdc&l+6E1(!W3-!!;0BFI>}bQ5b|P30FL>`*A&o>j_*>;u?Xg z9j>vsD0INppWjJRbI<{}p2al**WI`t$JGZHg@>f3l0^O25Latl&)_mbTQ=I#fR+4a z_xk{KG+;rSf#%@42iL>6rs6U}d)!RNbuX?*1W1iq6IU*-!MGm8Wy6(#%ZZD^Or1z0 z1r>xnWvS1~es921PV`)ooxmnp?Ec0=7F%6ast2A-p#iQ|xZ2=qgzFAm6spV$_c0vN z|I`upEd|X0O%wM-QpJ6WPWwrnaTA9tQ3!~5#r>Uvb`i9jphRk$?xS(PrmUh zqU9yg@@_r0^c=T@3SQ5NLZ>hyiSBH2{Wv96WIQS&<0xSXr8#<%xu^&QuSjinL~8T7 z1t#-iS;kRgw0c)0;m*~g8g*KMd4=j!zKTWHY1{ZOp_US%7E38M`;Tb0%q4mvxiroZ zEWqp2m{8iFWW0%lZDwMOP*{L$>SLB)_KBPG0+yZ@OO!tfz*y+|4dI<189=%;-JBxJpH%PZG9J zOBAhKq>u?c3J;*tlw)SD&Ko%{5hdhP4@8B!SeimPHjWnMEEFqP1&otI29+Ty8)@qU zX9|_9@%xbQUb&AeNt48CP>;Pw?8f!W_BT?(%dO|7SZrB<|v zYrT%3dOSSH+u{PB5B^Pmm%AN2u#-zNw5ACx|lO>EeN{n)4ndp1rXX@iuJgE|Rm%1CMC z!(%7pGFQB}DAd5xn>CAT%9g|*U)u0a_DEdAn31EWPJLub-pEHskDmb5iBCVdb#~(^ zmZJY8SX$b%JN2Dj^n3?PNQKu$ng{N9+@x_>8BGo;gN}KbL%(L2S6=->iB0L={ub= z9Q`Ez4j44`uGGG$%~UYm#ymA~`rxOOiFurbESou7B^RZ%w?uD!#Z${-oqE^SHErr! zSbBnQYf0P7R<^EPEZg3$5j)l{hW*mcRog0A;1%${tY-Vxb@h7-M{TTk`__I!XbHA) zJ<`Ms$N%YZqqscEgb`wa7q6#6+7zF-6mC$G#M*hkbIa)KCQ`k%)WNN zw8W&)(4;VN)|;4nY|<-La;wx*$SJ|kH$MS8i;~t0EU(>CEGSl~MCiN9+@!`mcA}HS zauQ$WCRX5nOkKhw$}DpeUKPRMSL~~f7Yjaqe|6j~_!SX&vEbtmMCcQb{G}BUf?~nP zi#ZL|;=wKWal74|uYtd4PUDZdAl)P=HAN7MFP9!L;l`en1mz~2HoQhSVZzPBwZeq^ zy@ocZW)k!;;gu%5mkGaa!ZS^{wAal!s#ul@cbM=#I!^V62WJx8r3?7qcoUv&!rdmk zuL(~y;dh(x6cc`r3D4N;cXO6XDw_nErU;4&mrZy-6P|0r`Q8+?+9c3S z5yqJCN)tZTgkLw|kD734pPO@({$nQGVZz5(wLcVGCc)#T2=ONT2@~!%;S)@Fq6vS} zgr}JBrv%RP&oBwZ-hqoVP52a3Lb3_ZGvT==e3}U#V#24J@KO8Rdi`qxq!U>qj59@; zVSu2MO!zYEv@#LR`$~oVUcq{RxobN+CImDq7&UYu?PJA)vI}wkZrBEU9 z{xW8&RdBmw=k5#`9B$W z?AN4_oAZ~6uS>iOyg%IL3<2boIgl> z4DqF$-$gvRlc5sMZzrC7n@}<5w-Dcu_`+MrKip;`0p!etW^;wL#M7Z{XcFgF5>HM| zXcXs{5>L)dD3|ju5>Gx%D3kMZiEm1L3g@3Co_v{*oAXnMCm$x{x`q71Z5}6poR^Tq z75+th3*syPBKgC_yNR#h{6OMc5?{{we#EyTzLfKQh$kN=RKof0#CwP@=6omO+Yn#q z=RkV`+7d9E^R0-#gZN3DZ$dmdEum4Ik0HJt@wuFjCZ2qkP$uWC#FNhwO5yyUOTl*_ z-p%>T#FOt5^1C>2h5&N)LlWmt6W@{e%A3>z-w;nuO{jwN$A~9qCREP(gT!|tzLfL3 zh)*NFg!9{pCm$zN%=s?xB0p!$#W^;Zm@m-0Z#QBxPlXDXq#rdVglT#DQ z<@}4pcPBoR^K*$O-zJp8`DckIpC;ty{1oDQ()t&2ao}+R$hiqgoc|Z`y@{{9!EJ!} zOyVmzKahBGZbIdp??*g2HK9_@_aUBqnNSJmyAz*Hd@<)c5#N{A-%ue3+7oa$Da_`4 zE8_1VeiG-K5KlfzXcXsTh$r79l*{>O;`g2C_*~*EIDd?I@;O4~oIgnXK;la|zl-=m#Fub>JMrXN zgo-)8g?Rt{1Qc>$BLU<~gl2PoE%6T$KM6c24>WhnfvD#fxg~jCX`VG)&S&mIBiui` z=K@TDlC1umHF(gpf64hh$3a)ht0M<{Iv2VnZ6G>W4mP_Ia7(`0!8SjEBEjLySi9cM z<(`O}6^`8lgr;h_+leVZ?~7`VTg%X_VV~@N)Y+myl%r=cVoLWTqr4_iKN-|ZR1f*Q z5ZJo7_gt%GD~suK)V~0B)Hm&zy3j)wm3CDg^NCO0GM)|5Q2>Yz5tQ;Ez7kaX>yL0a?R@?YUS`QTKLv}N66gzsi$3)i^-Q>s zmN7X{ccJPgPzel20r$y)`x3+KI+SH~x32HMD66OB;4)r-aA74DJ4D|rmz}oDfrWad z)r4qS&5m|>H}U+Yyc8Z1BwfBZA>R%I3jNo8T zqE8*`amc}JkK3ot^tj~UFpo!3_shWvo(_uo#o4CWfpib&kO7zaf-|8U9P3F$KBr+T z$ikIp>+rIl*F-@;*aU%=;a2T+80SM#3n9(dY6EvYOUEmWGNewnSNd$Lqm z;{=Z*OFiNXAnUZNcLfuYVSxJr!kYX6VNLIvLeF9TVAvvshlAyB%odK#ngGS)0G8)VkSnb!< zgYWU=wC5m}Q6$op)oYYHPbTRvd0WmmV}`su>xsGYwTrUtE4l2?I&xXKx2ztOlRlHZ zUr&vd$M4o#X|If8P!eaG%1PhIK_9x%_C1wZFVi>L7371S+xC`!BM&d~@95~x4tyE4rh*?7bG%=vqdO^OXYEiP<{NJgW z^hET;*Ih=1N=e}W6flyhmoSpAz#T zB?nyLCHe?2@SH#@(3l*dk!w=fpsNgsREfWx$~IjkiL3ZAmxzpV-M4j0bsa}!GLG9S zB~UR{hsqW%9D->oOWhZNSD%ln=BkTm2ET{WiBu@?NbYK>^J-O_)u^fCt1Iz}{Y}YH zU5VH1wvrzcBqim7R^POrZcoAOF?;2xztUt|_ABPj0zP*tf%{SE^qS$NR8!yhz2kU8 z>C-$-uw>v$U}l^n?bzLFx`jHLpe!{zg(t%0>S`$$@qEzt6VPAX;gA9Jop;qa|5XVk zG7?@W3ib&lL^UC+qiXw5AZjCLi){K+fJg+c)^iJ&`D`cpI(Npp`l^GO!xvb_ai6U` z+qttxTwis^(i7PB0QZ{&361)ytCwzYa)Al&QJ*5rz%C(MJ=oWKWXg)H@SgDAZ0|Zg z_c-SshbM39a%$oau_&Ri%Xs<2h1b!{CJpK-UBeF*s@LCCsK=`kp&I{9gAAuigW5vZ z@S&v+Ktxll26}HWefqrt&$WBivDe_tV08yLAlTzlPT(s+ZzQSYgW8@fnUQ_JORCn&-SiV)^QzZkd9f^vwJz&$P{X^&iX-7b3z zJX|ohC#~VIFyf%MkdpBu6XMf8k;}B+J7ILZ)p(-8!7dBtl%s#j^NvmLnihsDAloYQ zYV}ilxcjLy-3~ebR%Ko^-MZ*cyc{l*^Gn^B5~qAF2h($SYQek1MiHhqmdk#z`)t1` z`8Qp8b<#=|)t~LDRInspr`DhvQ(@$?3cF(4L$xC|^rRg>lL^FLLgST#50_zep&Qaa zK~%NM>cb9Nbg1RM`V8)z8xP;s)a&FLMUHgj?|^IREI5m0G(uOOPSAWQi0GWR5gJ(B zm*=}B&3y@LIo24;JlNA(;Fi)#_eZUn@0Oy`f|{i=9EQL87-YXdJ*^Zr!F9(hgO37* z6ez$gojl*~Mgj{tCHXT_ z3$&o@ai5)leEjBov?UiQ{iqle$VfmAcJ_j$<%EioqgGH`jHcpH38;>~pwHvT%^Ivd zf^v{kgme?DrF#ZhMzj(vCotIKxNZEENZqGiF-)D!AL#aXw4upxi6TK+J*0S# zRD=+-SLX|)U-3Q8X^Of(QtD309F-L4?}pNzM{iAxMW`G%x-*?(NsdCgnS*i zKzVn`Nr!GXs+?aICtnLG>X&|{>@TZa_D64D63Q$p^XM7$Wq2ReC&&BylwYe7oOd!0 zW9fUXFBE9Lr;K$kBTXQ@NZhGu38c!IL~}~e_5ID4^#8LnDXVsP(LIyrVnls--ZY~0 znNw?c4h0Zin>Hk*GnBXX9CbvXhex}NXhRDPyknFkZSRF?M-J949|1kaBlYxG zKmhqGB=4!q-z9k-$;GTwZH|2wQ-{0_WUVj0jk= zDq5fn*S=9~UVE2%Vmda;$u*wS&~?Rox9I{7dP{QsQiGpWZZg}&rY-r^I!Pqk8f&d9nS#yJYY#lEjlluhBj%VV_MYH3}jJ?fOzy_Cu6x zJ1Pg|u;M*1wYyyQ1L~$17C0RY=+nFsh^>VTQ*#2oTFB6s>PJ^rm~_jH?%*q30AeyA zeYNv>e{~johH5KGH`6}ZPIacP2;Q!?9L(!QZ2;T2X0CKGT2fJW<=D#eV)_SS-HIA3 z-5c<^9XWp0C!x}RqSE~XgWYf^21_my#pggml~(w=%_}X|;9#t&(q(e+SuEqXsM5MO zN}0*F{Z#3Ne3kAOu-}0J-EBZ%>>a4|*lwsZZTcxWKk4pL0@$r##AD*9rCs`&MjklP zfQlL?+b|Mn6e{Y2E@L_lUBi|ZBRoXI_2y4B4EUrmXO>&i7K%AxHVPv~hc@ola5z*( z!&g@v^1NH>sEvW9&>r-B4}UY!QXeLq4Hh&nip`GyWm+m6Rtn0z*a;Pk@^hMbEv=tW;3YBcm=%s%x3 z(par)&Kt^(4sGgBF^itoMT0>UHPfM>nM{fOMMEMGbt})5*!_BpR(cFqM2t;(jKk&_ z9rYNMcs_?b{PESIT0 zlif1}bM6k50L}6oPWZIuKTuQl{OBPrP9*U*7zoLSkvv?%li+hr|LKoN4 z#b*F*-=d3~lekP5Z$UIS4F?`PT=rNIrH&+a|{;IX~uhyA$syAcPp zfj_Y9vEAeTgLB%w*PqsQB0C%t%`1NjXGkqiv*lwenzTR-w#UQ$mV+Np`r{V*?fvp6 zAny9z*2Rx(wOB9T$Fd(=5j`mvN&NX#n~eLm{_2S z+r&}UO`o$SPmQ%+khji$Dh6@C+`4Si9IJKnXDn`NvGx6I_TkjC){3KB-^lyGYQ31r zMn2u&`tV`4>FE*HKM%1wGd%tWWK1F4?>O@bRWECB*8N!zWIZ_Oew-A?<77@z|A61- zQ|owSHP7R~VT`jN4#igjS#W7^7`&WA)W1sEnI88Bhjnt|O1MLHI)QA>Tc-FeXd zCMW55PQY%(a&5~A46|Yu9%jSrk>$YI6gE`*lxyGmY(M*wP_3JYm&My>(Z6VNQY+=) z@JiZJ24_Z9%HHp%$IuP|XP2~aCGGclOJ}z5%ibH#`S2(B?%~==F0*~FcuzPNEumuN z@5ia>@aq)4HsXqSbrEfPo}6?;@m`-b0cT`5Wh*<|JBtqu#r7>$x1%@Yc_*j$!ICY9 z_va*?$_ZpARl>zcti&3cbRBDGB3uLi;G_zy(uoy0feA^PPo0pcVZT{{+2HRk$P%p!fH=fK96mO$V5xp3X`7DlacbE$^F#*427v(eGfT9NR9i zN3Z*H=9NzGtf+f^wzGNgFzVRgy`YEl|H3w0R(&?|W^6E--Eit*GAE{dJ|Ng(xZW(o z(JY@&Z>W_03{%)E=fnTPkdWbZas;FnVZTrw0>U|EfY(Lh1 z9C+sh?}F)Hx1oS!_3>cHS!tn36&;vAK`H5uFIZ3}NHk@%(je!_n zz@7%{kM{)zr@{IM$2)QY_c_km`99M2XO8*|T=d`b&`edW4}MxD_PX)Ihh~j57B96- z-cF7`f>Q}}qXXu$KkTwU>8Q_p+WEp3Ob&|oaE|)3&v{SCXAAkfp()PWQGDJr)1#G- z^#sCBUjW+xpSo90x`-*kInPVc(G9ej%m2Ajv7y<1n*KD7SJ24tYkOzulZx#(`RFY% zDW#p1=Uw$v=b!c2PV&xALT4xGt}Jza5_NtOI-j?m53PpIr&dE|!J+84jmLC+Umu1^=+9kwx<%##h11rw#iE}EPb?^&u!`jgbya@o&O zaxkGCS`XWVi&NYAY^Q-?8L5zMd-G!8Iwj)hA`xD$9S@TRcR*#ZM+zpS>W*=<-L#{w zN@8f?a2JH`lXELkmGQ#sGrGr6gdgEbfi;I zi+tU{y)M&pn!wWzIq3*aAZXLXAJ_cRTTVJEd(SvuIESY4VS5?u;o*;iv;)Xe#@3V4 zHm4!72#iFB_`gPaiuxTt)Hv?5UBY=09s<#^#w8!-t@(VnIR5AAX$%P3TPxSjVY}>8 ze~@jT%j$Q&q+LqVIm}^oaLz#qz!UQ&l_}%PDXMno9%@DHZ^iKA&7o_(pj+fQ{4o|3ru`Utj~ny_MLn07D*Mfm-$cxt{ zvNz;>p%|7TCtZ=%Gw{ED$7#!PYI{s?cgWkSqIt`o#-xvjg~$=7)zg~!#-FCLr=2|O zk+&OahK3MgE2jNIy`t{UL8DZ)kaF$3qPGo>&Cs`BD(ZRP_{-yH8|$-Ofw@n2%W8th zr(S~z>*nh$g~`m>M|mpYPpADvS@FiJN|iRWym;uu{dN!f6<+ByRE`$aR zkowAa#N)~_uj>pZdq3ho;R`X zi3dV##m3f_ovg>K;ntHMvsJU&H{A>&rn1D{j~1F{8-Ne(-dgCNVz&|DG zZe`B}Th+P-(b+e(+^y`5U?=O$t?Zj%^Hx4Xzk$eux6FJnS}M}izTLu_Eb3%+Y-Ix$ zwecL?B1*Y}-^|2sEx3Ly(tqzA{29506)kFGU9pAjT(rm)|2D00_@M=6v}@YIx7o18 zZLMqHW(6S6zP)wR;#N`C2R5+sWgWZRzlmo2y>j4rDb$FJ?5DTLinHn2=4=|O##%@l z%@m}G6QBFM?2+Ynj_>m(N|k>d);S+~@|X!I7FOb>8>me#DmZkKF*dc@xA|P+Zy*|0 zYErG_xBKb#XMT&3cv1U?(xoC%p9MR&XvuCYZ*D!gfi-=ppY`51*<&wtvBtg0UVSMc zt`@}_(*xVVU#*nk5X#`UH`uY4GCIAuF&xGdao$^5^zc=i!4V`p7(Wo<$fH2i-E`kk zdw3)3QMB@bcitcy3u|w1dQn>gN~L;2Rth&$}u^7o_+zwI~&d)|q>QQSr#+gnkC z1nYiI4K`y%JO7XCkWzjr{H^`k({!)qQ$x`*=72Au?FOdag-yBO z?*dN^X7I0rr%|Bpk^>*{Cbq1nvgzuy71d@_vLcIEx>xh5?YYifIye})fKTtc{duhr? zXM5#%Z{^`>R#=<1j#*YFSi8Q?TCD8iSuElvQbMQK>Io6kM=jV&kIS{cUT4p&?C9ws z6zNx5+G3$d3@Os%b8X}6>@XBVLY6^_JxmNK((`ofL1ewEssA8aZX2CZ@#E&%Jx6=p z)N?cGw5lAvdATWcqo{ca)B5AC0N(c7v^2xrp#IV&N2xLBhfSQ8@o>h&t zEOT{Z|Do3~T=#mDru>3T>s3j=0E}O>Ax456C=H~e~&>;L@^#S z$9ShI#w5Uv^}-zIjf=L~7qzP!+D?09ExWWj)_*Tmm6oNKc%8An@&?R+`dR!isb_DV zSZDfQS=-m?qh&1awL6Nb9Z6j`ORdYRi1EGw@eXZ(?9VPYAZ`p2L30f#(dtK1=aE!s z0vgGHxuJeV=mUfXd$PvV2AyYuY=22FLGC2P7hdW)A+G*mBL^xsq#UXzx!7Db{*5H47#&sLF! z-{k$8c8vdalEwr>E6^|AHXvI%wSd!BLbu+ZaTE(L*!C)$`f6gwuaPF~ecoidBxSyD z!45ePRX5d54wqrw0he}#=N0u^3Oo4f&{|LFTww}JF22(`I)x1{Zfd=`hCN%{+4_Dl zd$+ieKL;w?9lS+RS8AP7YK%rG6!kl2)K_#SM3U9KZuFdytVp)a(6sSLgNn9@hG5{% zjUC56I?^Yo$4aWEM$>~m>R_8^r)ZIHgHMt>t_zKH;?QQFeud_q6$mYOO>j0YYVV75cx?`l>YP0^ zXxRtrMLT=Z}jvB(UPG#e?gOm6be;Axxs&orBmF&zL3D${4%<*QsHg_3WMT=tTG2inXpqR@kru!xKz?*ki zuf5FtZ^kL7sDf*6i3*~Pxk+otJCp#w*O*DT)o($bXHVj=EUzy8+C&b_&=lKWXYun) zt?LT*{hJ=^(d8^^LknwZ5o^1_-E0jtw`~~41nR_BBW%y~X(VCSJUR)P(ew*d+CJbnixsmp06B3!=P8$0}0~H$;bkk$Y*i-**lG-1c_|!j@z$_Fh-Gk!GNyim+mP5RmavR%|F_RN3yr(6S(D9-a>7eqfa5{!&E>53#%3`KP)sGz zi}r>5VTiVrP2AYRd9gNH-nx_=S8`j~!ZFQbR)VFI9m5NLaVa~z(QRG8*oBQ*-P=G) zyWqE%z)2ZKn=)-JZm9_hFfWnYtEe{>R7=n3cL+)U`6X=pTWQu4OWB&YS|>7~d{ak# z=nIVXxcGiZ4q)4+y-`S2LA!jsoQ2-H&$@95>#=F1RawGb+4QLO=rR`dw%59@ko9@{ z0jsZ&t$e$O^%i3%-p&}k2aTY>U+{UaU=J9CyRY4c#Ln)}O@;U@@S%I?_ZWQ8;3wEL zVv>04A?1RXlwNr1B14-aN|-oQ zDs;mzV?qmc@$y?K`P#u66T+}Y|`#CC1= zS&s*qt7NG4nIL}*M*e>6(PTQia0Q0~|QC2AiAkx%wQQQDJK zM{08`*BVB<=aYFos3|hE0noz91-5ZoK4QUzhMDT3*CEnw1w<;#jZ_juUKv`m7|J4$ zO}kS3R17Du`;=ghBRIc0sC5mp&F?lHz0rs@88?&<%IDVXRKCSX*@wq+?oc07`|(Y3 zo)OE-Z>s8bm`d~@l_=PA2v%S1i5FSYmX=PfDF!VzU6_l5%}zFDL$|cDZeGm%TUu`U zsKQe8T3t(zt+CtoSlHn0t69a4;WYJnKR)lLNvadKi74wUaElxT(R zLBFiU8ax=Z13Z<(_(>mmEayNE!;QVfjk z1RV@Yo25KE9$?(u9u7}H!gW4E1kfJ4Ai&SRe4wjAhk@<@UA-?HUI(9l6X*`m9iZQW z`u2yz9pEzz104*y`Z&_51wGJppb1~0z@QyK&w)+=?LZX(^+m%UJohaCl<@HP;czVe zYv8w_9Y9zAj0`|;g7&C~j4BZUOZ`mH1n>(%zXk1aIUKHot%48K13C;e8*~EbSkO(N z>p*va?g0H3^c?6p&{%(c)cgt}fGz}G4SM*Ga5xbV0kuopk$fhs?* zPE7}`Mb+d!u26H;G*U1$;MGXkxK=C(hml`Zup{;`aD~8GLFr9@4*=P?wxRFog*)~! z*cjN+wo<)9za1{W6s&K*A0*#7zurREqL{@E?EAs)-go%ZBcIu!EG=}|+X@9PZU6?6 zdVtg`_9wgS@pM<{PnPVz@m0`3%VEl}h#&b(z1s8!O#k)7r((vi96#wJ&9vdu04{!vozNcKp9_ zj3P?Q-X9hnkse@fQ+AB94MHzchw}75z5?=0JDXMBy%x8FlHT@?$jV#4q<4Oe`85|> zgSJKX#ZmUpEGS3!wCX6*pgPw*gM^iox5 z0*L>wsLERyt^ZJ!bTlPR5EAt0wOIDW(V}^x*dL#qZT=ey?)bEN_LO!VGQCfk^-!xC z>A00YW$h0&anfxDv@;>Jud2lc9ZIdSjAQIYi0L*FVtQkk{hnHE@!{s|=%IU~sSnd( zXG4nEwHmMeN1H10UFg+u88&c+WzM0=3E>;4}UK{}%Y92s{t^UjQEmyaf05 zrmWMakJp%h1}T1-t^KrBjb*sqR?ZH7disu;m~BgrRnKq}BGGKT0XV(*&R$f5CGBg@ zE*;5tdSD^jFbR&Lga_4N`JbiMC;&F(G~51J6DQr0m|py5ch=xdn@~QaMmDCz4L@vs zw!FQic^*bX;_2#HQj07E?mo>n?rBnE6K-9nsflYGrm=IHS&wyZTZiV1h=?7i9Kf&t z5DvTPz9ZXytT~%~%-%H}um+f0HvL4!FbC>>j7AC+eHir0jp!F`?4x5XoeP1L0-FuF z{g92FJ*GH+66s|kzWoIoyX$kc`D!Fy`0L;6@*eQ(-?1~FCk*Oh>F^)R@UqrYY0aqh zt);&lQ8!yjpVnF${aF*KpwZV>kR?sg%2yNS*T6mO^Lb=SA-t-NrN(=LZXVB=JI-Q`reN^DNAP%mST%X= z2%cUvMZt(qFP1X%^d>74KS=6T9gt`lG%4^`TbcPsg&ZctgYh~}m<|s^*0bmznzyQ? z{zRZ&q>zEOqX3KJVMh$>_d|>NyWO0ld7VP0gFTDL#@kS7dZLga+E%v)NjhL*+ka?o z-QZ#0{LsAqrq;UFAK~y*bXSYDJn<@? z3))N20fLU;6i(1Y0n8F~k)Ue?eMiupf*uj{l%N*`y(MV9PND#UCJWk2&;f#uAd38@ zi2|4<=psSa2>OnoI|V%==qW)j2zpDvOV9y=jsT_nrHKNVCFmkS*9iKK zpgRRUBIqeWF9>=|(0b{j0D>k9+Dp&@f{sY%uMtK81Tag`MS`vo^c_KW3VKA)Q-V@< z#u%ad;(e_9FJlu@yLr=ac?qhn;ND-Q(5dr3DHM~!m}aTnx_RmPrz8%r?!S&r=#=5@ zgzFy^ilLxA(lpK6DJ|`v#0FkWj^03?00O3m7cX{+F(wa#V)8h4 zF*(MVV+@L^C#Etv+L+EVJFN^^+Ntayp|MvQCw&YUBn2Jq$QU?9P#g1J{j(P869X4pLjm2C} zuIngsbDY1moTohMvO79apowMd#milyGX$Ga#twotR-Vi<7Ja2lH0Dc*f?US>UFlMP zoS2!%?dGT?vn5wjjOn^WfG4c%*p=j%1^e7wX~8~S*M&m;mKf&)JAVlyn`crN~x0l(<`Y-Xv0!xSWT5O$MGIh z)37#VwtslRGRbUsE4yJpx~|CIhWGFpwqqosM{r7p)l|n_l3_O0@%mM7x37-JNQMPf z!~J-9xnWDy1n_|kqpFTKgjKoC5WlzK#pi~ZnT0mIx4cA{Uv)fQB2#N*2I=00_hA=* z!j4@_wpOMy>-A*6qs&c$s?Z*H7PwB4^~vD)->cIXxD~IUbak#ug5M0~`jnfS^M;r8 zxWG5)c!R1}ZO(vz5-RM>c3n^I=Pq*txE+?@)`Hi|mxy6)NM7am-^=wDa7xa-o^}5t z*{_LWz-#7VB+6qk*~=DzKSH?WcK3G^_GKL2A_fzYmfz8u|DAa z{KEkxXdwiS{cd8bBJ>fs@dnXHxm1!y3VcC?{#+vifgAd-8tET!^Az*~VIb@>G7thI z!uLi7)gqtCxW#ip$=GFD1&b!A_N4k3EU{q0pMgx#(pGM zq;rh)F`&+gmVhbnP{HxKQt=x)KTG5<{US2BDKcm(B3No*1BMq^3$}_F34OOwhiGh4 zs4`xG57%L-KGLCz#s60a#tVE@4b-3dvM{2gPm2fzA_5-Y@~}|g#R6X=@NWd3S*im@ z*U5 z!V5%&QGY$0;et!yzs;HsitzVYxh}_Jq?9tZNI@q}IDQHLVWB$S8h9(%O2j7?nn-5|Q6qSVONL@4Qb)Bfq!s8*u%53vOO&qmSy~JCwCW;mL35HGlz4iOJ&RL-o`3Z(5^p1CB zB<5pEA@UOpJAhMhBR|35Knsz6Go>0hT$ z)=-ZY`89?@F18%k$yr^w0sKa)ZTWqAb&QWOWEEYaw4M{<;whqe#fttL7vt^!|NJ?I zrobuH$j>pP6}?--5@&f(CnY+u7S*o_u(eLw>7<`d#_D7yCyjT)0imxyM1GWEHy10P zK}@+uewCpo);iv!!bV`MJg5S%n4|Lst`!|cftvNfkDjRcBfre>65)K3J63gf!ML-; z7ALU#z+827Jzw25K z>=CKpk)La5RCEbNOHCHy$nP}_0ZwI&{9ePmJeuVYCykHt*nj`v&{tgiK}8+QZcD2! zX(Kz09QnkPlg5l3Gj7_%Cq_;hJ?4p#$*CC`ou%YX$?09viZY#+_{7vMT~h>56=A|t zW4L;9YL_nEs%vLtWc+XKjEt_;wYy|=`QO@IB1_UWrPKe`?wXQXJ?*ZY{x4~F?NqIn zEmJf8Z?(+m(v8iGO)jd8vBa`E4O{;GLl-2P%fCDEM=ZW-bUnsWhqZ|BK;O0a@q?&_ zmP1yS-?-@q(eakAEk&E#Tk3z%v5954rRd*HEeAgMAi*-!Qq(jFM@ygH(c*(4%`K&t zqW2Rl^^0;FSsWj%a$DM3i`KWdH0AkL`-BF2r%j`x+N~{FAB=Bp8DuG%eTV7u7e$*J zSq2xiY-nltf!4+{)ml`TX!(r29^a^FQ#(s$QFMDt@1mvcu}X+4)iHm&gUz`kj*V*3 z>4VrL%MuG~5f@iiCXj_8C&H6QK@&UfI(bZBkqNAmzef-4ndF+Qq@zI%?5A+>4 KNV#`_^nU<;-l?Ae diff --git a/PairHMM_JNI/org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM.cc b/PairHMM_JNI/org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM.cc index 852caa00d..59d00928e 100644 --- a/PairHMM_JNI/org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM.cc +++ b/PairHMM_JNI/org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM.cc @@ -18,6 +18,8 @@ #include #include using namespace std; + +#define ENABLE_ASSERTIONS 1 //#define DEBUG 1 //#define DEBUG0_1 1 //#define DEBUG3 1 @@ -189,7 +191,11 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPai g_load_time_initializer.m_haplotypeBasesFID = fid; } - +//JNI function to invoke compute_full_prob_avx +//readDataArray - array of JNIReadDataHolderClass objects which contain the readBases, readQuals etc +//haplotypeDataArray - array of JNIHaplotypeDataHolderClass objects which contain the haplotypeBases +//likelihoodArray - array of doubles to return results back to Java. Memory allocated by Java prior to JNI call +//maxNumThreadsToUse - Max number of threads that OpenMP can use for the HMM computation JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPairHMM_jniComputeLikelihoods (JNIEnv* env, jobject thisObject, jint numReads, jint numHaplotypes, jobjectArray readDataArray, jobjectArray haplotypeDataArray, jdoubleArray likelihoodArray, jint maxNumThreadsToUse) @@ -206,16 +212,16 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPai { jobject haplotypeObject = env->GetObjectArrayElement(haplotypeDataArray, j); jbyteArray haplotypeBases = (jbyteArray)env->GetObjectField(haplotypeObject, g_load_time_initializer.m_haplotypeBasesFID); -#ifdef DEBUG +#ifdef ENABLE_ASSERTIONS assert(haplotypeBases && ("haplotypeBases is NULL at index : "+to_string(j)+"\n").c_str()); #endif jbyte* haplotypeBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(haplotypeBases, &is_copy); -#ifdef DEBUG +#ifdef ENABLE_ASSERTIONS assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI"); assert(env->GetArrayLength(haplotypeBases) < MCOLS); +#endif #ifdef DEBUG0_1 cout << "JNI haplotype length "<GetArrayLength(haplotypeBases)<<"\n"; -#endif #endif haplotypeBasesArrayVector[j] = make_pair(haplotypeBases, haplotypeBasesArray); #ifdef DEBUG3 @@ -243,7 +249,7 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPai jbyteArray overallGCP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_overallGCPFID); jbyteArray readQuals = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_readQualsFID); -#ifdef DEBUG +#ifdef ENABLE_ASSERTIONS assert(readBases && ("readBases is NULL at index : "+to_string(i)+"\n").c_str()); assert(insertionGOP && ("insertionGOP is NULL at index : "+to_string(i)+"\n").c_str()); assert(deletionGOP && ("deletionGOP is NULL at index : "+to_string(i)+"\n").c_str()); @@ -257,7 +263,7 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPai jbyte* insertionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(insertionGOP, &is_copy); jbyte* deletionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(deletionGOP, &is_copy); jbyte* overallGCPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(overallGCP, &is_copy); -#ifdef DEBUG +#ifdef ENABLE_ASSERTIONS assert(readBasesArray && "readBasesArray not initialized in JNI"); assert(readQualsArray && "readQualsArray not initialized in JNI"); assert(insertionGOPArray && "insertionGOP array not initialized in JNI"); @@ -268,10 +274,10 @@ JNIEXPORT void JNICALL Java_org_broadinstitute_sting_utils_pairhmm_JNILoglessPai assert(readLength == env->GetArrayLength(insertionGOP)); assert(readLength == env->GetArrayLength(deletionGOP)); assert(readLength == env->GetArrayLength(overallGCP)); +#endif #ifdef DEBUG0_1 cout << "JNI read length "<GetArrayLength(likelihoodArray) == numTestCases); +#endif #pragma omp parallel for schedule (dynamic,10) private(tc_idx) num_threads(maxNumThreadsToUse) for(tc_idx=0;tc_idx readDataHolderClass, Class haplotypeDataHolderClass); + + private static boolean isJNILoglessPairHMMLibraryLoaded = false; + + public JNILoglessPairHMM() + { + super(); + if(!isJNILoglessPairHMMLibraryLoaded) + { + System.loadLibrary("JNILoglessPairHMM"); + isJNILoglessPairHMMLibraryLoaded = true; + jniGlobalInit(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class); //need to do this only once } } - - private native void jniInitialize(final int readMaxLength, final int haplotypeMaxLength); - - private native static void jniInitializeProbabilities(final double[][] transition, final byte[] insertionGOP, final byte[] deletionGOP, final byte[] overallGCP); + //Used to test parts of the compute kernel separately + private native void jniInitialize(final int readMaxLength, final int haplotypeMaxLength); + private native static void jniInitializeProbabilities(final double[][] transition, final byte[] insertionGOP, final byte[] deletionGOP, final byte[] overallGCP); private native double jniInitializePriorsAndUpdateCells( boolean doInitialization, final int paddedReadLength, final int paddedHaplotypeLength, final byte[] readBases, final byte[] haplotypeBases, final byte[] readQuals, final int hapStartIndex); - private native double jniSubComputeReadLikelihoodGivenHaplotypeLog10( final int readLength, final int haplotypeLength, final byte[] readBases, final byte[] haplotypeBases, final byte[] readQuals, @@ -101,14 +119,15 @@ public class JNILoglessPairHMM extends LoglessPairHMM { final int hapStartIndex); - + //Used only when testing parts of the compute kernel /** * {@inheritDoc} */ @Override public void initialize(final int readMaxLength, final int haplotypeMaxLength) { - super.initialize(readMaxLength, haplotypeMaxLength); + if(debug) + super.initialize(readMaxLength, haplotypeMaxLength); if(debug3) { System.out.println("Java: alloc initialized readMaxLength : "+readMaxLength+" haplotypeMaxLength : "+haplotypeMaxLength); @@ -119,97 +138,142 @@ public class JNILoglessPairHMM extends LoglessPairHMM { jniInitialize(readMaxLength, haplotypeMaxLength); } + //Real compute kernel + private native void jniComputeLikelihoods(int numReads, int numHaplotypes, + JNIReadDataHolderClass[] readDataArray, JNIHaplotypeDataHolderClass[] haplotypeDataArray, + double[] likelihoodArray, int maxNumThreadsToUse); /** * {@inheritDoc} */ @Override public PerReadAlleleLikelihoodMap computeLikelihoods(final List reads, final Map alleleHaplotypeMap, final Map GCPArrayMap) { - PerReadAlleleLikelihoodMap retValue = super.computeLikelihoods(reads, alleleHaplotypeMap, GCPArrayMap); + // (re)initialize the pairHMM only if necessary + final int readMaxLength = debug ? findMaxReadLength(reads) : 0; + final int haplotypeMaxLength = debug ? findMaxHaplotypeLength(alleleHaplotypeMap) : 0; if(debug) + { + if (!initialized || readMaxLength > maxReadLength || haplotypeMaxLength > maxHaplotypeLength) + { initialize(readMaxLength, haplotypeMaxLength); } + if ( ! initialized ) + throw new IllegalStateException("Must call initialize before calling jniComputeLikelihoods in debug mode"); + } + int readListSize = reads.size(); + int alleleHaplotypeMapSize = alleleHaplotypeMap.size(); + if(debug0_1) + System.out.println("Java numReads "+readListSize+" numHaplotypes "+alleleHaplotypeMapSize); + JNIReadDataHolderClass[] readDataArray = new JNIReadDataHolderClass[readListSize]; + int idx = 0; + for(GATKSAMRecord read : reads) + { + readDataArray[idx] = new JNIReadDataHolderClass(); + readDataArray[idx].readBases = read.getReadBases(); + readDataArray[idx].readQuals = read.getBaseQualities(); + readDataArray[idx].insertionGOP = read.getBaseInsertionQualities(); + readDataArray[idx].deletionGOP = read.getBaseDeletionQualities(); + readDataArray[idx].overallGCP = GCPArrayMap.get(read); + + if(debug0_1) + System.out.println("Java read length "+readDataArray[idx].readBases.length); + if(debug3) + { + for(int i=0;i currEntry : alleleHaplotypeMap.entrySet()) //order is important - access in same order always + { + haplotypeDataArray[idx] = new JNIHaplotypeDataHolderClass(); + haplotypeDataArray[idx].haplotypeBases = currEntry.getValue().getBases(); + if(debug0_1) + System.out.println("Java haplotype length "+haplotypeDataArray[idx].haplotypeBases.length); + if(debug3) + { + for(int i=0;i currEntry : alleleHaplotypeMap.entrySet())//order is important - access in same order always + { + likelihoodMap.add(read, currEntry.getKey(), likelihoodArray[idx]); + ++idx; + } + if(debug) + { + //to compare values + likelihoodMap = super.computeLikelihoods(reads, alleleHaplotypeMap, GCPArrayMap); + //for floating point values, no exact equality + //check whether numbers are close in terms of abs_error or relative_error + //For very large values, relative_error is relevant + //For very small values, abs_error is relevant + boolean toDump = false; + for(int i=0;i 1e-5 && relative_error > 1e-5) + { + toDump = true; + break; + } + } + //if numbers are not close, then dump out the data that produced the inconsistency + if(toDump) + { + idx = 0; + System.out.println("Dump : Java numReads "+readListSize+" numHaplotypes "+alleleHaplotypeMapSize); + for(int i=0;i maxReadLength || haplotypeMaxLength > maxHaplotypeLength) - //{ initialize(readMaxLength, haplotypeMaxLength); } - - //if ( ! initialized ) - //throw new IllegalStateException("Must call initialize before calling computeReadLikelihoodGivenHaplotypeLog10"); - //final PerReadAlleleLikelihoodMap likelihoodMap = new PerReadAlleleLikelihoodMap(); - //for(GATKSAMRecord read : reads){ - //final byte[] readBases = read.getReadBases(); - //final byte[] readQuals = read.getBaseQualities(); - //final byte[] readInsQuals = read.getBaseInsertionQualities(); - //final byte[] readDelQuals = read.getBaseDeletionQualities(); - //final byte[] overallGCP = GCPArrayMap.get(read); - - //// peak at the next haplotype in the list (necessary to get nextHaplotypeBases, which is required for caching in the array implementation) - //byte[] currentHaplotypeBases = null; - //boolean isFirstHaplotype = true; - //Allele currentAllele = null; - //double log10l; - //for (final Allele allele : alleleHaplotypeMap.keySet()){ - //final Haplotype haplotype = alleleHaplotypeMap.get(allele); - //final byte[] nextHaplotypeBases = haplotype.getBases(); - //if (currentHaplotypeBases != null) { - //log10l = computeReadLikelihoodGivenHaplotypeLog10(currentHaplotypeBases, - //readBases, readQuals, readInsQuals, readDelQuals, overallGCP, isFirstHaplotype, nextHaplotypeBases); - //likelihoodMap.add(read, currentAllele, log10l); - //} - //// update the current haplotype - //currentHaplotypeBases = nextHaplotypeBases; - //currentAllele = allele; - //} - //// process the final haplotype - //if (currentHaplotypeBases != null) { - - //// there is no next haplotype, so pass null for nextHaplotypeBases. - //log10l = computeReadLikelihoodGivenHaplotypeLog10(currentHaplotypeBases, - //readBases, readQuals, readInsQuals, readDelQuals, overallGCP, isFirstHaplotype, null); - //likelihoodMap.add(read, currentAllele, log10l); - //} - //} - //return likelihoodMap; - //} - - ///** - //* {@inheritDoc} - //*/ - //@Override - //protected final double computeReadLikelihoodGivenHaplotypeLog10( final byte[] haplotypeBases, - //final byte[] readBases, - //final byte[] readQuals, - //final byte[] insertionGOP, - //final byte[] deletionGOP, - //final byte[] overallGCP, - //final boolean recacheReadValues, - //final byte[] nextHaploytpeBases) { - - //if ( haplotypeBases == null ) throw new IllegalArgumentException("haplotypeBases cannot be null"); - //if ( haplotypeBases.length > maxHaplotypeLength ) throw new IllegalArgumentException("Haplotype bases is too long, got " + haplotypeBases.length + " but max is " + maxHaplotypeLength); - //if ( readBases == null ) throw new IllegalArgumentException("readBases cannot be null"); - //if ( readBases.length > maxReadLength ) throw new IllegalArgumentException("readBases is too long, got " + readBases.length + " but max is " + maxReadLength); - //if ( readQuals.length != readBases.length ) throw new IllegalArgumentException("Read bases and read quals aren't the same size: " + readBases.length + " vs " + readQuals.length); - //if ( insertionGOP.length != readBases.length ) throw new IllegalArgumentException("Read bases and read insertion quals aren't the same size: " + readBases.length + " vs " + insertionGOP.length); - //if ( deletionGOP.length != readBases.length ) throw new IllegalArgumentException("Read bases and read deletion quals aren't the same size: " + readBases.length + " vs " + deletionGOP.length); - //if ( overallGCP.length != readBases.length ) throw new IllegalArgumentException("Read bases and overall GCP aren't the same size: " + readBases.length + " vs " + overallGCP.length); - - //paddedReadLength = readBases.length + 1; - //paddedHaplotypeLength = haplotypeBases.length + 1; - //double result = subComputeReadLikelihoodGivenHaplotypeLog10(haplotypeBases, readBases, readQuals, insertionGOP, deletionGOP, overallGCP, 0, true, 0); - //if ( ! MathUtils.goodLog10Probability(result) ) - //throw new IllegalStateException("PairHMM Log Probability cannot be greater than 0: " + String.format("haplotype: %s, read: %s, result: %f", Arrays.toString(haplotypeBases), Arrays.toString(readBases), result)); - //// Warning: Careful if using the PairHMM in parallel! (this update has to be taken care of). - //// Warning: This assumes no downstream modification of the haplotype bases (saves us from copying the array). It is okay for the haplotype caller and the Unified Genotyper. - //// KG: seems pointless is not being used anywhere - //previousHaplotypeBases = haplotypeBases; - //return result; - //} /** * {@inheritDoc} @@ -232,10 +296,11 @@ public class JNILoglessPairHMM extends LoglessPairHMM { //} //System.out.println("#### END STACK TRACE ####"); // + if(debug1) jniSubComputeReadLikelihoodGivenHaplotypeLog10(readBases.length, haplotypeBases.length, - readBases, haplotypeBases, readQuals, - insertionGOP, deletionGOP, overallGCP, - hapStartIndex); + readBases, haplotypeBases, readQuals, + insertionGOP, deletionGOP, overallGCP, + hapStartIndex); boolean doInitialization = (previousHaplotypeBases == null || previousHaplotypeBases.length != haplotypeBases.length); if (doInitialization) { @@ -310,6 +375,9 @@ public class JNILoglessPairHMM extends LoglessPairHMM { // initialize the pBaseReadLog10 matrix for all combinations of read x haplotype bases // Abusing the fact that java initializes arrays with 0.0, so no need to fill in rows and columns below 2. + if(debug3) + System.out.println("hapStartIndex "+startIndex); + for (int i = 0; i < readBases.length; i++) { final byte x = readBases[i]; final byte qual = readQuals[i]; diff --git a/public/java/src/org/broadinstitute/sting/utils/pairhmm/PairHMM.java b/public/java/src/org/broadinstitute/sting/utils/pairhmm/PairHMM.java index ff883c5ae..3b4498776 100644 --- a/public/java/src/org/broadinstitute/sting/utils/pairhmm/PairHMM.java +++ b/public/java/src/org/broadinstitute/sting/utils/pairhmm/PairHMM.java @@ -57,6 +57,8 @@ public abstract class PairHMM { ORIGINAL, /* Optimized version of the PairHMM which caches per-read computations and operations in real space to avoid costly sums of log10'ed likelihoods */ LOGLESS_CACHING, + /* Optimized AVX implementation of LOGLESS_CACHING called through JNI */ + JNI_LOGLESS_CACHING, /* Logless caching PairHMM that stores computations in 1D arrays instead of matrices, and which proceeds diagonally over the (read x haplotype) intersection matrix */ ARRAY_LOGLESS } @@ -70,6 +72,9 @@ public abstract class PairHMM { protected boolean doNotUseTristateCorrection = false; protected void doNotUseTristateCorrection() { doNotUseTristateCorrection = true; } + //debug array + protected double[] mLikelihoodArray; + /** * Initialize this PairHMM, making it suitable to run against a read and haplotype with given lengths * @@ -132,6 +137,8 @@ public abstract class PairHMM { if (!initialized || readMaxLength > maxReadLength || haplotypeMaxLength > maxHaplotypeLength) { initialize(readMaxLength, haplotypeMaxLength); } final PerReadAlleleLikelihoodMap likelihoodMap = new PerReadAlleleLikelihoodMap(); + mLikelihoodArray = new double[reads.size()*alleleHaplotypeMap.size()]; + int idx = 0; for(GATKSAMRecord read : reads){ final byte[] readBases = read.getReadBases(); final byte[] readQuals = read.getBaseQualities(); @@ -144,12 +151,16 @@ public abstract class PairHMM { boolean isFirstHaplotype = true; Allele currentAllele = null; double log10l; - for (final Allele allele : alleleHaplotypeMap.keySet()){ - final Haplotype haplotype = alleleHaplotypeMap.get(allele); + //for (final Allele allele : alleleHaplotypeMap.keySet()){ + for (Map.Entry currEntry : alleleHaplotypeMap.entrySet()){ + //final Haplotype haplotype = alleleHaplotypeMap.get(allele); + final Allele allele = currEntry.getKey(); + final Haplotype haplotype = currEntry.getValue(); final byte[] nextHaplotypeBases = haplotype.getBases(); if (currentHaplotypeBases != null) { log10l = computeReadLikelihoodGivenHaplotypeLog10(currentHaplotypeBases, readBases, readQuals, readInsQuals, readDelQuals, overallGCP, isFirstHaplotype, nextHaplotypeBases); + mLikelihoodArray[idx++] = log10l; likelihoodMap.add(read, currentAllele, log10l); } // update the current haplotype @@ -163,6 +174,7 @@ public abstract class PairHMM { log10l = computeReadLikelihoodGivenHaplotypeLog10(currentHaplotypeBases, readBases, readQuals, readInsQuals, readDelQuals, overallGCP, isFirstHaplotype, null); likelihoodMap.add(read, currentAllele, log10l); + mLikelihoodArray[idx++] = log10l; } } return likelihoodMap;