From e8b42c4dfd7b2ebbdceafd28b0e5af420c77219e Mon Sep 17 00:00:00 2001 From: Ernesto Brau Date: Thu, 6 Apr 2017 10:42:56 -0400 Subject: [PATCH] Use GKL's implementation of Vector Logless Pair HMM Fixed MuTect2 tests by removing old -alwaysloadVectorHmm flag; upgraded to GKL 0.5.2; FASTEST_AVAILABLE pairhmm option; improved documenting comments in code Made FASTEST_AVAIALABLE the default for the pairHMM cmdline argument Make LOGLESS_CACHING the default pairHMM unified cmdline argument, fix error message if choose an unrecognized pairHMM Updae MD5s --- .../gatk/tools/walkers/cancer/m2/MuTect2.java | 4 +- .../genotyper/UnifiedGenotypingEngine.java | 2 +- .../haplotypecaller/HaplotypeCaller.java | 4 +- .../LikelihoodEngineArgumentCollection.java | 29 +- .../PairHMMLikelihoodCalculationEngine.java | 39 +- .../PairHMMNativeArgumentCollection.java | 79 +++ .../utils/pairhmm/DebugJNILoglessPairHMM.java | 5 +- .../utils/pairhmm/VectorLoglessPairHMM.java | 273 ++------- .../cancer/m2/MuTect2IntegrationTest.java | 4 +- ...LikelihoodCalculationEnginesBenchmark.java | 2 +- ...lexAndSymbolicVariantsIntegrationTest.java | 17 +- .../HaplotypeCallerGVCFIntegrationTest.java | 75 ++- .../HaplotypeCallerIntegrationTest.java | 61 +- .../HaplotypeCallerModesIntegrationTest.java | 4 +- ...aplotypeCallerParallelIntegrationTest.java | 4 +- ...MMLikelihoodCalculationEngineUnitTest.java | 2 +- ...ngLikelihoodCalculationEngineUnitTest.java | 2 +- public/VectorPairHMM/README.md | 72 --- public/VectorPairHMM/pom.xml | 122 ---- public/VectorPairHMM/src/main/c++/.gitignore | 16 - .../src/main/c++/LoadTimeInitializer.cc | 205 ------- .../src/main/c++/LoadTimeInitializer.h | 86 --- public/VectorPairHMM/src/main/c++/Makefile | 126 ---- public/VectorPairHMM/src/main/c++/Sandbox.cc | 106 ---- public/VectorPairHMM/src/main/c++/Sandbox.h | 96 --- .../VectorPairHMM/src/main/c++/Sandbox.java | 306 ---------- .../c++/Sandbox_JNIHaplotypeDataHolderClass.h | 13 - .../main/c++/Sandbox_JNIReadDataHolderClass.h | 13 - .../main/c++/avx_function_instantiations.cc | 45 -- public/VectorPairHMM/src/main/c++/baseline.cc | 157 ----- .../src/main/c++/common_data_structure.h | 215 ------- .../src/main/c++/define-double.h | 205 ------- .../VectorPairHMM/src/main/c++/define-float.h | 206 ------- .../src/main/c++/define-sse-double.h | 173 ------ .../src/main/c++/define-sse-float.h | 173 ------ public/VectorPairHMM/src/main/c++/headers.h | 71 --- .../VectorPairHMM/src/main/c++/jni_common.h | 60 -- public/VectorPairHMM/src/main/c++/jnidebug.h | 191 ------ ...tk_utils_pairhmm_DebugJNILoglessPairHMM.cc | 175 ------ ...atk_utils_pairhmm_DebugJNILoglessPairHMM.h | 86 --- ...gatk_utils_pairhmm_VectorLoglessPairHMM.cc | 416 ------------- ..._gatk_utils_pairhmm_VectorLoglessPairHMM.h | 96 --- .../src/main/c++/pairhmm-1-base.cc | 65 -- .../src/main/c++/pairhmm-template-kernel.cc | 380 ------------ .../src/main/c++/pairhmm-template-main.cc | 113 ---- public/VectorPairHMM/src/main/c++/run.sh | 32 - .../src/main/c++/shift_template.c | 113 ---- .../main/c++/sse_function_instantiations.cc | 44 -- public/VectorPairHMM/src/main/c++/template.h | 119 ---- public/VectorPairHMM/src/main/c++/utils.cc | 567 ------------------ public/VectorPairHMM/src/main/c++/utils.h | 85 --- public/gatk-root/pom.xml | 2 +- public/gatk-tools-public/pom.xml | 5 + .../gatk/utils/pairhmm/PairHMM.java | 31 +- .../utils/pairhmm/libVectorLoglessPairHMM.so | Bin 479437 -> 0 bytes 55 files changed, 262 insertions(+), 5330 deletions(-) create mode 100644 protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMNativeArgumentCollection.java delete mode 100644 public/VectorPairHMM/README.md delete mode 100644 public/VectorPairHMM/pom.xml delete mode 100644 public/VectorPairHMM/src/main/c++/.gitignore delete mode 100644 public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc delete mode 100644 public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h delete mode 100644 public/VectorPairHMM/src/main/c++/Makefile delete mode 100644 public/VectorPairHMM/src/main/c++/Sandbox.cc delete mode 100644 public/VectorPairHMM/src/main/c++/Sandbox.h delete mode 100644 public/VectorPairHMM/src/main/c++/Sandbox.java delete mode 100644 public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h delete mode 100644 public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h delete mode 100644 public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc delete mode 100644 public/VectorPairHMM/src/main/c++/baseline.cc delete mode 100644 public/VectorPairHMM/src/main/c++/common_data_structure.h delete mode 100644 public/VectorPairHMM/src/main/c++/define-double.h delete mode 100644 public/VectorPairHMM/src/main/c++/define-float.h delete mode 100644 public/VectorPairHMM/src/main/c++/define-sse-double.h delete mode 100644 public/VectorPairHMM/src/main/c++/define-sse-float.h delete mode 100644 public/VectorPairHMM/src/main/c++/headers.h delete mode 100644 public/VectorPairHMM/src/main/c++/jni_common.h delete mode 100644 public/VectorPairHMM/src/main/c++/jnidebug.h delete mode 100644 public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc delete mode 100644 public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h delete mode 100644 public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc delete mode 100644 public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h delete mode 100644 public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc delete mode 100644 public/VectorPairHMM/src/main/c++/pairhmm-template-kernel.cc delete mode 100644 public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc delete mode 100755 public/VectorPairHMM/src/main/c++/run.sh delete mode 100644 public/VectorPairHMM/src/main/c++/shift_template.c delete mode 100644 public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc delete mode 100644 public/VectorPairHMM/src/main/c++/template.h delete mode 100644 public/VectorPairHMM/src/main/c++/utils.cc delete mode 100644 public/VectorPairHMM/src/main/c++/utils.h delete mode 100644 public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2.java index 2f5ad5a38..f329c4f6c 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2.java @@ -101,6 +101,8 @@ import org.broadinstitute.gatk.utils.sam.*; import org.broadinstitute.gatk.utils.variant.GATKVCFConstants; import org.broadinstitute.gatk.utils.variant.GATKVCFHeaderLines; +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeArguments; + import java.io.FileNotFoundException; import java.util.*; @@ -874,7 +876,7 @@ public class MuTect2 extends ActiveRegionWalker, Integer> i * @return never {@code null}. */ private ReadLikelihoodCalculationEngine createLikelihoodCalculationEngine() { - return new PairHMMLikelihoodCalculationEngine( (byte)LEAC.gcpHMM, LEAC.pairHMM, LEAC.pairHMMSub, LEAC.alwaysLoadVectorLoglessPairHMMLib, log10GlobalReadMismappingRate, LEAC.noFpga, pcrErrorModel ); + return new PairHMMLikelihoodCalculationEngine( (byte)LEAC.gcpHMM, LEAC.pairHMM, LEAC.pairHMMNativeArgs.getPairHMMArgs(), log10GlobalReadMismappingRate, LEAC.noFpga, pcrErrorModel ); } /** diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/UnifiedGenotypingEngine.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/UnifiedGenotypingEngine.java index d1774160e..ce56ed04e 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/UnifiedGenotypingEngine.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/UnifiedGenotypingEngine.java @@ -248,7 +248,7 @@ public class UnifiedGenotypingEngine extends GenotypingEngine, In private ReadLikelihoodCalculationEngine createLikelihoodCalculationEngine() { switch (likelihoodEngineImplementation) { case PairHMM: - return new PairHMMLikelihoodCalculationEngine( (byte) LEAC.gcpHMM, LEAC.pairHMM, LEAC.pairHMMSub, LEAC.alwaysLoadVectorLoglessPairHMMLib, log10GlobalReadMismappingRate, LEAC.noFpga, pcrErrorModel ); + return new PairHMMLikelihoodCalculationEngine( (byte) LEAC.gcpHMM, LEAC.pairHMM, LEAC.pairHMMNativeArgs.getPairHMMArgs(), log10GlobalReadMismappingRate, LEAC.noFpga, pcrErrorModel ); case GraphBased: return new GraphBasedLikelihoodCalculationEngine( (byte) LEAC.gcpHMM,log10GlobalReadMismappingRate, heterogeneousKmerSizeResolution, HCAC.DEBUG, RTAC.debugGraphTransformations); case Random: diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/LikelihoodEngineArgumentCollection.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/LikelihoodEngineArgumentCollection.java index d65daad3e..a82cdcdf3 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/LikelihoodEngineArgumentCollection.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/LikelihoodEngineArgumentCollection.java @@ -53,6 +53,7 @@ package org.broadinstitute.gatk.tools.walkers.haplotypecaller; import org.broadinstitute.gatk.utils.commandline.Advanced; import org.broadinstitute.gatk.utils.commandline.Argument; +import org.broadinstitute.gatk.utils.commandline.ArgumentCollection; import org.broadinstitute.gatk.utils.commandline.Hidden; import org.broadinstitute.gatk.utils.pairhmm.PairHMM; @@ -71,29 +72,7 @@ public class LikelihoodEngineArgumentCollection { */ @Hidden @Argument(fullName = "pair_hmm_implementation", shortName = "pairHMM", doc = "The PairHMM implementation to use for genotype likelihood calculations", required = false) - public PairHMM.HMM_IMPLEMENTATION pairHMM = PairHMM.HMM_IMPLEMENTATION.VECTOR_LOGLESS_CACHING; - - /** - * This argument is intended for use in the test suite only. It gives developers the ability to select of the - * hardware dependent vectorized implementation of the vectorized PairHMM library (pairHMM=VECTOR_LOGLESS_CACHING). - * For normal usage, you should rely on the architecture auto-detection. - */ - @Hidden - @Advanced - @Argument(fullName = "pair_hmm_sub_implementation", shortName = "pairHMMSub", doc = "The PairHMM machine-dependent sub-implementation to use for genotype likelihood calculations", required = false) - public PairHMM.HMM_SUB_IMPLEMENTATION pairHMMSub = PairHMM.HMM_SUB_IMPLEMENTATION.ENABLE_ALL; - - /** - * This argument is intended for use in the test suite only. It gives developers the ability to load different - * hardware dependent sub-implementations (-pairHMMSub) of the vectorized PairHMM library (-pairHMM=VECTOR_LOGLESS_CACHING) - * for each test. Without this option, the library is only loaded once (for the first test executed in the suite) even if - * subsequent tests specify a different implementation. - * Each test will output the corresponding library loading messages. - */ - @Hidden - @Advanced - @Argument(fullName = "always_load_vector_logless_PairHMM_lib", shortName = "alwaysloadVectorHMM", doc = "Load the vector logless PairHMM library each time a GATK run is initiated in the test suite", required = false) - public boolean alwaysLoadVectorLoglessPairHMMLib = false; + public PairHMM.HMM_IMPLEMENTATION pairHMM = PairHMM.HMM_IMPLEMENTATION.FASTEST_AVAILABLE; /** * The phredScaledGlobalReadMismappingRate reflects the average global mismapping rate of all reads, regardless of their @@ -115,6 +94,6 @@ public class LikelihoodEngineArgumentCollection { @Argument(fullName="noFpga", shortName="noFpga", doc="Disable the use of the FPGA HMM implementation", required = false) public boolean noFpga = false; - - + @ArgumentCollection + public PairHMMNativeArgumentCollection pairHMMNativeArgs = new PairHMMNativeArgumentCollection(); } diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngine.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngine.java index 9ae44688a..5b22138fb 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngine.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngine.java @@ -67,6 +67,7 @@ import org.broadinstitute.gatk.utils.haplotype.Haplotype; import org.broadinstitute.gatk.utils.pairhmm.*; import org.broadinstitute.gatk.utils.sam.GATKSAMRecord; import org.broadinstitute.gatk.utils.variant.TandemRepeatFinder; +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeArguments; import java.io.File; import java.io.FileNotFoundException; @@ -82,8 +83,7 @@ public class PairHMMLikelihoodCalculationEngine implements ReadLikelihoodCalcula private final double log10globalReadMismappingRate; private final PairHMM.HMM_IMPLEMENTATION hmmType; - private final PairHMM.HMM_SUB_IMPLEMENTATION hmmSubType; - private final boolean alwaysLoadVectorLoglessPairHMMLib; + private final PairHMMNativeArguments pairHmmNativeArgs; private final boolean noFpga; private final ThreadLocal pairHMMThreadLocal = new ThreadLocal() { @@ -98,24 +98,34 @@ public class PairHMMLikelihoodCalculationEngine implements ReadLikelihoodCalcula else return new CnyPairHMM(); case VECTOR_LOGLESS_CACHING: - try - { - return new VectorLoglessPairHMM(hmmSubType, alwaysLoadVectorLoglessPairHMMLib); + return new VectorLoglessPairHMM(VectorLoglessPairHMM.Implementation.AVX, pairHmmNativeArgs); + case VECTOR_LOGLESS_CACHING_OMP: + return new VectorLoglessPairHMM(VectorLoglessPairHMM.Implementation.OMP, pairHmmNativeArgs); + case FASTEST_AVAILABLE: + try { + return new VectorLoglessPairHMM(VectorLoglessPairHMM.Implementation.OMP, pairHmmNativeArgs); } - catch(UnsatisfiedLinkError ule) - { - logger.warn("Failed to load native library for VectorLoglessPairHMM - using Java implementation of LOGLESS_CACHING"); + catch(UserException.HardwareFeatureException hfe) { + logger.warn("OpenMP multi-threaded AVX-accelerated native PairHMM implementation is not supported"); + } + try { + return new VectorLoglessPairHMM(VectorLoglessPairHMM.Implementation.AVX, pairHmmNativeArgs); + } + catch(UserException.HardwareFeatureException hfe) { + logger.warn("AVX-accelerated native PairHMM implementation is not supported. Falling back to slower LOGLESS_CACHING implementation"); return new LoglessPairHMM(); } case DEBUG_VECTOR_LOGLESS_CACHING: - return new DebugJNILoglessPairHMM(PairHMM.HMM_IMPLEMENTATION.VECTOR_LOGLESS_CACHING, hmmSubType, alwaysLoadVectorLoglessPairHMMLib); + return new DebugJNILoglessPairHMM(PairHMM.HMM_IMPLEMENTATION.VECTOR_LOGLESS_CACHING, pairHmmNativeArgs); case ARRAY_LOGLESS: if (noFpga || !CnyPairHMM.isAvailable()) return new ArrayLoglessPairHMM(); else return new CnyPairHMM(); default: - throw new UserException.BadArgumentValue("pairHMM", "Specified pairHMM implementation is unrecognized or incompatible with the HaplotypeCaller. Acceptable options are ORIGINAL, EXACT, CACHING, LOGLESS_CACHING, and ARRAY_LOGLESS."); + throw new UserException.BadArgumentValue("pairHMM", "Specified pairHMM implementation is unrecognized or " + + "incompatible with the HaplotypeCaller. Acceptable options are ORIGINAL, EXACT, CACHING, LOGLESS_CACHING, " + + "VECTOR_LOGLESS_CACHING, VECTOR_LOGLESS_CACHING_OMP, and ARRAY_LOGLESS."); } } }; @@ -160,8 +170,7 @@ public class PairHMMLikelihoodCalculationEngine implements ReadLikelihoodCalcula * * @param constantGCP the gap continuation penalty to use with the PairHMM * @param hmmType the type of the HMM to use - * @param hmmSubType the type of the machine dependent sub-implementation of HMM to use - * @param alwaysLoadVectorLoglessPairHMMLib always load the vector logless HMM library instead of once + * @param pairHmmNativeArgs arguments to the vector logless PairHMM implementation * @param log10globalReadMismappingRate the global mismapping probability, in log10(prob) units. A value of * -3 means that the chance that a read doesn't actually belong at this * location in the genome is 1 in 1000. The effect of this parameter is @@ -173,11 +182,9 @@ public class PairHMMLikelihoodCalculationEngine implements ReadLikelihoodCalcula * @param noFpga disable FPGA acceleration * @param pcrErrorModel model to correct for PCR indel artifacts */ - public PairHMMLikelihoodCalculationEngine( final byte constantGCP, final PairHMM.HMM_IMPLEMENTATION hmmType, final PairHMM.HMM_SUB_IMPLEMENTATION hmmSubType, - final boolean alwaysLoadVectorLoglessPairHMMLib, final double log10globalReadMismappingRate, final boolean noFpga, final PCR_ERROR_MODEL pcrErrorModel ) { + public PairHMMLikelihoodCalculationEngine( final byte constantGCP, final PairHMM.HMM_IMPLEMENTATION hmmType, final PairHMMNativeArguments pairHmmNativeArgs, final double log10globalReadMismappingRate, final boolean noFpga, final PCR_ERROR_MODEL pcrErrorModel ) { this.hmmType = hmmType; - this.hmmSubType = hmmSubType; - this.alwaysLoadVectorLoglessPairHMMLib = alwaysLoadVectorLoglessPairHMMLib; + this.pairHmmNativeArgs = pairHmmNativeArgs; this.constantGCP = constantGCP; this.log10globalReadMismappingRate = log10globalReadMismappingRate; this.noFpga = noFpga; diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMNativeArgumentCollection.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMNativeArgumentCollection.java new file mode 100644 index 000000000..baf246bd3 --- /dev/null +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMNativeArgumentCollection.java @@ -0,0 +1,79 @@ +/* +* By downloading the PROGRAM you agree to the following terms of use: +* +* BROAD INSTITUTE +* SOFTWARE LICENSE AGREEMENT +* FOR ACADEMIC NON-COMMERCIAL RESEARCH PURPOSES ONLY +* +* This Agreement is made between the Broad Institute, Inc. with a principal address at 415 Main Street, Cambridge, MA 02142 ("BROAD") and the LICENSEE and is effective at the date the downloading is completed ("EFFECTIVE DATE"). +* +* WHEREAS, LICENSEE desires to license the PROGRAM, as defined hereinafter, and BROAD wishes to have this PROGRAM utilized in the public interest, subject only to the royalty-free, nonexclusive, nontransferable license rights of the United States Government pursuant to 48 CFR 52.227-14; and +* WHEREAS, LICENSEE desires to license the PROGRAM and BROAD desires to grant a license on the following terms and conditions. +* NOW, THEREFORE, in consideration of the promises and covenants made herein, the parties hereto agree as follows: +* +* 1. DEFINITIONS +* 1.1 PROGRAM shall mean copyright in the object code and source code known as GATK3 and related documentation, if any, as they exist on the EFFECTIVE DATE and can be downloaded from http://www.broadinstitute.org/gatk on the EFFECTIVE DATE. +* +* 2. LICENSE +* 2.1 Grant. Subject to the terms of this Agreement, BROAD hereby grants to LICENSEE, solely for academic non-commercial research purposes, a non-exclusive, non-transferable license to: (a) download, execute and display the PROGRAM and (b) create bug fixes and modify the PROGRAM. LICENSEE hereby automatically grants to BROAD a non-exclusive, royalty-free, irrevocable license to any LICENSEE bug fixes or modifications to the PROGRAM with unlimited rights to sublicense and/or distribute. LICENSEE agrees to provide any such modifications and bug fixes to BROAD promptly upon their creation. +* The LICENSEE may apply the PROGRAM in a pipeline to data owned by users other than the LICENSEE and provide these users the results of the PROGRAM provided LICENSEE does so for academic non-commercial purposes only. For clarification purposes, academic sponsored research is not a commercial use under the terms of this Agreement. +* 2.2 No Sublicensing or Additional Rights. LICENSEE shall not sublicense or distribute the PROGRAM, in whole or in part, without prior written permission from BROAD. LICENSEE shall ensure that all of its users agree to the terms of this Agreement. LICENSEE further agrees that it shall not put the PROGRAM on a network, server, or other similar technology that may be accessed by anyone other than the LICENSEE and its employees and users who have agreed to the terms of this agreement. +* 2.3 License Limitations. Nothing in this Agreement shall be construed to confer any rights upon LICENSEE by implication, estoppel, or otherwise to any computer software, trademark, intellectual property, or patent rights of BROAD, or of any other entity, except as expressly granted herein. LICENSEE agrees that the PROGRAM, in whole or part, shall not be used for any commercial purpose, including without limitation, as the basis of a commercial software or hardware product or to provide services. LICENSEE further agrees that the PROGRAM shall not be copied or otherwise adapted in order to circumvent the need for obtaining a license for use of the PROGRAM. +* +* 3. PHONE-HOME FEATURE +* LICENSEE expressly acknowledges that the PROGRAM contains an embedded automatic reporting system ("PHONE-HOME") which is enabled by default upon download. Unless LICENSEE requests disablement of PHONE-HOME, LICENSEE agrees that BROAD may collect limited information transmitted by PHONE-HOME regarding LICENSEE and its use of the PROGRAM. Such information shall include LICENSEE'S user identification, version number of the PROGRAM and tools being run, mode of analysis employed, and any error reports generated during run-time. Collection of such information is used by BROAD solely to monitor usage rates, fulfill reporting requirements to BROAD funding agencies, drive improvements to the PROGRAM, and facilitate adjustments to PROGRAM-related documentation. +* +* 4. OWNERSHIP OF INTELLECTUAL PROPERTY +* LICENSEE acknowledges that title to the PROGRAM shall remain with BROAD. The PROGRAM is marked with the following BROAD copyright notice and notice of attribution to contributors. LICENSEE shall retain such notice on all copies. LICENSEE agrees to include appropriate attribution if any results obtained from use of the PROGRAM are included in any publication. +* Copyright 2012-2016 Broad Institute, Inc. +* Notice of attribution: The GATK3 program was made available through the generosity of Medical and Population Genetics program at the Broad Institute, Inc. +* LICENSEE shall not use any trademark or trade name of BROAD, or any variation, adaptation, or abbreviation, of such marks or trade names, or any names of officers, faculty, students, employees, or agents of BROAD except as states above for attribution purposes. +* +* 5. INDEMNIFICATION +* LICENSEE shall indemnify, defend, and hold harmless BROAD, and their respective officers, faculty, students, employees, associated investigators and agents, and their respective successors, heirs and assigns, (Indemnitees), against any liability, damage, loss, or expense (including reasonable attorneys fees and expenses) incurred by or imposed upon any of the Indemnitees in connection with any claims, suits, actions, demands or judgments arising out of any theory of liability (including, without limitation, actions in the form of tort, warranty, or strict liability and regardless of whether such action has any factual basis) pursuant to any right or license granted under this Agreement. +* +* 6. NO REPRESENTATIONS OR WARRANTIES +* THE PROGRAM IS DELIVERED AS IS. BROAD MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE PROGRAM OR THE COPYRIGHT, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE. BROAD EXTENDS NO WARRANTIES OF ANY KIND AS TO PROGRAM CONFORMITY WITH WHATEVER USER MANUALS OR OTHER LITERATURE MAY BE ISSUED FROM TIME TO TIME. +* IN NO EVENT SHALL BROAD OR ITS RESPECTIVE DIRECTORS, OFFICERS, EMPLOYEES, AFFILIATED INVESTIGATORS AND AFFILIATES BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ECONOMIC DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER BROAD SHALL BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE FOREGOING. +* +* 7. ASSIGNMENT +* This Agreement is personal to LICENSEE and any rights or obligations assigned by LICENSEE without the prior written consent of BROAD shall be null and void. +* +* 8. MISCELLANEOUS +* 8.1 Export Control. LICENSEE gives assurance that it will comply with all United States export control laws and regulations controlling the export of the PROGRAM, including, without limitation, all Export Administration Regulations of the United States Department of Commerce. Among other things, these laws and regulations prohibit, or require a license for, the export of certain types of software to specified countries. +* 8.2 Termination. LICENSEE shall have the right to terminate this Agreement for any reason upon prior written notice to BROAD. If LICENSEE breaches any provision hereunder, and fails to cure such breach within thirty (30) days, BROAD may terminate this Agreement immediately. Upon termination, LICENSEE shall provide BROAD with written assurance that the original and all copies of the PROGRAM have been destroyed, except that, upon prior written authorization from BROAD, LICENSEE may retain a copy for archive purposes. +* 8.3 Survival. The following provisions shall survive the expiration or termination of this Agreement: Articles 1, 3, 4, 5 and Sections 2.2, 2.3, 7.3, and 7.4. +* 8.4 Notice. Any notices under this Agreement shall be in writing, shall specifically refer to this Agreement, and shall be sent by hand, recognized national overnight courier, confirmed facsimile transmission, confirmed electronic mail, or registered or certified mail, postage prepaid, return receipt requested. All notices under this Agreement shall be deemed effective upon receipt. +* 8.5 Amendment and Waiver; Entire Agreement. This Agreement may be amended, supplemented, or otherwise modified only by means of a written instrument signed by all parties. Any waiver of any rights or failure to act in a specific instance shall relate only to such instance and shall not be construed as an agreement to waive any rights or fail to act in any other instance, whether or not similar. This Agreement constitutes the entire agreement among the parties with respect to its subject matter and supersedes prior agreements or understandings between the parties relating to its subject matter. +* 8.6 Binding Effect; Headings. This Agreement shall be binding upon and inure to the benefit of the parties and their respective permitted successors and assigns. All headings are for convenience only and shall not affect the meaning of any provision of this Agreement. +* 8.7 Governing Law. This Agreement shall be construed, governed, interpreted and applied in accordance with the internal laws of the Commonwealth of Massachusetts, U.S.A., without regard to conflict of laws principles. +*/ + +package org.broadinstitute.gatk.tools.walkers.haplotypecaller; + +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeArguments; +import org.broadinstitute.gatk.utils.commandline.Argument; +import org.broadinstitute.gatk.utils.commandline.Hidden; + +/** + * Arguments for native PairHMM implementations + */ +public class PairHMMNativeArgumentCollection { + + @Hidden + @Argument(fullName = "nativePairHmmThreads", shortName = "threads", doc="How many threads should a native pairHMM implementation use", required = false) + private int pairHmmNativeThreads = 1; + + @Hidden + @Argument(fullName = "useDoublePrecision", shortName = "useDoublePrecision", doc="use double precision in the native pairHmm. " + + "This is slower but matches the java implementation better", required = false) + private boolean useDoublePrecision = false; + + public PairHMMNativeArguments getPairHMMArgs(){ + final PairHMMNativeArguments args = new PairHMMNativeArguments(); + args.maxNumberOfThreads = pairHmmNativeThreads; + args.useDoublePrecision = useDoublePrecision; + return args; + } + +} diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/DebugJNILoglessPairHMM.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/DebugJNILoglessPairHMM.java index 645039614..595b28212 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/DebugJNILoglessPairHMM.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/DebugJNILoglessPairHMM.java @@ -59,6 +59,7 @@ import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap; import org.broadinstitute.gatk.utils.genotyper.ReadLikelihoods; import org.broadinstitute.gatk.utils.haplotype.Haplotype; import org.broadinstitute.gatk.utils.sam.GATKSAMRecord; +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeArguments; import java.io.BufferedWriter; import java.io.File; @@ -92,11 +93,11 @@ public class DebugJNILoglessPairHMM extends LoglessPairHMM { protected HashMap filenameToWriter = new HashMap(); private JNILoglessPairHMM jniPairHMM = null; - public DebugJNILoglessPairHMM(final PairHMM.HMM_IMPLEMENTATION hmmType, PairHMM.HMM_SUB_IMPLEMENTATION pairHMMSub, final boolean alwaysLoadVectorLoglessPairHMMLib) { + public DebugJNILoglessPairHMM(final PairHMM.HMM_IMPLEMENTATION hmmType, PairHMMNativeArguments pairHmmNativeArgs) { super(); switch(hmmType) { case VECTOR_LOGLESS_CACHING: - jniPairHMM = new VectorLoglessPairHMM(pairHMMSub, alwaysLoadVectorLoglessPairHMMLib); + jniPairHMM = new VectorLoglessPairHMM(VectorLoglessPairHMM.Implementation.AVX, pairHmmNativeArgs); break; default: throw new UserException.BadArgumentValue("pairHMM","Specified JNIPairHMM implementation is unrecognized or incompatible with the HaplotypeCaller. Acceptable options are VECTOR_LOGLESS_CACHING"); diff --git a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM.java b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM.java index f535cf2ac..d096bbf33 100644 --- a/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM.java +++ b/protected/gatk-tools-protected/src/main/java/org/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM.java @@ -51,7 +51,13 @@ package org.broadinstitute.gatk.utils.pairhmm; +import com.intel.gkl.pairhmm.IntelPairHmm; +import com.intel.gkl.pairhmm.IntelPairHmmOMP; import org.apache.log4j.Logger; +import org.broadinstitute.gatk.nativebindings.pairhmm.HaplotypeDataHolder; +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeArguments; +import org.broadinstitute.gatk.nativebindings.pairhmm.PairHMMNativeBinding; +import org.broadinstitute.gatk.nativebindings.pairhmm.ReadDataHolder; import org.broadinstitute.gatk.utils.exceptions.UserException; import org.broadinstitute.gatk.utils.genotyper.ReadLikelihoods; import org.broadinstitute.gatk.utils.haplotype.Haplotype; @@ -71,100 +77,61 @@ import java.util.Map; */ public class VectorLoglessPairHMM extends JNILoglessPairHMM { + /** + * Implementation of PairHMM to use + */ + public enum Implementation + { + /* Use AVX acceleration */ + AVX, + /* Use AVX acceleration with mult-threading via OpenMP */ + OMP + } + protected final static Logger logger = Logger.getLogger(VectorLoglessPairHMM.class); - - //Used to copy references to byteArrays to JNI from reads - protected class JNIReadDataHolderClass { - public byte[] readBases = null; - public byte[] readQuals = null; - public byte[] insertionGOP = null; - public byte[] deletionGOP = null; - public byte[] overallGCP = null; - } - - //Used to copy references to byteArrays to JNI from haplotypes - protected class JNIHaplotypeDataHolderClass { - public byte[] haplotypeBases = null; - } - - /** - * Return 64-bit mask representing machine capabilities - * Bit 0 is LSB, bit 63 MSB - * Bit 0 represents sse4.1 availability - * Bit 1 represents sse4.2 availability - * Bit 2 represents AVX availability - */ - public native long jniGetMachineType(); - - /** - * Function to initialize the fields of JNIReadDataHolderClass and JNIHaplotypeDataHolderClass from JVM. - * C++ codegets FieldIDs for these classes once and re-uses these IDs for the remainder of the program. Field IDs do not - * change per JVM session - * - * @param readDataHolderClass class type of JNIReadDataHolderClass - * @param haplotypeDataHolderClass class type of JNIHaplotypeDataHolderClass - * @param mask a 64 bit integer identical to the one received from jniGetMachineType(). Users can disable usage of some hardware features by zeroing bits in the mask - */ - private native void jniInitializeClassFieldsAndMachineMask(Class readDataHolderClass, Class haplotypeDataHolderClass, long mask); - - private static Boolean isVectorLoglessPairHMMLibraryLoaded = false; + private final PairHMMNativeBinding pairHmm; //The constructor is called only once inside PairHMMLikelihoodCalculationEngine - public VectorLoglessPairHMM(final PairHMM.HMM_SUB_IMPLEMENTATION pairHMMSub, final boolean alwaysLoadVectorLoglessPairHMMLib) throws UserException.HardwareFeatureException { - super(); + public VectorLoglessPairHMM(Implementation implementation, PairHMMNativeArguments args) throws UserException.HardwareFeatureException { + final boolean isSupported; - synchronized (isVectorLoglessPairHMMLibraryLoaded) { - // Get the mask for the requested hardware sub-implementation - // If a specifically requested hardware feature can not be supported, throw an exception - long mask = pairHMMSub.getMask(); - throwIfHardwareFeatureNotSupported(mask, pairHMMSub); - - // Load the library and initialize the FieldIDs - // Load if not loaded or if the the always load flag is true - if (!isVectorLoglessPairHMMLibraryLoaded || alwaysLoadVectorLoglessPairHMMLib) { - try - { - //Try loading from Java's library path first - //Useful if someone builds his/her own library and wants to override the bundled - //implementation without modifying the Java code - System.loadLibrary("VectorLoglessPairHMM"); - logger.info("libVectorLoglessPairHMM found in JVM library path"); - } catch (UnsatisfiedLinkError ule) { - //Could not load from Java's library path - try unpacking from jar - try - { - logger.debug("libVectorLoglessPairHMM not found in JVM library path - trying to unpack from GATK jar file"); - loadLibraryFromJar("/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so"); - logger.info("libVectorLoglessPairHMM unpacked successfully from GATK jar file"); - } catch (IOException ioe) { - //Throw the UnsatisfiedLinkError to make it clear to the user what failed - throw ule; - } + switch (implementation) { + case AVX: + pairHmm = new IntelPairHmm(); + isSupported = pairHmm.load(null); + if (!isSupported) { + throw new UserException.HardwareFeatureException("Machine does not support AVX PairHMM."); } - logger.info("Using vectorized implementation of PairHMM"); - isVectorLoglessPairHMMLibraryLoaded = true; + logger.info("Using AVX-accelerated native PairHMM implementation"); + break; - //need to do this only once - jniInitializeClassFieldsAndMachineMask(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class, mask); - } + case OMP: + pairHmm = new IntelPairHmmOMP(); + isSupported = pairHmm.load(null); + if (!isSupported) { + throw new UserException.HardwareFeatureException("Machine does not support OpenMP AVX PairHMM."); + } + logger.info("Using OpenMP multi-threaded AVX-accelerated native PairHMM implementation"); + break; + + default: + throw new UserException.HardwareFeatureException("Unknown PairHMM implementation."); } - } - private native void jniInitializeHaplotypes(final int numHaplotypes, JNIHaplotypeDataHolderClass[] haplotypeDataArray); + // instantiate and initialize IntelPairHmm + pairHmm.initialize(args); + } //Hold the mapping between haplotype and index in the list of Haplotypes passed to initialize //Use this mapping in computeLikelihoods to find the likelihood value corresponding to a given Haplotype private HashMap haplotypeToHaplotypeListIdxMap = new HashMap<>(); - private JNIHaplotypeDataHolderClass[] mHaplotypeDataArray; + private HaplotypeDataHolder[] mHaplotypeDataArray; @Override public HashMap getHaplotypeToHaplotypeListIdxMap() { return haplotypeToHaplotypeListIdxMap; } - //Used to transfer data to JNI - //Since the haplotypes are the same for all calls to computeLikelihoods within a region, transfer the haplotypes only once to the JNI per region - /** * {@inheritDoc} */ @@ -172,54 +139,35 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { public void initialize(final List haplotypes, final Map> perSampleReadList, final int readMaxLength, final int haplotypeMaxLength) { int numHaplotypes = haplotypes.size(); - mHaplotypeDataArray = new JNIHaplotypeDataHolderClass[numHaplotypes]; + mHaplotypeDataArray = new HaplotypeDataHolder[numHaplotypes]; int idx = 0; haplotypeToHaplotypeListIdxMap.clear(); for (final Haplotype currHaplotype : haplotypes) { - mHaplotypeDataArray[idx] = new JNIHaplotypeDataHolderClass(); + mHaplotypeDataArray[idx] = new HaplotypeDataHolder(); mHaplotypeDataArray[idx].haplotypeBases = currHaplotype.getBases(); haplotypeToHaplotypeListIdxMap.put(currHaplotype, idx); ++idx; } - jniInitializeHaplotypes(numHaplotypes, mHaplotypeDataArray); } - /** - * Tell JNI to release arrays - really important if native code is directly accessing Java memory, if not - * accessing Java memory directly, still important to release memory from C++ - */ - private native void jniFinalizeRegion(); - - /** - * {@inheritDoc} - */ - @Override - public void finalizeRegion() - { - jniFinalizeRegion(); - } - - /** - * Real compute kernel - */ - private native void jniComputeLikelihoods(int numReads, int numHaplotypes, JNIReadDataHolderClass[] readDataArray, - JNIHaplotypeDataHolderClass[] haplotypeDataArray, double[] likelihoodArray, int maxNumThreadsToUse); - /** * {@inheritDoc} */ @Override public void computeLikelihoods(final ReadLikelihoods.Matrix likelihoods, final List processedReads, final Map gcp) { - if (processedReads.isEmpty()) + if (processedReads.isEmpty()) { return; - if (doProfiling) + } + if (doProfiling) { startTime = System.nanoTime(); + } int readListSize = processedReads.size(); int numHaplotypes = likelihoods.alleleCount(); - JNIReadDataHolderClass[] readDataArray = new JNIReadDataHolderClass[readListSize]; + + ReadDataHolder[] readDataArray = new ReadDataHolder[readListSize]; int idx = 0; for (GATKSAMRecord read : processedReads) { - readDataArray[idx] = new JNIReadDataHolderClass(); + readDataArray[idx] = new ReadDataHolder(); readDataArray[idx].readBases = read.getReadBases(); readDataArray[idx].readQuals = read.getBaseQualities(); readDataArray[idx].insertionGOP = read.getBaseInsertionQualities(); @@ -229,12 +177,13 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { } mLikelihoodArray = new double[readListSize * numHaplotypes]; //to store results - if (doProfiling) + if (doProfiling) { threadLocalSetupTimeDiff = (System.nanoTime() - startTime); + } //for(reads) // for(haplotypes) // compute_full_prob() - jniComputeLikelihoods(readListSize, numHaplotypes, readDataArray, mHaplotypeDataArray, mLikelihoodArray, 12); + pairHmm.computeLikelihoods(readDataArray, mHaplotypeDataArray, mLikelihoodArray); int readIdx = 0; for (int r = 0; r < readListSize; r++) { @@ -249,6 +198,7 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { } readIdx += numHaplotypes; } + if (doProfiling) { threadLocalPairHMMComputeTimeDiff = (System.nanoTime() - startTime); //synchronized(doProfiling) @@ -259,120 +209,11 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { } } - /** - * Print final profiling information from native code - */ - public native void jniClose(); - @Override public void close() { + pairHmm.done(); if (doProfiling) logger.info("Time spent in setup for JNI call : " + (pairHMMSetupTime * 1e-9)); super.close(); - jniClose(); - } - - //Copied from http://frommyplayground.com/how-to-load-native-jni-library-from-jar - - /** - * Loads library from current JAR archive - *

- * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting. - * Method uses String as filename because the pathname is "abstract", not system-dependent. - * - * @param path The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext - * @throws IOException If temporary file creation or read/write operation fails - * @throws IllegalArgumentException If source file (param path) does not exist - * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}). - */ - public static void loadLibraryFromJar(String path) throws IOException { - - if (!path.startsWith("/")) { - throw new IllegalArgumentException("The path to be absolute (start with '/')."); - } - - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - - // Split filename to prexif and suffix (extension) - String prefix = ""; - String suffix = null; - if (filename != null) { - parts = filename.split("\\.", 2); - prefix = parts[0]; - suffix = (parts.length > 1) ? "." + parts[parts.length - 1] : null; // Thanks, davs! :-) - } - - // Check if the filename is okay - if (filename == null || prefix.length() < 3) { - throw new IllegalArgumentException("The filename has to be at least 3 characters long."); - } - - // Prepare temporary file - File temp = File.createTempFile(prefix, suffix); - //System.out.println("Temp lib file "+temp.getAbsolutePath()); - temp.deleteOnExit(); - - if (!temp.exists()) { - throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist."); - } - - // Prepare buffer for data copying - byte[] buffer = new byte[1024]; - int readBytes; - - // Open and check input stream - InputStream is = VectorLoglessPairHMM.class.getResourceAsStream(path); - if (is == null) { - throw new FileNotFoundException("File " + path + " was not found inside JAR."); - } - - // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = new FileOutputStream(temp); - try { - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - } finally { - // If read/write fails, close streams safely before throwing an exception - os.close(); - is.close(); - } - - // Finally, load the library - System.load(temp.getAbsolutePath()); - } - - /** - * If the machine does not support the requested hardware feature, throw an exception - *

- * If requesting a specific hardware feature, check if the machine supports this feature. - * If it does not, throw an exception. - * - * @param mask a 64 bit integer identical to the one received from jniGetMachineType(). Users can disable usage of some hardware features by zeroing some bits in the mask. - * @param pairHMMSub the PairHMM machine dependent sub-implementation to use for genotype likelihood calculations - * @throws UserException.HardwareFeatureException if the hardware feature is not supported - */ - private void throwIfHardwareFeatureNotSupported(long mask, PairHMM.HMM_SUB_IMPLEMENTATION pairHMMSub) throws UserException.HardwareFeatureException - { - if ( pairHMMSub.getIsSpecificHardwareRequest() ) { - if ( !isHardwareFeatureSupported(mask) ) - throw new UserException.HardwareFeatureException("Machine does not support pairHMM hardware dependent sub-type = " + pairHMMSub); - } - } - - /** - * Check if the machine supports the requested hardware feature - *

- * Mask the bits for the hardware feature and check if they are set by the machine - * If the bits are set, the machine supports this feature - * - * @param mask a 64 bit integer identical to the one received from jniGetMachineType(). Users can disable usage of some hardware features by zeroing some bits in the mask. - * @return true of machine supports the requested hardware feature, false otherwise - */ - private boolean isHardwareFeatureSupported(long mask) - { - return (mask & jniGetMachineType()) != 0x0; } } diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2IntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2IntegrationTest.java index feedfeb35..ae5b9d47c 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2IntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/cancer/m2/MuTect2IntegrationTest.java @@ -71,7 +71,7 @@ public class MuTect2IntegrationTest extends WalkerTest { final static String DREAM3_FP_INTERVALS_FILE = privateTestDir + "m2_dream3.fp.intervals"; final String commandLine = - "-T MuTect2 --no_cmdline_in_header -dt NONE --disableDithering -alwaysloadVectorHMM -pairHMM LOGLESS_CACHING -ip 50 -R %s --dbsnp %s --cosmic %s --normal_panel %s -I:tumor %s -I:normal %s -L %s"; + "-T MuTect2 --no_cmdline_in_header -dt NONE --disableDithering -pairHMM LOGLESS_CACHING -ip 50 -R %s --dbsnp %s --cosmic %s --normal_panel %s -I:tumor %s -I:normal %s -L %s"; private void M2Test(String tumorBam, String normalBam, String intervals, String args, String md5) { final String base = String.format( @@ -90,7 +90,7 @@ public class MuTect2IntegrationTest extends WalkerTest { private void m2TumorOnlyTest(String tumorBam, String intervals, String args, String md5) { final String base = String.format( - "-T MuTect2 --no_cmdline_in_header -dt NONE --disableDithering -alwaysloadVectorHMM -pairHMM LOGLESS_CACHING -ip 50 -R %s --dbsnp %s --cosmic %s --normal_panel %s -I:tumor %s -L %s", + "-T MuTect2 --no_cmdline_in_header -dt NONE --disableDithering -pairHMM LOGLESS_CACHING -ip 50 -R %s --dbsnp %s --cosmic %s --normal_panel %s -I:tumor %s -L %s", hg19Reference, DBSNP, COSMIC, PON, tumorBam, intervals) + " -o %s "; diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCLikelihoodCalculationEnginesBenchmark.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCLikelihoodCalculationEnginesBenchmark.java index 7877ee59a..abc1136e7 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCLikelihoodCalculationEnginesBenchmark.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCLikelihoodCalculationEnginesBenchmark.java @@ -126,7 +126,7 @@ public class HCLikelihoodCalculationEnginesBenchmark extends SimpleBenchmark { public void timeLoglessPairHMM(final int reps) { for (int i = 0; i < reps; i++) { final PairHMMLikelihoodCalculationEngine engine = new PairHMMLikelihoodCalculationEngine((byte) 10, - PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING, PairHMM.HMM_SUB_IMPLEMENTATION.UNVECTORIZED, true, -3, true, PairHMMLikelihoodCalculationEngine.PCR_ERROR_MODEL.NONE); + PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING, null, -3, true, PairHMMLikelihoodCalculationEngine.PCR_ERROR_MODEL.NONE); engine.computeReadLikelihoods(dataSet.assemblyResultSet(), SampleListUtils.singletonList("anonymous"), Collections.singletonMap("anonymous", dataSet.readList())); } } diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java index e7c2c4030..72b7ba61b 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java @@ -61,22 +61,19 @@ import static org.broadinstitute.gatk.tools.walkers.haplotypecaller.HaplotypeCal public class HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest extends WalkerTest { - final static String HMM_SUB_IMPLEMENTATION = "UNVECTORIZED"; - final static String ALWAYS_LOAD_VECTOR_HMM = "-alwaysloadVectorHMM"; - private void HCTestComplexVariants(String bam, String args, String md5) { - final String base = String.format("-T HaplotypeCaller --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " -L 20:10028767-10028967 -L 20:10431524-10431924 -L 20:10723661-10724061 -L 20:10903555-10903955 --no_cmdline_in_header -o %s -minPruning 4"; + final String base = String.format("-T HaplotypeCaller --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " -L 20:10028767-10028967 -L 20:10431524-10431924 -L 20:10723661-10724061 -L 20:10903555-10903955 --no_cmdline_in_header -o %s -minPruning 4"; final WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(base + " " + args, Arrays.asList(md5)); executeTest("testHaplotypeCallerComplexVariants: args=" + args, spec); } @Test public void testHaplotypeCallerMultiSampleComplex1() { - HCTestComplexVariants(privateTestDir + "AFR.complex.variants.bam", "", "590428bdfe466159cb8e1637aaa4f47c"); + HCTestComplexVariants(privateTestDir + "AFR.complex.variants.bam", "", "93f89c04b4c74463f75da798cdcf5064"); } private void HCTestSymbolicVariants(String bam, String args, String md5) { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " -L 20:5947969-5948369 -L 20:61091236-61091636 --no_cmdline_in_header -o %s -minPruning 1"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " -L 20:5947969-5948369 -L 20:61091236-61091636 --no_cmdline_in_header -o %s -minPruning 1"; final WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(base + " " + args, Arrays.asList(md5)); executeTest("testHaplotypeCallerSymbolicVariants: args=" + args, spec); } @@ -88,7 +85,7 @@ public class HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest extends Wa } private void HCTestComplexGGA(String bam, String args, String md5) { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " --no_cmdline_in_header -o %s -minPruning 3 -gt_mode GENOTYPE_GIVEN_ALLELES -alleles " + validationDataLocation + "combined.phase1.chr20.raw.indels.sites.vcf"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " --no_cmdline_in_header -o %s -minPruning 3 -gt_mode GENOTYPE_GIVEN_ALLELES -alleles " + validationDataLocation + "combined.phase1.chr20.raw.indels.sites.vcf"; final WalkerTestSpec spec = new WalkerTestSpec(base + " " + args, Arrays.asList(md5)); executeTest("testHaplotypeCallerComplexGGA: args=" + args, spec); } @@ -102,11 +99,11 @@ public class HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest extends Wa @Test public void testHaplotypeCallerMultiSampleGGAMultiAllelic() { HCTestComplexGGA(NA12878_CHR20_BAM, "-L 20:133041-133161 -L 20:300207-300337", - "82b53501bc3254def885e09866377e7c"); + "d50cf0d1efd94227e930565a6d31de91"); } private void HCTestComplexConsensusMode(String bam, String args, String md5) { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " --no_cmdline_in_header -o %s -consensus -alleles " + validationDataLocation + "combined.phase1.chr20.raw.indels.sites.vcf -alleles " + validationDataLocation + "phase1.projectConsensus.chr20.raw.snps.vcf"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " --no_cmdline_in_header -o %s -consensus -alleles " + validationDataLocation + "combined.phase1.chr20.raw.indels.sites.vcf -alleles " + validationDataLocation + "phase1.projectConsensus.chr20.raw.snps.vcf"; final WalkerTestSpec spec = new WalkerTestSpec(base + " " + args, Arrays.asList(md5)); executeTest("testHaplotypeCallerComplexConsensusMode: args=" + args, spec); } @@ -114,7 +111,7 @@ public class HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest extends Wa @Test public void testHaplotypeCallerMultiSampleConsensusModeComplex() { HCTestComplexGGA(NA12878_CHR20_BAM, "-L 20:119673-119823 -L 20:121408-121538 -L 20:133041-133161 -L 20:300207-300337", - "47894766b0ce7d4aecd89e4938ac1c85"); + "390236e17de3465c8ba778041f1670ad"); } } diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerGVCFIntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerGVCFIntegrationTest.java index 5e16a2ec0..c9d5fbb18 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerGVCFIntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerGVCFIntegrationTest.java @@ -74,9 +74,6 @@ import java.util.zip.GZIPInputStream; public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { - final static String HMM_SUB_IMPLEMENTATION = "UNVECTORIZED"; - final static String ALWAYS_LOAD_VECTOR_HMM = "-alwaysloadVectorHMM"; - @DataProvider(name = "MyDataProviderHaploid") public Object[][] makeMyDataProviderHaploid() { List tests = new ArrayList<>(); @@ -164,8 +161,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(dataProvider = "MyDataProvider") public void testHCWithGVCF(String bam, ReferenceConfidenceMode mode, String intervals, String md5) { - final String commandLine = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final String name = "testHCWithGVCF bam=" + bam + " intervals= " + intervals + " gvcf= " + mode; final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList(md5)); executeTest(name, spec); @@ -176,8 +173,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(dataProvider = "MyDataProviderHaploid", enabled=true) public void testHCWithGVCFHaploid(final String bam, final ReferenceConfidenceMode mode, final String intervals, final String md5) { - final String commandLine = String.format("-T HaplotypeCaller -ploidy 1 --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller -ploidy 1 --disableDithering --pcr_indel_model NONE -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final String name = "testHCWithGVCFHaploid bam=" + bam + " intervals= " + intervals + " gvcf= " + mode; final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList(md5)); executeTest(name, spec); @@ -188,8 +185,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(dataProvider = "MyDataProviderTetraploid", enabled=true) public void testHCWithGVCFTetraploid(final String bam, final ReferenceConfidenceMode mode, final String intervals, final String md5) { - final String commandLine = String.format("-T HaplotypeCaller -ploidy 4 --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller -ploidy 4 --disableDithering --pcr_indel_model NONE -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final String name = "testHCWithGVCFTetraploid bam=" + bam + " intervals= " + intervals + " gvcf= " + mode; final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList(md5)); executeTest(name, spec); @@ -200,8 +197,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(dataProvider = "MyDataProviderManyploid", enabled=true) public void testHCWithGVCFManyploid(final String bam, final ReferenceConfidenceMode mode, final String intervals, final String md5) { - final String commandLine = String.format("-T HaplotypeCaller -ploidy 33 --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller -ploidy 33 --disableDithering --pcr_indel_model NONE -R %s -I %s %s -ERC %s --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, bam, intervals, mode, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final String name = "testHCWithGVCFManyploid bam=" + bam + " intervals= " + intervals + " gvcf= " + mode; final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList(md5)); executeTest(name, spec); @@ -209,8 +206,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testERCRegionWithNoCalledHaplotypes() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("")); spec.disableShadowBCF(); executeTest("testERCRegionWithNoCalledHaplotypes", spec); @@ -218,8 +215,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test() public void testMissingGVCFIndexException() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001"); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", 1, UserException.GVCFIndexException.class); spec.disableShadowBCF(); executeTest("testMissingGVCFIndexingStrategyException", spec); @@ -230,8 +227,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test() public void testGVCFIndexNoThrow() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000000-17000100"); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000000-17000100"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList(GATKVCFUtils.GVCF_EXT), Arrays.asList("")); spec.disableShadowBCF(); executeTest("testGVCFIndexNoThrow", spec); @@ -243,8 +240,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test() public void testGVCFGzIndexNoThrow() throws IOException { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000000-17000100"); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000000-17000100"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine, Arrays.asList("")); final File outputFile = createTempFile("testGVCFGzIndexNoThrow", "." + GATKVCFUtils.GVCF_GZ_EXT); spec.setOutputFileLocation(outputFile); @@ -255,8 +252,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test() public void testWrongParameterGVCFIndexException() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER + 1); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER + 1); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", 1, UserException.GVCFIndexException.class); spec.disableShadowBCF(); executeTest("testMissingGVCFIndexingStrategyException", spec); @@ -269,8 +266,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { if (GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE == GATKVCFIndexType.DYNAMIC_SEEK) type = GATKVCFIndexType.DYNAMIC_SIZE; - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", type, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF -variant_index_type %s -variant_index_parameter %d", + b37KGReference, privateTestDir + "noCallRefModel.bam", "20:17000001-18000001", type, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", 1, UserException.GVCFIndexException.class); spec.disableShadowBCF(); executeTest("testMissingGVCFIndexingStrategyException", spec); @@ -281,8 +278,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test() public void testWrongGVCFNonVariantRecordOrderBugFix() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, WRONG_GVCF_RECORD_ORDER_BUGFIX_BAM, WRONG_GVCF_RECORD_ORDER_BUGFIX_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, WRONG_GVCF_RECORD_ORDER_BUGFIX_BAM, WRONG_GVCF_RECORD_ORDER_BUGFIX_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("f70b7052dfeb065ee8c7d796f1a1f84a")); spec.disableShadowBCF(); executeTest("testMissingGVCFIndexingStrategyException", spec); @@ -298,8 +295,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testNoCallGVCFMissingPLsBugFix() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, NOCALL_GVCF_BUGFIX_BAM, NOCALL_GVCF_BUGFIX_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d", + b37KGReference, NOCALL_GVCF_BUGFIX_BAM, NOCALL_GVCF_BUGFIX_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("883fdc6c10fd7cbc1de375ed26ce5734")); spec.disableShadowBCF(); executeTest("testNoCallGVCFMissingPLsBugFix", spec); @@ -310,8 +307,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(enabled=true) public void testGeneralPloidyArrayIndexBug1Fix() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -ploidy 1 -maxAltAlleles 2 -isr INTERSECTION -L 1:23696115-23696189", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, GENERAL_PLOIDY_BUGFIX1_BAM, GENERAL_PLOIDY_BUGFIX1_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -ploidy 1 -maxAltAlleles 2 -isr INTERSECTION -L 1:23696115-23696189", + b37KGReference, GENERAL_PLOIDY_BUGFIX1_BAM, GENERAL_PLOIDY_BUGFIX1_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("")); spec.disableShadowBCF(); executeTest(" testGeneralPloidyArrayIndexBug1Fix", spec); @@ -322,8 +319,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { */ @Test(enabled=true) public void testGeneralPloidyArrayIndexBug2Fix() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -ploidy 2 -maxAltAlleles 2 -A DepthPerSampleHC -A StrandBiasBySample -L 1:38052860-38052937", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, GENERAL_PLOIDY_BUGFIX2_BAM, GENERAL_PLOIDY_BUGFIX2_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -ploidy 2 -maxAltAlleles 2 -A DepthPerSampleHC -A StrandBiasBySample -L 1:38052860-38052937", + b37KGReference, GENERAL_PLOIDY_BUGFIX2_BAM, GENERAL_PLOIDY_BUGFIX2_INTERVALS, GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("")); spec.disableShadowBCF(); executeTest(" testGeneralPloidyArrayIndexBug2Fix", spec); @@ -331,8 +328,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testAlleleSpecificAnnotations() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G Standard -G AS_Standard --disableDithering", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G Standard -G AS_Standard --disableDithering", + b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Collections.singletonList("7e74286e2c412855509ea5312ea0ec57")); spec.disableShadowBCF(); executeTest(" testAlleleSpecificAnnotations", spec); @@ -340,8 +337,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testASMQMateRankSumAnnotation() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -A AS_MQMateRankSumTest --disableDithering", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -A AS_MQMateRankSumTest --disableDithering", + b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Collections.singletonList("e0b9135f68eb0b65cb36721dd3f40f00")); spec.disableShadowBCF(); executeTest(" testASMQMateRankSumAnnotation", spec); @@ -349,8 +346,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testBetaTestingAnnotationGroup() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G BetaTesting --disableDithering", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G BetaTesting --disableDithering", + b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Collections.singletonList("81f1fcddfec262a8aaedb9ea37d89873")); spec.disableShadowBCF(); executeTest(" testASMQMateRankSumAnnotation", spec); @@ -358,8 +355,8 @@ public class HaplotypeCallerGVCFIntegrationTest extends WalkerTest { @Test public void testASInsertSizeRankSum() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G Standard -G AS_Standard --disableDithering -A AS_InsertSizeRankSum", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -ERC GVCF --no_cmdline_in_header -variant_index_type %s -variant_index_parameter %d -G Standard -G AS_Standard --disableDithering -A AS_InsertSizeRankSum", + b37KGReference, privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam", "20:10433000-10437000", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Collections.singletonList("96934396683234559827a77c9bb38e21")); spec.disableShadowBCF(); executeTest(" testASInsertSizeRankSum", spec); diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java index 59f77e3c9..0b76f2a1a 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java @@ -92,11 +92,9 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { final static String CEUTRIO_MT_TEST_BAM = privateTestDir + "CEUTrio.HiSeq.b37.MT.1_50.bam"; final static String INTERVALS_FILE = validationDataLocation + "NA12878.HiSeq.b37.chr20.10_11mb.test.intervals"; final static String GGA_INTERVALS_FILE = privateTestDir + "haplotype-caller-reduced-test-interval.list"; - final static String HMM_SUB_IMPLEMENTATION = "UNVECTORIZED"; - final static String ALWAYS_LOAD_VECTOR_HMM = "-alwaysloadVectorHMM"; private void HCTest(String bam, String args, String md5) throws IOException { - final String base = String.format("-T HaplotypeCaller --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE --maxReadsInRegionPerSample 1000 --minReadsPerAlignmentStart 5 --maxProbPropagationDistance 50 --activeProbabilityThreshold 0.002 -pairHMMSub %s %s -R %s -I %s -L %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam, INTERVALS_FILE) + " --no_cmdline_in_header -o %s -minPruning 3"; + final String base = String.format("-T HaplotypeCaller --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE --maxReadsInRegionPerSample 1000 --minReadsPerAlignmentStart 5 --maxProbPropagationDistance 50 --activeProbabilityThreshold 0.002 -R %s -I %s -L %s", REF, bam, INTERVALS_FILE) + " --no_cmdline_in_header -o %s -minPruning 3"; final WalkerTestSpec spec = new WalkerTestSpec(base + " " + args, Arrays.asList(md5)); final File outputVCF = executeTest("testHaplotypeCaller: args=" + args, spec).getFirst().get(0); Assert.assertFalse(FileUtils.readFileToString(outputVCF).contains(VCFConstants.MAPPING_QUALITY_ZERO_KEY)); @@ -229,7 +227,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { } private void HCTestIndelQualityScores(String bam, String args, String md5) { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " -L 20:10,005,000-10,025,000 --no_cmdline_in_header -o %s -minPruning 2"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " -L 20:10,005,000-10,025,000 --no_cmdline_in_header -o %s -minPruning 2"; final WalkerTestSpec spec = new WalkerTestSpec(base + " " + args, Arrays.asList(md5)); executeTest("testHaplotypeCallerIndelQualityScores: args=" + args, spec); } @@ -244,7 +242,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { final ReferenceSequenceFile fasta = new IndexedFastaSequenceFile(new File(b37KGReference)); final GenomeLocParser parser = new GenomeLocParser(fasta.getSequenceDictionary()); - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, bam) + " -L 20:10,001,603-10,001,642 -L 20:10,001,653-10,001,742 --no_cmdline_in_header -o %s"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, bam) + " -L 20:10,001,603-10,001,642 -L 20:10,001,653-10,001,742 --no_cmdline_in_header -o %s"; final WalkerTestSpec spec = new WalkerTestSpec(base + " " + args, Arrays.asList(md5)); for( final File vcf : executeTest("testHaplotypeCallerNearbySmallIntervals: args=" + args, spec).getFirst() ) { if( containsDuplicateRecord(vcf, parser) ) { @@ -282,14 +280,14 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { // any of the calls in that region because it is so messy. @Test public void HCTestProblematicReadsModifiedInActiveRegions() { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, privateTestDir + "haplotype-problem-4.bam") + " --no_cmdline_in_header -o %s -minPruning 3 -L 4:49139026-49139965"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, privateTestDir + "haplotype-problem-4.bam") + " --no_cmdline_in_header -o %s -minPruning 3 -L 4:49139026-49139965"; final WalkerTestSpec spec = new WalkerTestSpec(base, Arrays.asList("eb79b4c0bf9142c955f0a4501e9e6d8f")); executeTest("HCTestProblematicReadsModifiedInActiveRegions: ", spec); } @Test public void HCTestStructuralIndels() { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, privateTestDir + "AFR.structural.indels.bam") + " --no_cmdline_in_header -o %s -minPruning 6 -L 20:8187565-8187800 -L 20:18670537-18670730"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, privateTestDir + "AFR.structural.indels.bam") + " --no_cmdline_in_header -o %s -minPruning 6 -L 20:8187565-8187800 -L 20:18670537-18670730"; final WalkerTestSpec spec = new WalkerTestSpec(base, Arrays.asList("8bddb7f343302ed20bc549df4b82825a")); executeTest("HCTestStructuralIndels: ", spec); } @@ -298,14 +296,14 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { public void HCTestDoesNotFailOnBadRefBase() { // don't care about the output - just want to make sure it doesn't fail final String outputVCF = createTempFile("temp", ".vcf").getAbsolutePath(); - final String base = String.format("-T HaplotypeCaller --disableDithering -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, privateTestDir + "NA12878.readsOverBadBase.chr3.bam") + " --no_cmdline_in_header -o " + outputVCF + " -L 3:60830000-60840000 --minPruning 3 -stand_call_conf 2"; + final String base = String.format("-T HaplotypeCaller --disableDithering -R %s -I %s", REF, privateTestDir + "NA12878.readsOverBadBase.chr3.bam") + " --no_cmdline_in_header -o " + outputVCF + " -L 3:60830000-60840000 --minPruning 3 -stand_call_conf 2"; final WalkerTestSpec spec = new WalkerTestSpec(base, Collections.emptyList()); executeTest("HCTestDoesNotFailOnBadRefBase: ", spec); } @Test public void HCTestDanglingTailMergingForDeletions() throws IOException { - final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, NA12878_BAM) + " --no_cmdline_in_header -o %s -L 20:10130740-10130800 --allowNonUniqueKmersInRef"; + final String base = String.format("-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R %s -I %s", REF, NA12878_BAM) + " --no_cmdline_in_header -o %s -L 20:10130740-10130800 --allowNonUniqueKmersInRef"; final WalkerTestSpec spec = new WalkerTestSpec(base, 1, Arrays.asList("")); final File outputVCF = executeTest("HCTestDanglingTailMergingForDeletions", spec).getFirst().get(0); @@ -331,7 +329,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { public void testLeftAlignmentBamOutBugFix() throws FileNotFoundException { final String outputVCF = createTempFile("temp", ".vcf").getAbsolutePath(); final String md5BAMOut = "27e729df3b166c81792a62a5b57ef7b3"; - final String base = String.format("-T HaplotypeCaller -pairHMMSub %s %s -R %s -I %s", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, LEFT_ALIGNMENT_BAMOUT_TEST_INPUT) + final String base = String.format("-T HaplotypeCaller -R %s -I %s", REF, LEFT_ALIGNMENT_BAMOUT_TEST_INPUT) + " --no_cmdline_in_header -bamout %s -o " + outputVCF + " -L 1:11740000-11740700 --allowNonUniqueKmersInRef"; final WalkerTestSpec spec = new WalkerTestSpec(base, 1, Arrays.asList(md5BAMOut)); executeTest("LeftAlignmentBamOutBugFix", spec); @@ -347,7 +345,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestDBSNPAnnotationWGS() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,090,000-10,100,000 -D " + b37dbSNP132, 1, + "-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,090,000-10,100,000 -D " + b37dbSNP132, 1, Arrays.asList("fc71471b01f93bc531e3cf19cdf78b1f")); executeTest("HC calling with dbSNP ID annotation on WGS intervals", spec); } @@ -355,7 +353,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestDBSNPAnnotationWEx() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,100,000-11,000,000 -D " + b37dbSNP132 + "-T HaplotypeCaller --disableDithering --pcr_indel_model NONE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,100,000-11,000,000 -D " + b37dbSNP132 + " -L " + hg19Intervals + " -isr INTERSECTION", 1, Arrays.asList("bf8bb5d13b01facdf90ec24bfbf82faa")); executeTest("HC calling with dbSNP ID annotation on WEx intervals", spec); @@ -364,7 +362,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestDBSNPAnnotationWGSGraphBased() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,090,000-10,100,000 -D " + b37dbSNP132, 1, + "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,090,000-10,100,000 -D " + b37dbSNP132, 1, Arrays.asList("dbae51c7903e088b2e62cbada6ea2d50")); executeTest("HC calling with dbSNP ID annotation on WGS intervals", spec); } @@ -372,7 +370,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestDBSNPAnnotationWExGraphBased() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,000,000-11,000,000 -D " + b37dbSNP132 + "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_PCRFREE + " -o %s -L 20:10,000,000-11,000,000 -D " + b37dbSNP132 + " -L " + hg19Intervals + " -isr INTERSECTION", 1, Arrays.asList("2ffaf2e9ef293a6d5ce7c00be40edba7")); executeTest("HC calling with dbSNP ID annotation on WEx intervals", spec); @@ -381,7 +379,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestGraphBasedPCRFreePositiveLogLkFix() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + hg19Reference + " --no_cmdline_in_header -I " + NA12878_PCRFREE250_ADAPTER_TRIMMED + " -o %s -L 20:10,024,000-10,024,500 " + "-T HaplotypeCaller -likelihoodEngine GraphBased --disableDithering --pcr_indel_model NONE -R " + hg19Reference + " --no_cmdline_in_header -I " + NA12878_PCRFREE250_ADAPTER_TRIMMED + " -o %s -L 20:10,024,000-10,024,500 " , 1, Arrays.asList("")); executeTest("HCTestGraphBasedPCRFreePositiveLogLkFix", spec); @@ -396,24 +394,24 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void HCTestAggressivePcrIndelModelWGS() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller --disableDithering --pcr_indel_model AGGRESSIVE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_BAM + " -o %s -L 20:10,270,000-10,300,000", 1, - Arrays.asList("8c3ae4dc3d8af2aa8c71deaadb26cc14")); + "-T HaplotypeCaller --disableDithering --pcr_indel_model AGGRESSIVE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_BAM + " -o %s -L 20:10,270,000-10,300,000", 1, + Arrays.asList("7bd5bdfeb587a4c73f4c1cd8b850524f")); executeTest("HC calling with aggressive indel error modeling on WGS intervals", spec); } @Test public void HCTestConservativePcrIndelModelWGS() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller --disableDithering --pcr_indel_model CONSERVATIVE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_BAM + " -o %s -L 20:10,270,000-10,300,000", 1, - Arrays.asList("61aef3fe9d18eec1df526e99a8456115")); + "-T HaplotypeCaller --disableDithering --pcr_indel_model CONSERVATIVE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_BAM + " -o %s -L 20:10,270,000-10,300,000", 1, + Arrays.asList("5c1b487b0e7e1353a9a549a50c91d96f")); executeTest("HC calling with conservative indel error modeling on WGS intervals", spec); } @Test public void testNoSuchEdgeBugFix() { - final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub %s %s -R %s -I %s -L %s -dontTrimActiveRegions -ERC GVCF " + + final String commandLine = String.format("-T HaplotypeCaller --pcr_indel_model NONE -R %s -I %s -L %s -dontTrimActiveRegions -ERC GVCF " + "-likelihoodEngine GraphBased -variant_index_type %s -variant_index_parameter %d", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReferenceWithDecoy, privateTestDir + "graphbased_no_such_edge_bug.bam", privateTestDir + "graphbased_no_such_edge_bug.intervals.bed", + b37KGReferenceWithDecoy, privateTestDir + "graphbased_no_such_edge_bug.bam", privateTestDir + "graphbased_no_such_edge_bug.intervals.bed", GATKVCFUtils.DEFAULT_GVCF_INDEX_TYPE, GATKVCFUtils.DEFAULT_GVCF_INDEX_PARAMETER); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("")); spec.disableShadowBCF(); @@ -432,8 +430,8 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { // This test takes longer than 15 secs ... ~ 25-35 , @Test public void testLackSensitivityDueToBadHaplotypeSelectionFix() { - final String commandLine = String.format("-T HaplotypeCaller -pairHMMSub %s %s -R %s -I %s -L %s --no_cmdline_in_header --maxNumHaplotypesInPopulation 16", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReferenceWithDecoy, privateTestDir + "hc-lack-sensitivity.bam", privateTestDir + "hc-lack-sensitivity.interval_list"); + final String commandLine = String.format("-T HaplotypeCaller -R %s -I %s -L %s --no_cmdline_in_header --maxNumHaplotypesInPopulation 16", + b37KGReferenceWithDecoy, privateTestDir + "hc-lack-sensitivity.bam", privateTestDir + "hc-lack-sensitivity.interval_list"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("5087a8855b3ee9ea1091367674783462")); spec.disableShadowBCF(); executeTest("testLackSensitivityDueToBadHaplotypeSelectionFix", spec); @@ -441,8 +439,8 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { @Test public void testMissingKeyAlternativeHaplotypesBugFix() { - final String commandLine = String.format("-T HaplotypeCaller -pairHMMSub %s %s -R %s -I %s -L %s --no_cmdline_in_header ", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, b37KGReferenceWithDecoy, privateTestDir + "lost-alt-key-hap.bam", privateTestDir + "lost-alt-key-hap.interval_list"); + final String commandLine = String.format("-T HaplotypeCaller -R %s -I %s -L %s --no_cmdline_in_header ", + b37KGReferenceWithDecoy, privateTestDir + "lost-alt-key-hap.bam", privateTestDir + "lost-alt-key-hap.interval_list"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine + " -o %s", Arrays.asList("e6d8c32585906122a6407cb40261d00d")); spec.disableShadowBCF(); executeTest("testMissingKeyAlternativeHaplotypesBugFix", spec); @@ -455,9 +453,9 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { final String TEST_BAM = privateTestDir + "sw_epsilon_test.bam"; final String REFERENCE = b37KGReference; final String DBSNP = b37dbSNP138; - final String commandLineWithoutInterval = String.format("-T HaplotypeCaller -pairHMMSub %s %s -I %s -R %s -D %s " + final String commandLineWithoutInterval = String.format("-T HaplotypeCaller -I %s -R %s -D %s " + "-variant_index_type LINEAR -variant_index_parameter 128000 --no_cmdline_in_header " - + "-stand_call_conf 10.0", HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, TEST_BAM, REFERENCE, DBSNP); + + "-stand_call_conf 10.0", TEST_BAM, REFERENCE, DBSNP); final String commandLineShortInterval = commandLineWithoutInterval + " -L " + SHORT_INTERVAL; final String commandLineLongInterval = commandLineWithoutInterval + " -L " + LONG_INTERVAL; @@ -480,8 +478,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { " -T HaplotypeCaller" + " --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE --maxReadsInRegionPerSample 1000 " + " --minReadsPerAlignmentStart 5 --maxProbPropagationDistance 50 --activeProbabilityThreshold 0.002 " + - " --no_cmdline_in_header -minPruning 3 -pairHMM VECTOR_LOGLESS_CACHING -pairHMMSub TEST_BEYOND_CAPABILITIES " + - ALWAYS_LOAD_VECTOR_HMM + + " --no_cmdline_in_header -minPruning 3 -pairHMM VECTOR_LOGLESS_CACHING " + " -R " + REF + " -I " + NA12878_BAM + " -L " + INTERVALS_FILE + @@ -496,7 +493,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { " -T HaplotypeCaller" + " --contamination_fraction_to_filter 0.05 --disableDithering --pcr_indel_model NONE --maxReadsInRegionPerSample 1000 " + " --minReadsPerAlignmentStart 5 --maxProbPropagationDistance 50 --activeProbabilityThreshold 0.002 " + - " --no_cmdline_in_header -minPruning 3 -pairHMM VECTOR_LOGLESS_CACHING -pairHMMSub " + HMM_SUB_IMPLEMENTATION + + " --no_cmdline_in_header -minPruning 3 -pairHMM VECTOR_LOGLESS_CACHING " + " -dcov 50" + " -R " + REF + " -I " + NA12878_BAM + @@ -570,8 +567,8 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { final String md5 = "d41d8cd98f00b204e9800998ecf8427e"; final String commandLine = String.format("-T HaplotypeCaller --contamination_fraction_to_filter 0.05 --disableDithering --maxReadsInRegionPerSample 1000" + " --minReadsPerAlignmentStart 5 --maxProbPropagationDistance 50 --activeProbabilityThreshold 0.002 --pcr_indel_model NONE" + - " -pairHMMSub %s %s -R %s -I %s -L %s -minPruning 3 --no_cmdline_in_header", - HMM_SUB_IMPLEMENTATION, ALWAYS_LOAD_VECTOR_HMM, REF, NA12878_BAM, "20:10000000-10100000"); + " -R %s -I %s -L %s -minPruning 3 --no_cmdline_in_header", + REF, NA12878_BAM, "20:10000000-10100000"); final WalkerTestSpec spec = new WalkerTestSpec(commandLine, Arrays.asList(md5)); final File outputFile = createTempFile("testBCFInFileNameGivesVCF", ".bcftoolsFile.vcf"); spec.setOutputFileLocation(outputFile); diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerModesIntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerModesIntegrationTest.java index 3cc756cdb..a62ee2427 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerModesIntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerModesIntegrationTest.java @@ -70,8 +70,6 @@ public class HaplotypeCallerModesIntegrationTest extends WalkerTest { // // -------------------------------------------------------------------------------------------------------------- - final static String HMM_SUB_IMPLEMENTATION = "UNVECTORIZED"; - final static String ALWAYS_LOAD_VECTOR_HMM = "-alwaysloadVectorHMM"; @Test public void HCTestBamWriterCalledHaplotypes() { @@ -86,7 +84,7 @@ public class HaplotypeCallerModesIntegrationTest extends WalkerTest { public void HCTestBamWriter(final HaplotypeBAMWriter.Type type, final String md5) { final String outputVCF = createTempFile("temp", ".vcf").getAbsolutePath(); WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( - "-T HaplotypeCaller -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + + "-T HaplotypeCaller -R " + b37KGReference + " --no_cmdline_in_header -I " + privateTestDir + "PCRFree.2x250.Illumina.20_10_11.bam -o " + outputVCF + " -bamout %s -L 20:10,000,000-10,010,000 -bamWriterType " + type, 1, Arrays.asList(md5)); diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerParallelIntegrationTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerParallelIntegrationTest.java index 6cc7f63a8..be96a7b39 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerParallelIntegrationTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HaplotypeCallerParallelIntegrationTest.java @@ -61,8 +61,6 @@ import java.util.List; public class HaplotypeCallerParallelIntegrationTest extends WalkerTest { - final static String HMM_SUB_IMPLEMENTATION = "UNVECTORIZED"; - final static String ALWAYS_LOAD_VECTOR_HMM = "-alwaysloadVectorHMM"; @DataProvider(name = "NCTDataProvider") public Object[][] makeNCTDataProvider() { @@ -78,7 +76,7 @@ public class HaplotypeCallerParallelIntegrationTest extends WalkerTest { @Test(dataProvider = "NCTDataProvider") public void testHCNCT(final int nct, final String md5) { WalkerTestSpec spec = new WalkerTestSpec( - "-T HaplotypeCaller --pcr_indel_model NONE -pairHMMSub " + HMM_SUB_IMPLEMENTATION + " " + ALWAYS_LOAD_VECTOR_HMM + " -R " + b37KGReference + " --no_cmdline_in_header -I " + "-T HaplotypeCaller --pcr_indel_model NONE -R " + b37KGReference + " --no_cmdline_in_header -I " + privateTestDir + "PCRFree.2x250.Illumina.20_10_11.bam -o %s " + " -L 20:10,000,000-10,100,000 -G none -A none -contamination 0.0 -nct " + nct, 1, Arrays.asList(md5)); diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngineUnitTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngineUnitTest.java index 1b055c9d4..72b8ff01a 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngineUnitTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/PairHMMLikelihoodCalculationEngineUnitTest.java @@ -138,7 +138,7 @@ public class PairHMMLikelihoodCalculationEngineUnitTest extends BaseTest { public void createPcrErrorModelTest(final String repeat, final int repeatLength) { final PairHMMLikelihoodCalculationEngine engine = new PairHMMLikelihoodCalculationEngine((byte)0, - PairHMM.HMM_IMPLEMENTATION.ORIGINAL, PairHMM.HMM_SUB_IMPLEMENTATION.UNVECTORIZED, false, 0.0, true, + PairHMM.HMM_IMPLEMENTATION.ORIGINAL, null, 0.0, true, PairHMMLikelihoodCalculationEngine.PCR_ERROR_MODEL.CONSERVATIVE); final String readString = Utils.dupString(repeat, repeatLength); diff --git a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/ReadThreadingLikelihoodCalculationEngineUnitTest.java b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/ReadThreadingLikelihoodCalculationEngineUnitTest.java index 97908682e..861273568 100644 --- a/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/ReadThreadingLikelihoodCalculationEngineUnitTest.java +++ b/protected/gatk-tools-protected/src/test/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/ReadThreadingLikelihoodCalculationEngineUnitTest.java @@ -95,7 +95,7 @@ public class ReadThreadingLikelihoodCalculationEngineUnitTest extends ActiveRegi //final PairHMMLikelihoodCalculationEngine fullPairHMM = new PairHMMLikelihoodCalculationEngine((byte)10, false, // PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING, -3); final PairHMMLikelihoodCalculationEngine fullPairHMM = new PairHMMLikelihoodCalculationEngine((byte)10, - PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING, PairHMM.HMM_SUB_IMPLEMENTATION.UNVECTORIZED, true, Double.NEGATIVE_INFINITY, + PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING, null, Double.NEGATIVE_INFINITY, true, PairHMMLikelihoodCalculationEngine.PCR_ERROR_MODEL.NONE); // When using likelihoods it should be around 0.05 since diff --git a/public/VectorPairHMM/README.md b/public/VectorPairHMM/README.md deleted file mode 100644 index ad4005526..000000000 --- a/public/VectorPairHMM/README.md +++ /dev/null @@ -1,72 +0,0 @@ -Implementation overview: -Created a new Java class called VectorLoglessPairHMM which extends LoglessPairHMM and -overrides functions from both LoglessPairHMM and PairHMM. -1. Constructor: Call base class constructors. Then, load the native library located in this -directory and call an init function (with suffix 'jniInitializeClassFieldsAndMachineMask') in the -library to determine fields ids for the members of classes JNIReadDataHolder and -JNIHaplotypeDataHolders. The native code stores the field ids (struct offsets) for the classes and -re-uses them for subsequent computations. Optionally, the user can disable the vector -implementation, by using the 'mask' argument (see comments for a more detailed explanation). -2. When the library is loaded, it invokes the constructor of the class LoadTimeInitializer (because -a global variable g_load_time_initializer is declared in the library). This constructor -(LoadTimeInitializer.cc) can be used to perform various initializations. Currently, it initializes -two global function pointers to point to the function implementation that is supported on the -machine (AVX/SSE/un-vectorized) on which the program is being run. The two pointers are for float -and double respectively. The global function pointers are declared in utils.cc and are assigned in -the function initialize_function_pointers() defined in utils.cc and invoked from the constructor of -LoadTimeInitializer. -Other initializations in LoadTimeInitializer: -* ConvertChar::init - sets some masks for the vector implementation -* FTZ for performance -* stat counters = 0 -* debug structs (which are never used in non-debug mode) -This initialization is done only once for the whole program. -3. initialize(): To initialize the region for PairHMM. Pass haplotype bases to native code through -the JNIHaplotypeDataHolder class. Since the haplotype list is common across multiple samples in -computeReadLikelihoods(), we can pass the haplotype bases to the native code once and re-use across -multiple samples. -4. computeLikelihoods(): Copies array references for readBases/quals etc to array of -JNIReadDataHolder objects. Invokes the JNI function to perform the computation and updates the -likelihoodMap. -The JNI function copies the byte array references into an array of testcase structs and invokes the -compute_full_prob function through the function pointers initialized earlier. -The primary native function called is -Java_org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods. It uses -standard JNI calls to get and return data from/to the Java class VectorLoglessPairHMM. 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). -Note: OpenMP has been disabled for now - insufficient #testcases per call to computeLikelihoods() to -justify multi-threading. -5. finalizeRegion(): Releases the haplotype arrays initialized in step 3 - should be called at the -end of every region (line 351 in PairHMMLikelihoodCalculationEngine). - -Note: Debug code has been moved to a separate class DebugJNILoglessPairHMM.java. - -Compiling: -The native library (called libVectorLoglessPairHMM.so) can be compiled with icc (Intel C compiler) -or gcc versions >= 4.8.1 that support AVX intrinsics. By default, the make process tries to invoke -icc. To use gcc, edit the file 'pom.xml' (in this directory) and enable the environment variables -USE_GCC,C_COMPILER and CPP_COMPILER (edit and uncomment lines 60-62). -Using Maven: -Type 'mvn install' in this directory - this will build the library (by invoking 'make') and copy the -native library to the directory -${sting-utils.basedir}/src/main/resources/org/broadinstitute/sting/utils/pairhmm -The GATK maven build process (when run) will bundle the library into the StingUtils jar file from -the copied directory. -Simple build: -cd src/main/c++ -make - -Running: -The default implementation of PairHMM is now VECTOR_LOGLESS_CACHING in HaplotypeCaller.java. To use -the Java version, use the command line argument "--pair_hmm_implementation LOGLESS_CACHING". (see -run.sh in src/main/c++). -The native library is bundled with the StingUtils jar file. When HaplotypeCaller is invoked, then -the library is unpacked from the jar file, copied to the /tmp directory (with a unique id) and -loaded by the Java class VectorLoglessPairHMM in the constructor (if it has not been loaded -already). -The default library can be overridden by using the -Djava.library.path argument (see -src/main/c++/run.sh for an example) for the JVM to pass the path to the library. If the library -libVectorLoglessPairHMM.so can be found in java.library.path, then it is loaded and the 'packed' -library is not used. diff --git a/public/VectorPairHMM/pom.xml b/public/VectorPairHMM/pom.xml deleted file mode 100644 index 9ae0b3260..000000000 --- a/public/VectorPairHMM/pom.xml +++ /dev/null @@ -1,122 +0,0 @@ - - - 4.0.0 - - - org.broadinstitute.gatk - gatk-root - 3.8-SNAPSHOT - ../../public/gatk-root - - - VectorPairHMM - pom - Vectorized PairHMM native libraries - - Builds a GNU/Linux x86_64 library of VectorPairHMM using icc (Intel C++ compiler). During install, copies it into gatk-utils. Neither tested nor expected to work on any other platform. - - - UTF-8 - ${sourceEncoding} - ${sourceEncoding} - ${project.basedir}/../.. - ${gatk.basedir}/public/gatk-utils - - ${gatk-utils.basedir}/src/main/resources/org/broadinstitute/gatk/utils/pairhmm - - - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - - display-info - - validate - - - - - - - org.codehaus.mojo - exec-maven-plugin - - - - exec - - compile - - make - src/main/c++ - - ${java.home} - - - - ${project.build.directory} - - - - - - - - - org.apache.maven.plugins - maven-install-plugin - - true - - - - - - org.apache.maven.plugins - maven-resources-plugin - - - default-install - - copy-resources - - install - - ${pairhmm.resources.directory} - - - ${project.build.directory} - - **/* - - - - - - - - - - - com.google.code.sortpom - maven-sortpom-plugin - - false - custom_1 - \n - ${sourceEncoding} - true - scope - 4 - false - - - - - diff --git a/public/VectorPairHMM/src/main/c++/.gitignore b/public/VectorPairHMM/src/main/c++/.gitignore deleted file mode 100644 index d791ffd80..000000000 --- a/public/VectorPairHMM/src/main/c++/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -.svn -*.o -*.so -tests -.deps -hmm_Mohammad -pairhmm-template-main -*.swp -*.class -checker -reformat -subdir_checkout.sh -avx/ -sse/ -triplicate.sh - diff --git a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc deleted file mode 100644 index f6cdbab4b..000000000 --- a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc +++ /dev/null @@ -1,205 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include "utils.h" -#include "LoadTimeInitializer.h" -using namespace std; -char* LoadTimeInitializerStatsNames[] = -{ - "num_regions", - "num_reads", - "num_haplotypes", - "num_testcases", - "num_double_invocations", - "haplotype_length", - "readlength", - "product_read_length_haplotype_length", - "dummy" -}; - -LoadTimeInitializer g_load_time_initializer; - -LoadTimeInitializer::LoadTimeInitializer() //will be called when library is loaded -{ -#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__INTEL_COMPILER) - //compiles only with gcc >= 4.8 - __builtin_cpu_init(); -#endif - ConvertChar::init(); -#ifndef DISABLE_FTZ - //Very important to get good performance on Intel processors - //Function: enabling FTZ converts denormals to 0 in hardware - //Denormals cause microcode to insert uops into the core causing big slowdown - _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); - //cout << "FTZ enabled - may decrease accuracy if denormal numbers encountered\n"; -#else - cout << "FTZ is not set - may slow down performance if denormal numbers encountered\n"; -#endif - //Profiling: times for compute and transfer (either bytes copied or pointers copied) - m_compute_time = 0; - m_data_transfer_time = 0; - m_bytes_copied = 0; - - //Initialize profiling counters - for(unsigned i=0;i::initializeStaticMembers(); - Context::initializeStaticMembers(); - - cout.flush(); -} - -void LoadTimeInitializer::print_profiling() -{ - double mean = 0; - double variance = 0; - uint64_t denominator = 1; - cout << "Time spent in compute_testcases "< C++) "<::iterator mI = m_filename_to_fptr.find(filename); - ofstream* fptr = 0; - if(mI == m_filename_to_fptr.end()) - { - m_filename_to_fptr[filename] = new ofstream(); - fptr = m_filename_to_fptr[filename]; - //File never seen before - if(m_written_files_set.find(filename) == m_written_files_set.end()) - { - to_append = false; - m_written_files_set.insert(filename); - } - fptr->open(filename.c_str(), to_append ? ios::app : ios::out); - assert(fptr->is_open()); - } - else - fptr = (*mI).second; - //ofstream fptr; - //fptr.open(filename.c_str(), to_append ? ofstream::app : ofstream::out); - (*fptr) << s; - if(add_newline) - (*fptr) << "\n"; - //fptr.close(); -} -void LoadTimeInitializer::debug_close() -{ - for(map::iterator mB = m_filename_to_fptr.begin(), mE = m_filename_to_fptr.end(); - mB != mE;mB++) - { - (*mB).second->close(); - delete (*mB).second; - } - m_filename_to_fptr.clear(); -} - -void LoadTimeInitializer::dump_sandbox(testcase& tc, unsigned tc_idx, unsigned numReads, unsigned numHaplotypes) -{ - unsigned haplotypeLength = tc.haplen; - unsigned readLength = tc.rslen; - ofstream& dumpFptr = m_sandbox_fptr; - for(unsigned k=0;k -/*#include "template.h"*/ - -enum LoadTimeInitializerStatsEnum -{ - NUM_REGIONS_IDX=0, - NUM_READS_IDX, - NUM_HAPLOTYPES_IDX, - NUM_TESTCASES_IDX, - NUM_DOUBLE_INVOCATIONS_IDX, - HAPLOTYPE_LENGTH_IDX, - READ_LENGTH_IDX, - PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX, - TOTAL_NUMBER_STATS -}; -extern char* LoadTimeInitializerStatsNames[]; - -class LoadTimeInitializer -{ - public: - LoadTimeInitializer(); //will be called when library is loaded - void print_profiling(); - void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline=true); - void debug_close(); - - void dump_sandbox(testcase& tc, unsigned tc_idx, unsigned numReads, unsigned numHaplotypes); - void open_sandbox() { m_sandbox_fptr.open("sandbox.txt", std::ios::app); } - void close_sandbox() { m_sandbox_fptr.close(); } - - jfieldID m_readBasesFID; - jfieldID m_readQualsFID; - jfieldID m_insertionGOPFID; - jfieldID m_deletionGOPFID; - jfieldID m_overallGCPFID; - jfieldID m_haplotypeBasesFID; - //profiling - update stats - void update_stat(LoadTimeInitializerStatsEnum stat_idx, uint64_t value); - //timing in nanoseconds - uint64_t m_compute_time; - uint64_t m_data_transfer_time; - //bytes copied - uint64_t m_bytes_copied; - private: - std::map m_filename_to_fptr; - std::set m_written_files_set; - std::ofstream m_sandbox_fptr; - //used to compute various stats - uint64_t m_sum_stats[TOTAL_NUMBER_STATS]; - double m_sum_square_stats[TOTAL_NUMBER_STATS]; - uint64_t m_min_stats[TOTAL_NUMBER_STATS]; - uint64_t m_max_stats[TOTAL_NUMBER_STATS]; -}; -extern LoadTimeInitializer g_load_time_initializer; - -#define SIZE_PER_TESTCASE 6*10000 -#define SIZE_PER_BUFFER 10000 - -#endif diff --git a/public/VectorPairHMM/src/main/c++/Makefile b/public/VectorPairHMM/src/main/c++/Makefile deleted file mode 100644 index 0fae1e815..000000000 --- a/public/VectorPairHMM/src/main/c++/Makefile +++ /dev/null @@ -1,126 +0,0 @@ -#Copyright (c) 2012 The Broad Institute - -#Permission is hereby granted, free of charge, to any person -#obtaining a copy of this software and associated documentation -#files (the "Software"), to deal in the Software without -#restriction, including without limitation the rights to use, -#copy, modify, merge, publish, distribute, sublicense, and/or sell -#copies of the Software, and to permit persons to whom the -#Software is furnished to do so, subject to the following -#conditions: - -#The above copyright notice and this permission notice shall be -#included in all copies or substantial portions of the Software. - -#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -#OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -#HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -#THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - - -#OMPCFLAGS=-fopenmp -#OMPLFLAGS=-fopenmp #-openmp-link static - -#CFLAGS=-O2 -std=c++11 -W -Wall -march=corei7-avx -Wa,-q -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas -#CFLAGS=-O2 -W -Wall -march=corei7 -mfpmath=sse -msse4.2 -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas - -JRE_HOME?=/opt/jdk1.7.0_25/jre -JNI_COMPILATION_FLAGS=-D_REENTRANT -fPIC -I${JRE_HOME}/../include -I${JRE_HOME}/../include/linux - -#COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -W -Wall -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas -COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -Wall $(OMPCFLAGS) -Wno-unknown-pragmas -Wno-write-strings -Wno-unused-variable -Wno-unused-but-set-variable -ifdef DISABLE_FTZ - COMMON_COMPILATION_FLAGS+=-DDISABLE_FTZ -endif - -ifdef USE_GCC - C_COMPILER?=gcc - CPP_COMPILER?=g++ - AVX_FLAGS=-mavx - SSE41_FLAGS=-msse4.1 - COMMON_COMPILATION_FLAGS+=-Wno-char-subscripts -else - C_COMPILER?=icc - CPP_COMPILER?=icc - AVX_FLAGS=-xAVX - SSE41_FLAGS=-xSSE4.1 - LIBFLAGS=-static-intel - ifdef DISABLE_FTZ - COMMON_COMPILATION_FLAGS+=-no-ftz - endif -endif - -LDFLAGS=-lm -lrt $(OMPLDFLAGS) - -PAPI_DIR=/home/karthikg/softwares/papi-5.3.0 -ifdef USE_PAPI - ifeq ($(USE_PAPI),1) - COMMON_COMPILATION_FLAGS+=-I$(PAPI_DIR)/include -DUSE_PAPI - LDFLAGS+=-L$(PAPI_DIR)/lib -lpapi - endif -endif - -BIN=libVectorLoglessPairHMM.so pairhmm-template-main checker -#BIN=checker - -DEPDIR=.deps -DF=$(DEPDIR)/$(*).d - -#Common across libJNI and sandbox -COMMON_SOURCES=utils.cc avx_function_instantiations.cc baseline.cc sse_function_instantiations.cc LoadTimeInitializer.cc -#Part of libJNI -LIBSOURCES=org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc Sandbox.cc $(COMMON_SOURCES) -SOURCES=$(LIBSOURCES) pairhmm-template-main.cc pairhmm-1-base.cc -LIBOBJECTS=$(LIBSOURCES:.cc=.o) -COMMON_OBJECTS=$(COMMON_SOURCES:.cc=.o) - - -#No vectorization for these files -NO_VECTOR_SOURCES=org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc pairhmm-template-main.cc pairhmm-1-base.cc utils.cc baseline.cc LoadTimeInitializer.cc Sandbox.cc -#Use -xAVX for these files -AVX_SOURCES=avx_function_instantiations.cc -#Use -xSSE4.2 for these files -SSE_SOURCES=sse_function_instantiations.cc - -NO_VECTOR_OBJECTS=$(NO_VECTOR_SOURCES:.cc=.o) -AVX_OBJECTS=$(AVX_SOURCES:.cc=.o) -SSE_OBJECTS=$(SSE_SOURCES:.cc=.o) -$(NO_VECTOR_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) -$(AVX_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(AVX_FLAGS) -$(SSE_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(SSE41_FLAGS) -OBJECTS=$(NO_VECTOR_OBJECTS) $(AVX_OBJECTS) $(SSE_OBJECTS) - -all: $(BIN) Sandbox.class copied_lib - --include $(addprefix $(DEPDIR)/,$(SOURCES:.cc=.d)) - -checker: pairhmm-1-base.o $(COMMON_OBJECTS) - $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) - -pairhmm-template-main: pairhmm-template-main.o $(COMMON_OBJECTS) - $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) - -libVectorLoglessPairHMM.so: $(LIBOBJECTS) - $(CPP_COMPILER) $(OMPLFLAGS) -shared $(LIBFLAGS) -o $@ $(LIBOBJECTS) ${LDFLAGS} - - -$(OBJECTS): %.o: %.cc - @mkdir -p $(DEPDIR) - $(CPP_COMPILER) -c -MMD -MF $(DF) $(CXXFLAGS) $(OUTPUT_OPTION) $< - -Sandbox.class: Sandbox.java - javac Sandbox.java - -copied_lib: libVectorLoglessPairHMM.so -ifdef OUTPUT_DIR - mkdir -p $(OUTPUT_DIR) - rsync -a libVectorLoglessPairHMM.so $(OUTPUT_DIR)/ -endif - -clean: - rm -rf $(BIN) *.o $(DEPDIR) *.class diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.cc b/public/VectorPairHMM/src/main/c++/Sandbox.cc deleted file mode 100644 index a4c2b73ec..000000000 --- a/public/VectorPairHMM/src/main/c++/Sandbox.cc +++ /dev/null @@ -1,106 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include "Sandbox.h" -#include "org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h" -#include "utils.h" -#include "jni_common.h" -/* - * Class: Sandbox - * Method: jniGetMachineType - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_Sandbox_jniGetMachineType - (JNIEnv * env, jobject thisObj) -{ - return 0; -} - -/* - * Class: Sandbox - * Method: jniInitializeClassFieldsAndMachineMask - * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniInitializeClassFieldsAndMachineMask - (JNIEnv* env, jobject thisObject, jclass readDataHolderClass, jclass haplotypeDataHolderClass, jlong mask) -{ - Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask(env, thisObject, readDataHolderClass, - haplotypeDataHolderClass, mask); -} - -/* - * Class: Sandbox - * Method: jniInitializeHaplotypes - * Signature: (I[LSandbox/JNIHaplotypeDataHolderClass;)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniInitializeHaplotypes - (JNIEnv * env, jobject thisObject, jint numHaplotypes, jobjectArray haplotypeDataArray) -{ - Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray); -} - -/* - * Class: Sandbox - * Method: jniFinalizeRegion - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniFinalizeRegion - (JNIEnv * env, jobject thisObject) -{ - Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniFinalizeRegion(env, thisObject); -} - - -/* - * Class: Sandbox - * Method: jniComputeLikelihoods - * Signature: (II[LSandbox/JNIReadDataHolderClass;[LSandbox/JNIHaplotypeDataHolderClass;[DI)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniComputeLikelihoods - (JNIEnv* env, jobject thisObject, jint numReads, jint numHaplotypes, - jobjectArray readDataArray, jobjectArray haplotypeDataArray, jdoubleArray likelihoodArray, jint maxNumThreadsToUse) -{ - Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods(env, thisObject, - numReads, numHaplotypes, readDataArray, haplotypeDataArray, likelihoodArray, maxNumThreadsToUse); -} -/* - * Class: Sandbox - * Method: jniClose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniClose - (JNIEnv* env, jobject thisObject) -{ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniClose(env, thisObject); } - -JNIEXPORT void JNICALL Java_Sandbox_doEverythingNative - (JNIEnv* env, jobject thisObject, jstring fileNameString) -{ - const char* fileName = env->GetStringUTFChars(fileNameString, 0); - char local_array[800]; - strncpy(local_array, fileName, 200); - env->ReleaseStringUTFChars(fileNameString, fileName); - do_compute(local_array, true, 10000, false); -} - diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.h b/public/VectorPairHMM/src/main/c++/Sandbox.h deleted file mode 100644 index 486a1c095..000000000 --- a/public/VectorPairHMM/src/main/c++/Sandbox.h +++ /dev/null @@ -1,96 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class Sandbox */ - -#ifndef _Included_Sandbox -#define _Included_Sandbox -#ifdef __cplusplus -extern "C" { -#endif -#undef Sandbox_enableAll -#define Sandbox_enableAll -1LL -/* - * Class: Sandbox - * Method: jniGetMachineType - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_Sandbox_jniGetMachineType - (JNIEnv *, jobject); - -/* - * Class: Sandbox - * Method: jniInitializeClassFieldsAndMachineMask - * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniInitializeClassFieldsAndMachineMask - (JNIEnv *, jobject, jclass, jclass, jlong); - -/* - * Class: Sandbox - * Method: jniInitializeHaplotypes - * Signature: (I[LSandbox/JNIHaplotypeDataHolderClass;)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniInitializeHaplotypes - (JNIEnv *, jobject, jint, jobjectArray); - -/* - * Class: Sandbox - * Method: jniFinalizeRegion - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniFinalizeRegion - (JNIEnv *, jobject); - -/* - * Class: Sandbox - * Method: jniComputeLikelihoods - * Signature: (II[LSandbox/JNIReadDataHolderClass;[LSandbox/JNIHaplotypeDataHolderClass;[DI)V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniComputeLikelihoods - (JNIEnv *, jobject, jint, jint, jobjectArray, jobjectArray, jdoubleArray, jint); - -/* - * Class: Sandbox - * Method: jniClose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_Sandbox_jniClose - (JNIEnv *, jobject); - -/* - * Class: Sandbox - * Method: doEverythingNative - * Signature: ([B)V - */ -JNIEXPORT void JNICALL Java_Sandbox_doEverythingNative - (JNIEnv *, jobject, jstring); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.java b/public/VectorPairHMM/src/main/c++/Sandbox.java deleted file mode 100644 index a1ecb21f9..000000000 --- a/public/VectorPairHMM/src/main/c++/Sandbox.java +++ /dev/null @@ -1,306 +0,0 @@ -/* -* Copyright 2012-2016 Broad Institute, Inc. -* -* Permission is hereby granted, free of charge, to any person -* obtaining a copy of this software and associated documentation -* files (the "Software"), to deal in the Software without -* restriction, including without limitation the rights to use, -* copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following -* conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -package org.broadinstitute.gatk.utils.vectorpairhmm; - -import java.util.List; -import java.util.LinkedList; -import java.util.Map; -import java.util.HashMap; -import java.io.File; -import java.util.Scanner; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; - -public class Sandbox { - - private long setupTime = 0; - private long computeTime = 0; - //Used to copy references to byteArrays to JNI from reads - protected class JNIReadDataHolderClass { - public byte[] readBases = null; - public byte[] readQuals = null; - public byte[] insertionGOP = null; - public byte[] deletionGOP = null; - public byte[] overallGCP = null; - } - - //Used to copy references to byteArrays to JNI from haplotypes - protected class JNIHaplotypeDataHolderClass { - public byte[] haplotypeBases = null; - } - - /** - * Return 64-bit mask representing machine capabilities - * Bit 0 is LSB, bit 63 MSB - * Bit 0 represents sse4.2 availability - * Bit 1 represents AVX availability - */ - public native long jniGetMachineType(); - public static final long enableAll = 0xFFFFFFFFFFFFFFFFl; - - - /** - * Function to initialize the fields of JNIReadDataHolderClass and JNIHaplotypeDataHolderClass from JVM. - * C++ codegets FieldIDs for these classes once and re-uses these IDs for the remainder of the program. Field IDs do not - * change per JVM session - * @param readDataHolderClass class type of JNIReadDataHolderClass - * @param haplotypeDataHolderClass class type of JNIHaplotypeDataHolderClass - * @param mask 64 bit integer identical to the one received from jniGetMachineType(). Users can disable usage of some hardware features by zeroing bits in the mask - * */ - private native void jniInitializeClassFieldsAndMachineMask(Class readDataHolderClass, Class haplotypeDataHolderClass, long mask); - - private static Boolean isVectorLoglessPairHMMLibraryLoaded = false; - //The constructor is called only once inside PairHMMLikelihoodCalculationEngine - public Sandbox() { - synchronized(isVectorLoglessPairHMMLibraryLoaded) { - //Load the library and initialize the FieldIDs - if(!isVectorLoglessPairHMMLibraryLoaded) { - System.loadLibrary("VectorLoglessPairHMM"); - isVectorLoglessPairHMMLibraryLoaded = true; - jniInitializeClassFieldsAndMachineMask(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class, enableAll); //need to do this only once - } - } - } - - private native void jniInitializeHaplotypes(final int numHaplotypes, JNIHaplotypeDataHolderClass[] haplotypeDataArray); - private JNIHaplotypeDataHolderClass[] mHaplotypeDataArray = null; - - //Used to transfer data to JNI - //Since the haplotypes are the same for all calls to computeLikelihoods within a region, transfer the haplotypes only once to the JNI per region - public void initialize(final List haplotypes) { - int numHaplotypes = haplotypes.size(); - mHaplotypeDataArray = new JNIHaplotypeDataHolderClass[numHaplotypes]; - int idx = 0; - for(final JNIHaplotypeDataHolderClass currHaplotype : haplotypes) - { - mHaplotypeDataArray[idx] = new JNIHaplotypeDataHolderClass(); - mHaplotypeDataArray[idx].haplotypeBases = currHaplotype.haplotypeBases; - ++idx; - } - jniInitializeHaplotypes(numHaplotypes, mHaplotypeDataArray); - } - /** - * Tell JNI to release arrays - really important if native code is directly accessing Java memory, if not - * accessing Java memory directly, still important to release memory from C++ - */ - private native void jniFinalizeRegion(); - - - public void finalizeRegion() - { - jniFinalizeRegion(); - } - - /** - * Real compute kernel - */ - private native void jniComputeLikelihoods(int numReads, int numHaplotypes, JNIReadDataHolderClass[] readDataArray, - JNIHaplotypeDataHolderClass[] haplotypeDataArray, double[] likelihoodArray, int maxNumThreadsToUse); - - public void computeLikelihoods(final List reads, final List haplotypes) { - //System.out.println("Region : "+reads.size()+" x "+haplotypes.size()); - long startTime = System.nanoTime(); - int readListSize = reads.size(); - int numHaplotypes = haplotypes.size(); - int numTestcases = readListSize*numHaplotypes; - JNIReadDataHolderClass[] readDataArray = new JNIReadDataHolderClass[readListSize]; - int idx = 0; - for(JNIReadDataHolderClass read : reads) - { - readDataArray[idx] = new JNIReadDataHolderClass(); - readDataArray[idx].readBases = read.readBases; - readDataArray[idx].readQuals = read.readQuals; - readDataArray[idx].insertionGOP = read.insertionGOP; - readDataArray[idx].deletionGOP = read.deletionGOP; - readDataArray[idx].overallGCP = read.overallGCP; - ++idx; - } - - double[] mLikelihoodArray = new double[readListSize*numHaplotypes]; //to store results - setupTime += (System.nanoTime() - startTime); - //for(reads) - // for(haplotypes) - // compute_full_prob() - jniComputeLikelihoods(readListSize, numHaplotypes, readDataArray, mHaplotypeDataArray, mLikelihoodArray, 12); - - computeTime += (System.nanoTime() - startTime); - } - - /** - * Print final profiling information from native code - */ - public native void jniClose(); - public void close() - { - System.err.println("Time spent in setup for JNI call : " + (setupTime * 1e-9) + " compute time : " + (computeTime * 1e-9)); - jniClose(); - } - - public void parseSandboxFile(String filename) - { - File file = new File(filename); - Scanner input = null; - try - { - input = new Scanner(file); - } - catch(FileNotFoundException e) - { - System.err.println("File "+filename + " cannot be found/read"); - return; - } - int idx = 0; - int numReads = 0; - int numHaplotypes = 0; - int readIdx = 0, testCaseIdx = 0, haplotypeIdx = 0; - LinkedList haplotypeList = new LinkedList(); - LinkedList readList = new LinkedList(); - - byte[][] byteArray = new byte[6][]; - boolean firstLine = true; - String[] currTokens = new String[8]; - while(input.hasNextLine()) - { - String line = input.nextLine(); - Scanner lineScanner = new Scanner(line); - idx = 0; - while(lineScanner.hasNext()) - currTokens[idx++] = lineScanner.next(); - if(idx == 0) - break; - assert(idx >= 6); - //start of new region - if(idx == 8) - { - if(!firstLine) - { - initialize(haplotypeList); - computeLikelihoods(readList, haplotypeList); - finalizeRegion(); - } - try - { - numReads = Integer.parseInt(currTokens[6]); - } - catch(NumberFormatException e) - { - numReads = 1; - } - try - { - numHaplotypes = Integer.parseInt(currTokens[7]); - } - catch(NumberFormatException e) - { - numHaplotypes = 1; - } - haplotypeIdx = readIdx = testCaseIdx = 0; - readList.clear(); - haplotypeList.clear(); - } - if(haplotypeIdx < numHaplotypes) - { - JNIHaplotypeDataHolderClass X = new JNIHaplotypeDataHolderClass(); - X.haplotypeBases = currTokens[0].getBytes(); - haplotypeList.add(X); - } - if(testCaseIdx%numHaplotypes == 0) - { - JNIReadDataHolderClass X = new JNIReadDataHolderClass(); - X.readBases = currTokens[1].getBytes(); - for(int i=2;i<6;++i) - { - byteArray[i] = currTokens[i].getBytes(); - for(int j=0;j 0 && readList.size() > 0) - { - initialize(haplotypeList); - computeLikelihoods(readList, haplotypeList); - finalizeRegion(); - } - - close(); - input.close(); - } - - private native void doEverythingNative(String filename); - - public static void main(String[] args) - { - if(args.length <= 0) - { - System.err.println("Needs 1 argument - "); - System.exit(-1); - } - //// Get runtime - //java.lang.Runtime rt = java.lang.Runtime.getRuntime(); - //// Start a new process: UNIX command ls - //String cmd = "/home/karthikg/broad/gsa-unstable/public/c++/VectorPairHMM/checker "+args[0]; - //try - //{ - //System.out.println(cmd); - //java.lang.Process p = rt.exec(cmd); - //try - //{ - //p.waitFor(); - //java.io.InputStream is = p.getInputStream(); - //java.io.BufferedReader reader = new java.io.BufferedReader(new InputStreamReader(is)); - //// And print each line - //String s = null; - //while ((s = reader.readLine()) != null) { - //System.out.println(s); - //} - //is.close(); - //} - //catch(InterruptedException e) - //{ - //System.err.println(e); - //} - //} - //catch(IOException e) - //{ - //System.err.println(e); - //} - Sandbox t = new Sandbox(); - //t.doEverythingNative(args[0]); - t.parseSandboxFile(args[0]); - } -} diff --git a/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h b/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h deleted file mode 100644 index 7f78f0178..000000000 --- a/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h +++ /dev/null @@ -1,13 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class Sandbox_JNIHaplotypeDataHolderClass */ - -#ifndef _Included_Sandbox_JNIHaplotypeDataHolderClass -#define _Included_Sandbox_JNIHaplotypeDataHolderClass -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif -#endif diff --git a/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h b/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h deleted file mode 100644 index a9312ff3b..000000000 --- a/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h +++ /dev/null @@ -1,13 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class Sandbox_JNIReadDataHolderClass */ - -#ifndef _Included_Sandbox_JNIReadDataHolderClass -#define _Included_Sandbox_JNIReadDataHolderClass -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif -#endif diff --git a/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc b/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc deleted file mode 100644 index 1a6b593c2..000000000 --- a/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc +++ /dev/null @@ -1,45 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - - -#undef SIMD_ENGINE -#undef SIMD_ENGINE_SSE - -#define SIMD_ENGINE avx -#define SIMD_ENGINE_AVX - -#include "template.h" - -#include "define-float.h" -#include "shift_template.c" -#include "pairhmm-template-kernel.cc" - -#include "define-double.h" -#include "shift_template.c" -#include "pairhmm-template-kernel.cc" - -template double compute_full_prob_avxd(testcase* tc, double* nextlog); -template float compute_full_prob_avxs(testcase* tc, float* nextlog); - diff --git a/public/VectorPairHMM/src/main/c++/baseline.cc b/public/VectorPairHMM/src/main/c++/baseline.cc deleted file mode 100644 index 17d2c279e..000000000 --- a/public/VectorPairHMM/src/main/c++/baseline.cc +++ /dev/null @@ -1,157 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include "headers.h" -#include "common_data_structure.h" -#include "utils.h" -#include "LoadTimeInitializer.h" -using namespace std; - -template -NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log) -{ - int r, c; - int ROWS = tc->rslen + 1; - int COLS = tc->haplen + 1; - - Context ctx; - //#define USE_STACK_ALLOCATION 1 -#ifdef USE_STACK_ALLOCATION - NUMBER M[ROWS][COLS]; - NUMBER X[ROWS][COLS]; - NUMBER Y[ROWS][COLS]; - NUMBER p[ROWS][6]; -#else - //allocate on heap in way that simulates a 2D array. Having a 2D array instead of - //a straightforward array of pointers ensures that all data lies 'close' in memory, increasing - //the chance of being stored together in the cache. Also, prefetchers can learn memory access - //patterns for 2D arrays, not possible for array of pointers - //NUMBER* common_buffer = 0; - NUMBER* common_buffer = new NUMBER[3*ROWS*COLS + ROWS*6]; - //pointers to within the allocated buffer - NUMBER** common_pointer_buffer = new NUMBER*[4*ROWS]; - NUMBER* ptr = common_buffer; - unsigned i = 0; - for(i=0;i<3*ROWS;++i, ptr+=COLS) - common_pointer_buffer[i] = ptr; - for(;i<4*ROWS;++i, ptr+=6) - common_pointer_buffer[i] = ptr; - - NUMBER** M = common_pointer_buffer; - NUMBER** X = M + ROWS; - NUMBER** Y = X + ROWS; - NUMBER** p = Y + ROWS; -#endif - - - p[0][MM] = ctx._(0.0); - p[0][GapM] = ctx._(0.0); - p[0][MX] = ctx._(0.0); - p[0][XX] = ctx._(0.0); - p[0][MY] = ctx._(0.0); - p[0][YY] = ctx._(0.0); - - for (r = 1; r < ROWS; r++) - { - int _i = tc->i[r-1] & 127; - int _d = tc->d[r-1] & 127; - int _c = tc->c[r-1] & 127; - //p[r][MM] = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127]; - SET_MATCH_TO_MATCH_PROB(p[r][MM], _i, _d); - p[r][GapM] = ctx._(1.0) - ctx.ph2pr[_c]; - p[r][MX] = ctx.ph2pr[_i]; - p[r][XX] = ctx.ph2pr[_c]; - p[r][MY] = ctx.ph2pr[_d]; - p[r][YY] = ctx.ph2pr[_c]; - //p[r][MY] = (r == ROWS - 1) ? ctx._(1.0) : ctx.ph2pr[_d]; - //p[r][YY] = (r == ROWS - 1) ? ctx._(1.0) : ctx.ph2pr[_c]; - } - for (c = 0; c < COLS; c++) - { - M[0][c] = ctx._(0.0); - X[0][c] = ctx._(0.0); - Y[0][c] = ctx.INITIAL_CONSTANT / (tc->haplen); - } - - for (r = 1; r < ROWS; r++) - { - M[r][0] = ctx._(0.0); - X[r][0] = X[r-1][0] * p[r][XX]; - Y[r][0] = ctx._(0.0); - } - - NUMBER result = ctx._(0.0); - - for (r = 1; r < ROWS; r++) - for (c = 1; c < COLS; c++) - { - fexcept_t flagp; - char _rs = tc->rs[r-1]; - char _hap = tc->hap[c-1]; - int _q = tc->q[r-1] & 127; - NUMBER distm = ctx.ph2pr[_q]; - if (_rs == _hap || _rs == 'N' || _hap == 'N') - distm = ctx._(1.0) - distm; - else - distm = distm/3; - - - //feclearexcept(FE_ALL_EXCEPT); - M[r][c] = distm * (M[r-1][c-1] * p[r][MM] + X[r-1][c-1] * p[r][GapM] + Y[r-1][c-1] * p[r][GapM]); - //STORE_FP_EXCEPTIONS(flagp, exceptions_array); - - //feclearexcept(FE_ALL_EXCEPT); - X[r][c] = M[r-1][c] * p[r][MX] + X[r-1][c] * p[r][XX]; - //STORE_FP_EXCEPTIONS(flagp, exceptions_array); - - //feclearexcept(FE_ALL_EXCEPT); - Y[r][c] = M[r][c-1] * p[r][MY] + Y[r][c-1] * p[r][YY]; - //STORE_FP_EXCEPTIONS(flagp, exceptions_array); - - //CONVERT_AND_PRINT(M[r][c]); - //CONVERT_AND_PRINT(X[r][c]); - //CONVERT_AND_PRINT(Y[r][c]); - - } - for (c = 0; c < COLS; c++) - { - result += M[ROWS-1][c] + X[ROWS-1][c]; - } - - if (before_last_log != NULL) - *before_last_log = result; - -#ifndef USE_STACK_ALLOCATION - delete[] common_pointer_buffer; - delete[] common_buffer; -#endif - - return result; - //return ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT; -} - -template double compute_full_prob(testcase* tc, double* nextbuf); -template float compute_full_prob(testcase* tc, float* nextbuf); - diff --git a/public/VectorPairHMM/src/main/c++/common_data_structure.h b/public/VectorPairHMM/src/main/c++/common_data_structure.h deleted file mode 100644 index 4b5f0341c..000000000 --- a/public/VectorPairHMM/src/main/c++/common_data_structure.h +++ /dev/null @@ -1,215 +0,0 @@ -#ifndef COMMON_DATA_STRUCTURE_H -#define COMMON_DATA_STRUCTURE_H - -#include "headers.h" - -#define CAT(X,Y) X####Y -#define CONCAT(X,Y) CAT(X,Y) - -#define MM 0 -#define GapM 1 -#define MX 2 -#define XX 3 -#define MY 4 -#define YY 5 - -//#define MROWS 500 -//#define MCOLS 1000 - - -#define MAX_QUAL 254 -#define MAX_JACOBIAN_TOLERANCE 8.0 -#define JACOBIAN_LOG_TABLE_STEP 0.0001 -#define JACOBIAN_LOG_TABLE_INV_STEP (1.0 / JACOBIAN_LOG_TABLE_STEP) -#define MAXN 70000 -#define LOG10_CACHE_SIZE (4*MAXN) // we need to be able to go up to 2*(2N) when calculating some of the coefficients -#define JACOBIAN_LOG_TABLE_SIZE ((int) (MAX_JACOBIAN_TOLERANCE / JACOBIAN_LOG_TABLE_STEP) + 1) - -template -struct ContextBase -{ - public: - NUMBER ph2pr[128]; - NUMBER INITIAL_CONSTANT; - NUMBER LOG10_INITIAL_CONSTANT; - NUMBER RESULT_THRESHOLD; - - static bool staticMembersInitializedFlag; - static NUMBER jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE]; - static NUMBER matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1]; - - static void initializeStaticMembers() - { - if(!staticMembersInitializedFlag) - { - //Order of calls important - Jacobian first, then MatchToMatch - initializeJacobianLogTable(); - initializeMatchToMatchProb(); - staticMembersInitializedFlag = true; - } - } - - static void deleteStaticMembers() - { - if(staticMembersInitializedFlag) - { - staticMembersInitializedFlag = false; - } - } - - //Called only once during library load - don't bother to optimize with single precision fp - static void initializeJacobianLogTable() - { - for (int k = 0; k < JACOBIAN_LOG_TABLE_SIZE; k++) { - jacobianLogTable[k] = (NUMBER)(log10(1.0 + pow(10.0, -((double) k) * JACOBIAN_LOG_TABLE_STEP))); - } - } - - //Called only once per library load - don't bother optimizing with single fp - static void initializeMatchToMatchProb() - { - double LN10 = log(10); - double INV_LN10 = 1.0/LN10; - for (int i = 0, offset = 0; i <= MAX_QUAL; offset += ++i) - for (int j = 0; j <= i; j++) { - double log10Sum = approximateLog10SumLog10(-0.1*i, -0.1*j); - double matchToMatchLog10 = - log1p(-std::min(1.0,pow(10,log10Sum))) * INV_LN10; - matchToMatchProb[offset + j] = (NUMBER)(pow(10,matchToMatchLog10)); - } - } - //Called during computation - use single precision where possible - static int fastRound(NUMBER d) { - return (d > ((NUMBER)0.0)) ? (int) (d + ((NUMBER)0.5)) : (int) (d - ((NUMBER)0.5)); - } - //Called during computation - use single precision where possible - static NUMBER approximateLog10SumLog10(NUMBER small, NUMBER big) { - // make sure small is really the smaller value - if (small > big) { - NUMBER t = big; - big = small; - small = t; - } - - if (isinf(small) == -1 || isinf(big) == -1) - return big; - - NUMBER diff = big - small; - if (diff >= ((NUMBER)MAX_JACOBIAN_TOLERANCE)) - return big; - - // OK, so |y-x| < tol: we use the following identity then: - // we need to compute log10(10^x + 10^y) - // By Jacobian logarithm identity, this is equal to - // max(x,y) + log10(1+10^-abs(x-y)) - // we compute the second term as a table lookup with integer quantization - // we have pre-stored correction for 0,0.1,0.2,... 10.0 - int ind = fastRound((NUMBER)(diff * ((NUMBER)JACOBIAN_LOG_TABLE_INV_STEP))); // hard rounding - return big + jacobianLogTable[ind]; - } -}; - -template -struct Context : public ContextBase -{}; - -template<> -struct Context : public ContextBase -{ - Context():ContextBase() - { - for (int x = 0; x < 128; x++) - ph2pr[x] = pow(10.0, -((double)x) / 10.0); - - INITIAL_CONSTANT = ldexp(1.0, 1020.0); - LOG10_INITIAL_CONSTANT = log10(INITIAL_CONSTANT); - RESULT_THRESHOLD = 0.0; - } - - double LOG10(double v){ return log10(v); } - inline double POW(double b, double e) { return pow(b,e); } - - static double _(double n){ return n; } - static double _(float n){ return ((double) n); } -}; - -template<> -struct Context : public ContextBase -{ - Context() : ContextBase() - { - for (int x = 0; x < 128; x++) - { - ph2pr[x] = powf(10.f, -((float)x) / 10.f); - } - - INITIAL_CONSTANT = ldexpf(1.f, 120.f); - LOG10_INITIAL_CONSTANT = log10f(INITIAL_CONSTANT); - RESULT_THRESHOLD = ldexpf(1.f, -110.f); - } - - float LOG10(float v){ return log10f(v); } - inline float POW(float b, float e) { return powf(b,e); } - - static float _(double n){ return ((float) n); } - static float _(float n){ return n; } -}; - -#define SET_MATCH_TO_MATCH_PROB(output, insQual, delQual) \ -{ \ - int minQual = delQual; \ - int maxQual = insQual; \ - if (insQual <= delQual) \ - { \ - minQual = insQual; \ - maxQual = delQual; \ - } \ - (output) = (MAX_QUAL < maxQual) ? \ - ((NUMBER)1.0) - ctx.POW(((NUMBER)10), ctx.approximateLog10SumLog10(((NUMBER)-0.1)*minQual, ((NUMBER)-0.1)*maxQual)) \ - : ctx.matchToMatchProb[((maxQual * (maxQual + 1)) >> 1) + minQual]; \ -} - - - -typedef struct -{ - int rslen, haplen; - /*int *q, *i, *d, *c;*/ - /*int q[MROWS], i[MROWS], d[MROWS], c[MROWS];*/ - char *q, *i, *d, *c; - char *hap, *rs; - int *ihap; - int *irs; -} testcase; - -#define MIN_ACCEPTED 1e-28f -#define NUM_DISTINCT_CHARS 5 -#define AMBIG_CHAR 4 - -class ConvertChar { - - static uint8_t conversionTable[255] ; - -public: - - static void init() { - assert (NUM_DISTINCT_CHARS == 5) ; - assert (AMBIG_CHAR == 4) ; - - conversionTable['A'] = 0 ; - conversionTable['C'] = 1 ; - conversionTable['T'] = 2 ; - conversionTable['G'] = 3 ; - conversionTable['N'] = 4 ; - } - - static inline uint8_t get(uint8_t input) { - return conversionTable[input] ; - } - -}; - -int normalize(char c); -int read_testcase(testcase *tc, FILE* ifp=0); - -#endif diff --git a/public/VectorPairHMM/src/main/c++/define-double.h b/public/VectorPairHMM/src/main/c++/define-double.h deleted file mode 100644 index 96fc274c4..000000000 --- a/public/VectorPairHMM/src/main/c++/define-double.h +++ /dev/null @@ -1,205 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include - -#ifdef PRECISION -#undef PRECISION -#undef MAIN_TYPE -#undef MAIN_TYPE_SIZE -#undef UNION_TYPE -#undef IF_128 -#undef IF_MAIN_TYPE -#undef SHIFT_CONST1 -#undef SHIFT_CONST2 -#undef SHIFT_CONST3 -#undef _128_TYPE -#undef SIMD_TYPE -#undef AVX_LENGTH -#undef HAP_TYPE -#undef MASK_TYPE -#undef MASK_ALL_ONES - -#undef SET_VEC_ZERO -#undef VEC_OR -#undef VEC_ADD -#undef VEC_SUB -#undef VEC_MUL -#undef VEC_DIV -#undef VEC_BLEND -#undef VEC_BLENDV -#undef VEC_CAST_256_128 -#undef VEC_EXTRACT_128 -#undef VEC_EXTRACT_UNIT -#undef VEC_SET1_VAL128 -#undef VEC_MOVE -#undef VEC_CAST_128_256 -#undef VEC_INSERT_VAL -#undef VEC_CVT_128_256 -#undef VEC_SET1_VAL -#undef VEC_POPCVT_CHAR -#undef VEC_LDPOPCVT_CHAR -#undef VEC_CMP_EQ -#undef VEC_SET_LSE -#undef SHIFT_HAP -#undef MASK_VEC -#undef VEC_SSE_TO_AVX -#undef VEC_SHIFT_LEFT_1BIT -#undef MASK_ALL_ONES -#undef COMPARE_VECS -#undef _256_INT_TYPE -#undef BITMASK_VEC -#endif - -#define PRECISION d -#define MAIN_TYPE double -#define MAIN_TYPE_SIZE 64 -#define UNION_TYPE mix_D -#define IF_128 IF_128d -#define IF_MAIN_TYPE IF_64 -#define SHIFT_CONST1 8 -#define SHIFT_CONST2 1 -#define SHIFT_CONST3 8 -#define _128_TYPE __m128d -#define SIMD_TYPE __m256d -#define _256_INT_TYPE __m256i -#define AVX_LENGTH 4 -#define HAP_TYPE __m128i -#define MASK_TYPE uint64_t -#define MASK_ALL_ONES 0xFFFFFFFFFFFFFFFF -#define MASK_VEC MaskVec_D - -#define SET_VEC_ZERO(__vec) \ - __vec= _mm256_setzero_pd() - -#define VEC_OR(__v1, __v2) \ - _mm256_or_pd(__v1, __v2) - -#define VEC_ADD(__v1, __v2) \ - _mm256_add_pd(__v1, __v2) - -#define VEC_SUB(__v1, __v2) \ - _mm256_sub_pd(__v1, __v2) - -#define VEC_MUL(__v1, __v2) \ - _mm256_mul_pd(__v1, __v2) - -#define VEC_DIV(__v1, __v2) \ - _mm256_div_pd(__v1, __v2) - -#define VEC_BLEND(__v1, __v2, __mask) \ - _mm256_blend_pd(__v1, __v2, __mask) - -#define VEC_BLENDV(__v1, __v2, __maskV) \ - _mm256_blendv_pd(__v1, __v2, __maskV) - -#define VEC_CAST_256_128(__v1) \ - _mm256_castpd256_pd128 (__v1) - -#define VEC_EXTRACT_128(__v1, __im) \ - _mm256_extractf128_pd (__v1, __im) - -#define VEC_EXTRACT_UNIT(__v1, __im) \ - _mm_extract_epi64(__v1, __im) - -#define VEC_SET1_VAL128(__val) \ - _mm_set1_pd(__val) - -#define VEC_MOVE(__v1, __val) \ - _mm_move_sd(__v1, __val) - -#define VEC_CAST_128_256(__v1) \ - _mm256_castpd128_pd256(__v1) - -#define VEC_INSERT_VAL(__v1, __val, __pos) \ - _mm256_insertf128_pd(__v1, __val, __pos) - -#define VEC_CVT_128_256(__v1) \ - _mm256_cvtepi32_pd(__v1) - -#define VEC_SET1_VAL(__val) \ - _mm256_set1_pd(__val) - -#define VEC_POPCVT_CHAR(__ch) \ - _mm256_cvtepi32_pd(_mm_set1_epi32(__ch)) - -#define VEC_LDPOPCVT_CHAR(__addr) \ - _mm256_cvtepi32_pd(_mm_load_si128((__m128i const *)__addr)) - -#define VEC_CMP_EQ(__v1, __v2) \ - _mm256_cmp_pd(__v1, __v2, _CMP_EQ_OQ) - -#define VEC_SET_LSE(__val) \ - _mm256_set_pd(zero, zero, zero, __val); - -#define SHIFT_HAP(__v1, __val) \ - __v1 = _mm_insert_epi32(_mm_slli_si128(__v1, 4), __val.i, 0) - -#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \ - __vdst = _mm256_castpd128_pd256(__vsLow) ; \ -__vdst = _mm256_insertf128_pd(__vdst, __vsHigh, 1) ; - -#define VEC_SHIFT_LEFT_1BIT(__vs) \ - __vs = _mm_slli_epi64(__vs, 1) - - -#define COMPARE_VECS(__v1, __v2, __first, __last) { \ - double* ptr1 = (double*) (&__v1) ; \ - double* ptr2 = (double*) (&__v2) ; \ - for (int ei=__first; ei <= __last; ++ei) { \ - if (ptr1[ei] != ptr2[ei]) { \ - std::cout << "Double Mismatch at " << ei << ": " \ - << ptr1[ei] << " vs. " << ptr2[ei] << std::endl ; \ - exit(0) ; \ - } \ - } \ -} - -class BitMaskVec_double { - - MASK_VEC low_, high_ ; - SIMD_TYPE combined_ ; - - public: - inline MASK_TYPE& getLowEntry(int index) { - return low_.masks[index] ; - } - inline MASK_TYPE& getHighEntry(int index) { - return high_.masks[index] ; - } - - inline const SIMD_TYPE& getCombinedMask() { - VEC_SSE_TO_AVX(low_.vecf, high_.vecf, combined_) ; - return combined_ ; - } - - inline void shift_left_1bit() { - VEC_SHIFT_LEFT_1BIT(low_.vec) ; - VEC_SHIFT_LEFT_1BIT(high_.vec) ; - } - -} ; - -#define BITMASK_VEC BitMaskVec_double diff --git a/public/VectorPairHMM/src/main/c++/define-float.h b/public/VectorPairHMM/src/main/c++/define-float.h deleted file mode 100644 index 056bd53f5..000000000 --- a/public/VectorPairHMM/src/main/c++/define-float.h +++ /dev/null @@ -1,206 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include - -#ifdef PRECISION -#undef PRECISION -#undef MAIN_TYPE -#undef MAIN_TYPE_SIZE -#undef UNION_TYPE -#undef IF_128 -#undef IF_MAIN_TYPE -#undef SHIFT_CONST1 -#undef SHIFT_CONST2 -#undef SHIFT_CONST3 -#undef _128_TYPE -#undef SIMD_TYPE -#undef AVX_LENGTH -#undef HAP_TYPE -#undef MASK_TYPE -#undef MASK_ALL_ONES - -#undef SET_VEC_ZERO -#undef VEC_OR -#undef VEC_ADD -#undef VEC_SUB -#undef VEC_MUL -#undef VEC_DIV -#undef VEC_BLEND -#undef VEC_BLENDV -#undef VEC_CAST_256_128 -#undef VEC_EXTRACT_128 -#undef VEC_EXTRACT_UNIT -#undef VEC_SET1_VAL128 -#undef VEC_MOVE -#undef VEC_CAST_128_256 -#undef VEC_INSERT_VAL -#undef VEC_CVT_128_256 -#undef VEC_SET1_VAL -#undef VEC_POPCVT_CHAR -#undef VEC_LDPOPCVT_CHAR -#undef VEC_CMP_EQ -#undef VEC_SET_LSE -#undef SHIFT_HAP -#undef MASK_VEC -#undef VEC_SSE_TO_AVX -#undef VEC_SHIFT_LEFT_1BIT -#undef MASK_ALL_ONES -#undef COMPARE_VECS -#undef _256_INT_TYPE -#undef BITMASK_VEC -#endif - -#define PRECISION s - -#define MAIN_TYPE float -#define MAIN_TYPE_SIZE 32 -#define UNION_TYPE mix_F -#define IF_128 IF_128f -#define IF_MAIN_TYPE IF_32 -#define SHIFT_CONST1 12 -#define SHIFT_CONST2 3 -#define SHIFT_CONST3 4 -#define _128_TYPE __m128 -#define SIMD_TYPE __m256 -#define _256_INT_TYPE __m256i -#define AVX_LENGTH 8 -#define HAP_TYPE UNION_TYPE -#define MASK_TYPE uint32_t -#define MASK_ALL_ONES 0xFFFFFFFF -#define MASK_VEC MaskVec_F - -#define SET_VEC_ZERO(__vec) \ - __vec= _mm256_setzero_ps() - -#define VEC_OR(__v1, __v2) \ - _mm256_or_ps(__v1, __v2) - -#define VEC_ADD(__v1, __v2) \ - _mm256_add_ps(__v1, __v2) - -#define VEC_SUB(__v1, __v2) \ - _mm256_sub_ps(__v1, __v2) - -#define VEC_MUL(__v1, __v2) \ - _mm256_mul_ps(__v1, __v2) - -#define VEC_DIV(__v1, __v2) \ - _mm256_div_ps(__v1, __v2) - -#define VEC_BLEND(__v1, __v2, __mask) \ - _mm256_blend_ps(__v1, __v2, __mask) - -#define VEC_BLENDV(__v1, __v2, __maskV) \ - _mm256_blendv_ps(__v1, __v2, __maskV) - -#define VEC_CAST_256_128(__v1) \ - _mm256_castps256_ps128 (__v1) - -#define VEC_EXTRACT_128(__v1, __im) \ - _mm256_extractf128_ps (__v1, __im) - -#define VEC_EXTRACT_UNIT(__v1, __im) \ - _mm_extract_epi32(__v1, __im) - -#define VEC_SET1_VAL128(__val) \ - _mm_set1_ps(__val) - -#define VEC_MOVE(__v1, __val) \ - _mm_move_ss(__v1, __val) - -#define VEC_CAST_128_256(__v1) \ - _mm256_castps128_ps256(__v1) - -#define VEC_INSERT_VAL(__v1, __val, __pos) \ - _mm256_insertf128_ps(__v1, __val, __pos) - -#define VEC_CVT_128_256(__v1) \ - _mm256_cvtepi32_ps(__v1.i) - -#define VEC_SET1_VAL(__val) \ - _mm256_set1_ps(__val) - -#define VEC_POPCVT_CHAR(__ch) \ - _mm256_cvtepi32_ps(_mm256_set1_epi32(__ch)) - -#define VEC_LDPOPCVT_CHAR(__addr) \ - _mm256_cvtepi32_ps(_mm256_loadu_si256((__m256i const *)__addr)) - -#define VEC_CMP_EQ(__v1, __v2) \ - _mm256_cmp_ps(__v1, __v2, _CMP_EQ_OQ) - -#define VEC_SET_LSE(__val) \ - _mm256_set_ps(zero, zero, zero, zero, zero, zero, zero, __val); - -#define SHIFT_HAP(__v1, __val) \ - _vector_shift_lastavxs(__v1, __val.f); - -#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \ - __vdst = _mm256_castps128_ps256(__vsLow) ; \ -__vdst = _mm256_insertf128_ps(__vdst, __vsHigh, 1) ; - -#define VEC_SHIFT_LEFT_1BIT(__vs) \ - __vs = _mm_slli_epi32(__vs, 1) - -#define COMPARE_VECS(__v1, __v2, __first, __last) { \ - float* ptr1 = (float*) (&__v1) ; \ - float* ptr2 = (float*) (&__v2) ; \ - for (int ei=__first; ei <= __last; ++ei) { \ - if (ptr1[ei] != ptr2[ei]) { \ - std::cout << "Float Mismatch at " << ei << ": " \ - << ptr1[ei] << " vs. " << ptr2[ei] << std::endl ; \ - exit(0) ; \ - } \ - } \ -} - -class BitMaskVec_float { - - MASK_VEC low_, high_ ; - SIMD_TYPE combined_ ; - - public: - - inline MASK_TYPE& getLowEntry(int index) { - return low_.masks[index] ; - } - inline MASK_TYPE& getHighEntry(int index) { - return high_.masks[index] ; - } - - inline const SIMD_TYPE& getCombinedMask() { - VEC_SSE_TO_AVX(low_.vecf, high_.vecf, combined_) ; - return combined_ ; - } - - inline void shift_left_1bit() { - VEC_SHIFT_LEFT_1BIT(low_.vec) ; - VEC_SHIFT_LEFT_1BIT(high_.vec) ; - } - -} ; - -#define BITMASK_VEC BitMaskVec_float diff --git a/public/VectorPairHMM/src/main/c++/define-sse-double.h b/public/VectorPairHMM/src/main/c++/define-sse-double.h deleted file mode 100644 index 9456e1453..000000000 --- a/public/VectorPairHMM/src/main/c++/define-sse-double.h +++ /dev/null @@ -1,173 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifdef PRECISION -#undef PRECISION -#undef MAIN_TYPE -#undef MAIN_TYPE_SIZE -#undef UNION_TYPE -#undef IF_128 -#undef IF_MAIN_TYPE -#undef SHIFT_CONST1 -#undef SHIFT_CONST2 -#undef SHIFT_CONST3 -#undef _128_TYPE -#undef SIMD_TYPE -#undef AVX_LENGTH -#undef HAP_TYPE -#undef MASK_TYPE -#undef MASK_ALL_ONES - -#undef VEC_EXTRACT_UNIT -#undef VEC_INSERT_UNIT -#undef SET_VEC_ZERO -#undef VEC_OR -#undef VEC_ADD -#undef VEC_SUB -#undef VEC_MUL -#undef VEC_DIV -#undef VEC_BLEND -#undef VEC_BLENDV -#undef VEC_CAST_256_128 -#undef VEC_EXTRACT_128 -#undef VEC_EXTRACT_UNIT -#undef VEC_SET1_VAL128 -#undef VEC_MOVE -#undef VEC_CAST_128_256 -#undef VEC_INSERT_VAL -#undef VEC_CVT_128_256 -#undef VEC_SET1_VAL -#undef VEC_POPCVT_CHAR -#undef VEC_LDPOPCVT_CHAR -#undef VEC_CMP_EQ -#undef VEC_SET_LSE -#undef SHIFT_HAP -#undef MASK_VEC -#undef VEC_SSE_TO_AVX -#undef VEC_SHIFT_LEFT_1BIT -#undef MASK_ALL_ONES -#undef COMPARE_VECS -#undef _256_INT_TYPE -#undef BITMASK_VEC -#endif - -#define SSE -#define PRECISION d - -#define MAIN_TYPE double -#define MAIN_TYPE_SIZE 64 -#define UNION_TYPE mix_D128 -#define IF_128 IF_128d -#define IF_MAIN_TYPE IF_64 -#define SHIFT_CONST1 1 -#define SHIFT_CONST2 8 -#define SHIFT_CONST3 0 -#define _128_TYPE __m128d -#define SIMD_TYPE __m128d -#define _256_INT_TYPE __m128i -#define AVX_LENGTH 2 -#define HAP_TYPE __m128i -#define MASK_TYPE uint64_t -#define MASK_ALL_ONES 0xFFFFFFFFFFFFFFFFL -#define MASK_VEC MaskVec_D - -#define VEC_EXTRACT_UNIT(__v1, __im) \ - _mm_extract_epi64(__v1, __im) - -#define VEC_INSERT_UNIT(__v1,__ins,__im) \ - _mm_insert_epi64(__v1,__ins,__im) - -#define VEC_OR(__v1, __v2) \ - _mm_or_pd(__v1, __v2) - -#define VEC_ADD(__v1, __v2) \ - _mm_add_pd(__v1, __v2) - -#define VEC_SUB(__v1, __v2) \ - _mm_sub_pd(__v1, __v2) - -#define VEC_MUL(__v1, __v2) \ - _mm_mul_pd(__v1, __v2) - -#define VEC_DIV(__v1, __v2) \ - _mm_div_pd(__v1, __v2) - -#define VEC_CMP_EQ(__v1, __v2) \ - _mm_cmpeq_pd(__v1, __v2) - -#define VEC_BLEND(__v1, __v2, __mask) \ - _mm_blend_pd(__v1, __v2, __mask) - -#define VEC_BLENDV(__v1, __v2, __maskV) \ - _mm_blendv_pd(__v1, __v2, __maskV) - -#define SHIFT_HAP(__v1, __val) \ - __v1 = _mm_insert_epi32(_mm_slli_si128(__v1, 4), __val.i, 0) - -#define VEC_CVT_128_256(__v1) \ - _mm_cvtepi32_pd(__v1) - -#define VEC_SET1_VAL(__val) \ - _mm_set1_pd(__val) - -#define VEC_POPCVT_CHAR(__ch) \ - _mm_cvtepi32_pd(_mm_set1_epi32(__ch)) - -#define VEC_SET_LSE(__val) \ - _mm_set_pd(zero, __val); - -#define VEC_LDPOPCVT_CHAR(__addr) \ - _mm_cvtepi32_pd(_mm_loadu_si128((__m128i const *)__addr)) - -#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \ - __vdst = _mm_castsi128_pd(_mm_set_epi64(__vsHigh, __vsLow)) - -#define VEC_SHIFT_LEFT_1BIT(__vs) \ - __vs = _mm_slli_epi64(__vs, 1) - - -class BitMaskVec_sse_double { - - MASK_VEC combined_ ; - public: - inline MASK_TYPE& getLowEntry(int index) { - return combined_.masks[index] ; - } - inline MASK_TYPE& getHighEntry(int index) { - return combined_.masks[AVX_LENGTH/2+index] ; - } - - inline const SIMD_TYPE& getCombinedMask() { - return combined_.vecf ; - } - - inline void shift_left_1bit() { - VEC_SHIFT_LEFT_1BIT(combined_.vec) ; - } - -} ; - -#define BITMASK_VEC BitMaskVec_sse_double - diff --git a/public/VectorPairHMM/src/main/c++/define-sse-float.h b/public/VectorPairHMM/src/main/c++/define-sse-float.h deleted file mode 100644 index e9371c000..000000000 --- a/public/VectorPairHMM/src/main/c++/define-sse-float.h +++ /dev/null @@ -1,173 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifdef PRECISION -#undef PRECISION -#undef MAIN_TYPE -#undef MAIN_TYPE_SIZE -#undef UNION_TYPE -#undef IF_128 -#undef IF_MAIN_TYPE -#undef SHIFT_CONST1 -#undef SHIFT_CONST2 -#undef SHIFT_CONST3 -#undef _128_TYPE -#undef SIMD_TYPE -#undef AVX_LENGTH -#undef HAP_TYPE -#undef MASK_TYPE -#undef MASK_ALL_ONES - -#undef VEC_EXTRACT_UNIT -#undef VEC_INSERT_UNIT -#undef SET_VEC_ZERO -#undef VEC_OR -#undef VEC_ADD -#undef VEC_SUB -#undef VEC_MUL -#undef VEC_DIV -#undef VEC_BLEND -#undef VEC_BLENDV -#undef VEC_CAST_256_128 -#undef VEC_EXTRACT_128 -#undef VEC_EXTRACT_UNIT -#undef VEC_SET1_VAL128 -#undef VEC_MOVE -#undef VEC_CAST_128_256 -#undef VEC_INSERT_VAL -#undef VEC_CVT_128_256 -#undef VEC_SET1_VAL -#undef VEC_POPCVT_CHAR -#undef VEC_LDPOPCVT_CHAR -#undef VEC_CMP_EQ -#undef VEC_SET_LSE -#undef SHIFT_HAP -#undef MASK_VEC -#undef VEC_SSE_TO_AVX -#undef VEC_SHIFT_LEFT_1BIT -#undef MASK_ALL_ONES -#undef COMPARE_VECS -#undef _256_INT_TYPE -#undef BITMASK_VEC -#endif - -#define SSE -#define PRECISION s - -#define MAIN_TYPE float -#define MAIN_TYPE_SIZE 32 -#define UNION_TYPE mix_F128 -#define IF_128 IF_128f -#define IF_MAIN_TYPE IF_32 -#define SHIFT_CONST1 3 -#define SHIFT_CONST2 4 -#define SHIFT_CONST3 0 -#define _128_TYPE __m128 -#define SIMD_TYPE __m128 -#define _256_INT_TYPE __m128i -#define AVX_LENGTH 4 -//#define MAVX_COUNT (MROWS+3)/AVX_LENGTH -#define HAP_TYPE UNION_TYPE -#define MASK_TYPE uint32_t -#define MASK_ALL_ONES 0xFFFFFFFF -#define MASK_VEC MaskVec_F - -#define VEC_EXTRACT_UNIT(__v1, __im) \ - _mm_extract_epi32(__v1, __im) - -#define VEC_INSERT_UNIT(__v1,__ins,__im) \ - _mm_insert_epi32(__v1,__ins,__im) - -#define VEC_OR(__v1, __v2) \ - _mm_or_ps(__v1, __v2) - -#define VEC_ADD(__v1, __v2) \ - _mm_add_ps(__v1, __v2) - -#define VEC_SUB(__v1, __v2) \ - _mm_sub_ps(__v1, __v2) - -#define VEC_MUL(__v1, __v2) \ - _mm_mul_ps(__v1, __v2) - -#define VEC_DIV(__v1, __v2) \ - _mm_div_ps(__v1, __v2) - -#define VEC_CMP_EQ(__v1, __v2) \ - _mm_cmpeq_ps(__v1, __v2) - -#define VEC_BLEND(__v1, __v2, __mask) \ - _mm_blend_ps(__v1, __v2, __mask) - -#define VEC_BLENDV(__v1, __v2, __maskV) \ - _mm_blendv_ps(__v1, __v2, __maskV) - -#define SHIFT_HAP(__v1, __val) \ - _vector_shift_lastsses(__v1, __val.f) - -#define VEC_CVT_128_256(__v1) \ - _mm_cvtepi32_ps(__v1.i) - -#define VEC_SET1_VAL(__val) \ - _mm_set1_ps(__val) - -#define VEC_POPCVT_CHAR(__ch) \ - _mm_cvtepi32_ps(_mm_set1_epi32(__ch)) - -#define VEC_SET_LSE(__val) \ - _mm_set_ps(zero, zero, zero, __val); - -#define VEC_LDPOPCVT_CHAR(__addr) \ - _mm_cvtepi32_ps(_mm_loadu_si128((__m128i const *)__addr)) - -#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \ - __vdst = _mm_cvtpi32x2_ps(__vsLow, __vsHigh) - -#define VEC_SHIFT_LEFT_1BIT(__vs) \ - __vs = _mm_slli_epi32(__vs, 1) - -class BitMaskVec_sse_float { - - MASK_VEC combined_ ; - - public: - inline MASK_TYPE& getLowEntry(int index) { - return combined_.masks[index] ; - } - inline MASK_TYPE& getHighEntry(int index) { - return combined_.masks[AVX_LENGTH/2+index] ; - } - - inline const SIMD_TYPE& getCombinedMask() { - return combined_.vecf ; - } - - inline void shift_left_1bit() { - VEC_SHIFT_LEFT_1BIT(combined_.vec) ; - } - -} ; - -#define BITMASK_VEC BitMaskVec_sse_float diff --git a/public/VectorPairHMM/src/main/c++/headers.h b/public/VectorPairHMM/src/main/c++/headers.h deleted file mode 100644 index 4a0d89b57..000000000 --- a/public/VectorPairHMM/src/main/c++/headers.h +++ /dev/null @@ -1,71 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef COMMON_HEADERS_H -#define COMMON_HEADERS_H - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern uint64_t exceptions_array[128]; -extern FILE* g_debug_fptr; -#define STORE_FP_EXCEPTIONS(flagp, exceptions_array) \ - fegetexceptflag(&flagp, FE_ALL_EXCEPT | __FE_DENORM); \ - exceptions_array[FE_INVALID] += ((flagp & FE_INVALID)); \ - exceptions_array[__FE_DENORM] += ((flagp & __FE_DENORM) >> 1); \ - exceptions_array[FE_DIVBYZERO] += ((flagp & FE_DIVBYZERO) >> 2); \ - exceptions_array[FE_OVERFLOW] += ((flagp & FE_OVERFLOW) >> 3); \ - exceptions_array[FE_UNDERFLOW] += ((flagp & FE_UNDERFLOW) >> 4); \ - feclearexcept(FE_ALL_EXCEPT | __FE_DENORM); - -#define CONVERT_AND_PRINT(X) \ - g_converter.f = (X); \ - fwrite(&(g_converter.i),4,1,g_debug_fptr); \ - -#endif diff --git a/public/VectorPairHMM/src/main/c++/jni_common.h b/public/VectorPairHMM/src/main/c++/jni_common.h deleted file mode 100644 index b3139d4ac..000000000 --- a/public/VectorPairHMM/src/main/c++/jni_common.h +++ /dev/null @@ -1,60 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef JNI_COMMON_H -#define JNI_COMMON_H - -/*#define SINGLE_THREADED_ONLY 1*/ -#include -/*#define ENABLE_ASSERTIONS 1*/ -#ifdef SINGLE_THREADED_ONLY -#define DO_PROFILING 1 -#endif -/*#define DEBUG0_1 1*/ -/*#define DEBUG3 1*/ -/*#define DUMP_TO_SANDBOX 1*/ - - -/*#define DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY 1*/ - -#ifdef DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY -//Gets direct access to Java arrays -#define GET_BYTE_ARRAY_ELEMENTS env->GetPrimitiveArrayCritical -#define RELEASE_BYTE_ARRAY_ELEMENTS env->ReleasePrimitiveArrayCritical -#define JNI_RO_RELEASE_MODE JNI_ABORT -#define GET_DOUBLE_ARRAY_ELEMENTS env->GetPrimitiveArrayCritical -#define RELEASE_DOUBLE_ARRAY_ELEMENTS env->ReleasePrimitiveArrayCritical - -#else -//Likely makes copy of Java arrays to JNI C++ space -#define GET_BYTE_ARRAY_ELEMENTS env->GetByteArrayElements -#define RELEASE_BYTE_ARRAY_ELEMENTS env->ReleaseByteArrayElements -#define JNI_RO_RELEASE_MODE JNI_ABORT -#define GET_DOUBLE_ARRAY_ELEMENTS env->GetDoubleArrayElements -#define RELEASE_DOUBLE_ARRAY_ELEMENTS env->ReleaseDoubleArrayElements - -#endif //ifdef DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY - -#endif //ifndef JNI_COMMON_H diff --git a/public/VectorPairHMM/src/main/c++/jnidebug.h b/public/VectorPairHMM/src/main/c++/jnidebug.h deleted file mode 100644 index df2e207b6..000000000 --- a/public/VectorPairHMM/src/main/c++/jnidebug.h +++ /dev/null @@ -1,191 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef JNI_DEBUG_H -#define JNI_DEBUG_H - -template -class DataHolder -{ -#define INIT_MATRIX(X) \ - X = new NUMBER*[m_paddedMaxReadLength]; \ - for(int i=0;i ctx; - for (int r = 1; r <= length;r++) //in original code, r < ROWS (where ROWS = paddedReadLength) - { - int _i = insertionGOP[r-1]; //insertionGOP - int _d = deletionGOP[r-1]; //deletionGOP - int _c = overallGCP[r-1]; //overallGCP - m_transition[r][MM] = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127]; //lines 161-162 - m_transition[r][GapM] = ctx._(1.0) - ctx.ph2pr[_c]; //line 163 - m_transition[r][MX] = ctx.ph2pr[_i]; //164 - m_transition[r][XX] = ctx.ph2pr[_c]; //165 - m_transition[r][MY] = ctx.ph2pr[_d];//last row seems different, compared to line 166 - m_transition[r][YY] = ctx.ph2pr[_c];//same as above for line 167 - //m_transition[r][MY] = (r == length) ? ctx._(1.0) : ctx.ph2pr[_d];//last row seems different, compared to line 166 - //m_transition[r][YY] = (r == length) ? ctx._(1.0) : ctx.ph2pr[_c];//same as above for line 167 -#ifdef DEBUG3 - for(int j=0;j<6;++j) - debug_dump("transitions_jni.txt", to_string(m_transition[r][j]),true); -#endif - } - ++g_num_prob_init; - } - bool m_is_initialized; - int m_readMaxLength; - int m_haplotypeMaxLength; - int m_paddedMaxReadLength; - int m_paddedMaxHaplotypeLength; - NUMBER** m_matchMatrix; - NUMBER** m_insertionMatrix; - NUMBER** m_deletionMatrix; - NUMBER** m_prior; - NUMBER (*m_transition)[6]; -}; -extern DataHolder g_double_dataholder; - -template -NUMBER compute_full_prob(testcase *tc, NUMBER** M, NUMBER** X, NUMBER** Y, NUMBER (*p)[6], - bool do_initialization, jint hapStartIndex, NUMBER *before_last_log = NULL) -{ - int r, c; - int ROWS = tc->rslen + 1; //ROWS = paddedReadLength - int COLS = tc->haplen + 1; //COLS = paddedHaplotypeLength - - Context ctx; - //////NOTES - ////ctx.ph2pr[quality]; //This quantity is QualityUtils.qualToErrorProb(quality) - ////1-ctx.ph2pr[quality]; //This corresponds to QualityUtils.qualToProb(quality); - - //Initialization - if(do_initialization) - { - for (c = 0; c < COLS; c++) - { - M[0][c] = ctx._(0.0); - X[0][c] = ctx._(0.0); - Y[0][c] = ctx.INITIAL_CONSTANT / (tc->haplen); //code from 87-90 in LoglessPairHMM - } - - for (r = 1; r < ROWS; r++) - { - M[r][0] = ctx._(0.0); - //deletionMatrix row 0 in above nest is initialized in the Java code - //However, insertionMatrix column 0 is not initialized in Java code, could it be that - //values are re-used from a previous iteration? - //Why even do this, X[0][0] = 0 from above loop nest, X[idx][0] = 0 from this computation - X[r][0] = X[r-1][0] * p[r][XX]; - Y[r][0] = ctx._(0.0); - } - } - - for (r = 1; r < ROWS; r++) - for (c = hapStartIndex+1; c < COLS; c++) - { - //The following lines correspond to initializePriors() - char _rs = tc->rs[r-1]; //line 137 - char _hap = tc->hap[c-1]; //line 140 - //int _q = tc->q[r-1] & 127; //line 138 - q is the quality (qual), should be byte hence int ANDed with 0xFF - int _q = tc->q[r-1]; //line 138 - q is the quality (qual), should be byte hence int ANDed with 0xFF - NUMBER distm = ctx.ph2pr[_q]; //This quantity is QualityUtils.qualToErrorProb(_q) - //The assumption here is that doNotUseTristateCorrection is true - //TOASK - if (_rs == _hap || _rs == 'N' || _hap == 'N') - distm = ctx._(1.0) - distm; //This is the quantity QualityUtils.qualToProb(qual) - else - distm = distm/3; -#ifdef DEBUG3 - debug_dump("priors_jni.txt",to_string(distm),true); -#endif - - //Computation inside updateCell - M[r][c] = distm * (M[r-1][c-1] * p[r][MM] + X[r-1][c-1] * p[r][GapM] + Y[r-1][c-1] * p[r][GapM]); - X[r][c] = M[r-1][c] * p[r][MX] + X[r-1][c] * p[r][XX]; - Y[r][c] = M[r][c-1] * p[r][MY] + Y[r][c-1] * p[r][YY]; -#ifdef DEBUG3 - debug_dump("matrices_jni.txt",to_string(M[r][c]),true); - debug_dump("matrices_jni.txt",to_string(X[r][c]),true); - debug_dump("matrices_jni.txt",to_string(Y[r][c]),true); -#endif - } - - NUMBER result = ctx._(0.0); - for (c = 0; c < COLS; c++) - result += M[ROWS-1][c] + X[ROWS-1][c]; - - if (before_last_log != NULL) - *before_last_log = result; - -#ifdef DEBUG - debug_dump("return_values_jni.txt",to_string(ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT),true); -#endif - return ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT; -} - -#endif diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc deleted file mode 100644 index 42a9237c5..000000000 --- a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc +++ /dev/null @@ -1,175 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include "headers.h" -#include "jni_common.h" -#include "org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h" -#include "utils.h" -#include "LoadTimeInitializer.h" -#include "jnidebug.h" -DataHolder g_double_dataholder; - -using namespace std; - -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitialize -(JNIEnv* env, jobject thisObject, - jint readMaxLength, jint haplotypeMaxLength) -{ - static int g_num_init_calls = 0; -#ifdef DEBUG3 - cout << "Entered alloc initialized .. readMaxLength "<GetArrayLength(insertionGOP); -#ifdef DEBUG3 - cout << "Entered initializeProbabilities .. length "<GetByteArrayElements(insertionGOP, &is_copy); - jbyte* deletionGOPArray = (env)->GetByteArrayElements(deletionGOP, &is_copy); - jbyte* overallGCPArray = (env)->GetByteArrayElements(overallGCP, &is_copy); -#ifdef DEBUG - if(insertionGOPArray == 0) - cerr << "insertionGOP array not initialized in JNI\n"; - ////assert(insertionGOPArray && "insertionGOP array not initialized in JNI"); - if(deletionGOPArray == 0) - cerr << "deletionGOP array not initialized in JNI\n"; - ////assert(deletionGOPArray && "deletionGOP array not initialized in JNI"); - assert(overallGCPArray && "OverallGCP array not initialized in JNI"); -#endif - - g_double_dataholder.initializeProbabilities(length, insertionGOPArray, deletionGOPArray, overallGCPArray); - - env->ReleaseByteArrayElements(overallGCP, overallGCPArray, JNI_ABORT); - env->ReleaseByteArrayElements(deletionGOP, deletionGOPArray, JNI_ABORT); - env->ReleaseByteArrayElements(insertionGOP, insertionGOPArray, JNI_ABORT); -} - -JNIEXPORT jdouble JNICALL -Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializePriorsAndUpdateCells( - JNIEnv* env, jobject thisObject, - jboolean doInitialization, jint paddedReadLength, jint paddedHaplotypeLength, - jbyteArray readBases, jbyteArray haplotypeBases, jbyteArray readQuals, - jint hapStartIndex - ) -{ -#ifdef DEBUG3 - cout << "Entered mainCompute .. doInitialization "<<(doInitialization == JNI_TRUE)<<" hapStartIndex "<GetByteArrayElements(readBases, &is_copy); - jbyte* haplotypeBasesArray = (env)->GetByteArrayElements(haplotypeBases, &is_copy); - jbyte* readQualsArray = (env)->GetByteArrayElements(readQuals, &is_copy); -#ifdef DEBUG - assert(readBasesArray && "readBasesArray not initialized in JNI"); - assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI"); - assert(readQualsArray && "readQualsArray not initialized in JNI"); -#endif - testcase tc; - - tc.rslen = paddedReadLength-1; - tc.haplen = paddedHaplotypeLength-1; - - tc.rs = (char*)readBasesArray; - tc.hap = (char*)haplotypeBasesArray; - tc.q = (char*)readQualsArray; //TOASK - q is now char* - - compute_full_prob(&tc, g_double_dataholder.m_matchMatrix, g_double_dataholder.m_insertionMatrix, - g_double_dataholder.m_deletionMatrix, g_double_dataholder.m_transition, - doInitialization == JNI_TRUE, hapStartIndex, NULL); - - env->ReleaseByteArrayElements(readBases, readBasesArray, JNI_ABORT); - env->ReleaseByteArrayElements(haplotypeBases, haplotypeBasesArray, JNI_ABORT); - env->ReleaseByteArrayElements(readQuals, readQualsArray, JNI_ABORT); - return 0.0; -} - -JNIEXPORT jdouble JNICALL -Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniSubComputeReadLikelihoodGivenHaplotypeLog10( - JNIEnv* env, jobject thisObject, - jint readLength, jint haplotypeLength, - jbyteArray readBases, jbyteArray haplotypeBases, jbyteArray readQuals, - jbyteArray insertionGOP, jbyteArray deletionGOP, jbyteArray overallGCP, - jint hapStartIndex - ) -{ - jboolean is_copy = JNI_FALSE; - jbyte* readBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readBases, &is_copy); - jbyte* haplotypeBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(haplotypeBases, &is_copy); - jbyte* readQualsArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readQuals, &is_copy); - 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 - assert(readBasesArray && "readBasesArray not initialized in JNI"); - assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI"); - assert(readQualsArray && "readQualsArray not initialized in JNI"); - assert(insertionGOPArray && "insertionGOP array not initialized in JNI"); - assert(deletionGOPArray && "deletionGOP array not initialized in JNI"); - assert(overallGCPArray && "OverallGCP array not initialized in JNI"); - //assert(readLength < MROWS); -#endif - testcase tc; - tc.rslen = readLength; - tc.haplen = haplotypeLength; - tc.rs = (char*)readBasesArray; - tc.hap = (char*)haplotypeBasesArray; - for(unsigned i=0;i -/* Header for class org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM */ - -#ifndef _Included_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM -#define _Included_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM -#ifdef __cplusplus -extern "C" { -#endif -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_TRISTATE_CORRECTION -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_TRISTATE_CORRECTION 3.0 -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_dumpSandboxOnly -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_dumpSandboxOnly 0L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug 0L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_verify -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_verify 1L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug0_1 -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug0_1 0L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug1 -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug1 0L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug2 -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug2 0L -#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug3 -#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug3 0L -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM - * Method: jniInitialize - * Signature: (II)V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitialize - (JNIEnv *, jobject, jint, jint); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM - * Method: jniInitializeProbabilities - * Signature: ([[D[B[B[B)V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializeProbabilities - (JNIEnv *, jclass, jobjectArray, jbyteArray, jbyteArray, jbyteArray); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM - * Method: jniInitializePriorsAndUpdateCells - * Signature: (ZII[B[B[BI)D - */ -JNIEXPORT jdouble JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializePriorsAndUpdateCells - (JNIEnv *, jobject, jboolean, jint, jint, jbyteArray, jbyteArray, jbyteArray, jint); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM - * Method: jniSubComputeReadLikelihoodGivenHaplotypeLog10 - * Signature: (II[B[B[B[B[B[BI)D - */ -JNIEXPORT jdouble JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniSubComputeReadLikelihoodGivenHaplotypeLog10 - (JNIEnv *, jobject, jint, jint, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jint); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc deleted file mode 100644 index d9d268462..000000000 --- a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc +++ /dev/null @@ -1,416 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#include "headers.h" -#include "jni_common.h" -#include "org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h" -//#include "template.h" -#include "utils.h" -#include "LoadTimeInitializer.h" - -using namespace std; - -JNIEXPORT jlong JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniGetMachineType - (JNIEnv* env, jobject thisObject) -{ - return (jlong)get_machine_capabilities(); -} - -//Should be called only once for the whole Java process - initializes field ids for the classes JNIReadDataHolderClass -//and JNIHaplotypeDataHolderClass -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask - (JNIEnv* env, jobject thisObject, jclass readDataHolderClass, jclass haplotypeDataHolderClass, jlong mask) -{ - assert(readDataHolderClass); - assert(haplotypeDataHolderClass); - jfieldID fid; - fid = env->GetFieldID(readDataHolderClass, "readBases", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for readBases"); - g_load_time_initializer.m_readBasesFID = fid; - fid = env->GetFieldID(readDataHolderClass, "readQuals", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for readQuals"); - g_load_time_initializer.m_readQualsFID = fid; - fid = env->GetFieldID(readDataHolderClass, "insertionGOP", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for insertionGOP"); - g_load_time_initializer.m_insertionGOPFID = fid; - fid = env->GetFieldID(readDataHolderClass, "deletionGOP", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for deletionGOP"); - g_load_time_initializer.m_deletionGOPFID = fid; - fid = env->GetFieldID(readDataHolderClass, "overallGCP", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for overallGCP"); - g_load_time_initializer.m_overallGCPFID = fid; - - fid = env->GetFieldID(haplotypeDataHolderClass, "haplotypeBases", "[B"); - assert(fid && "JNI pairHMM: Could not get FID for haplotypeBases"); - g_load_time_initializer.m_haplotypeBasesFID = fid; - if(mask != ENABLE_ALL_HARDWARE_FEATURES) - { - cout << "Using user supplied hardware mask to re-initialize function pointers for PairHMM\n"; - initialize_function_pointers((uint64_t)mask); - cout.flush(); - } -} - -JNIEXPORT void JNICALL initializeHaplotypes - (JNIEnv * env, jobject& thisObject, jint numHaplotypes, jobjectArray& haplotypeDataArray, - vector >& haplotypeBasesArrayVector, vector& haplotypeBasesLengths) -{ - jboolean is_copy = JNI_FALSE; - haplotypeBasesArrayVector.clear(); - haplotypeBasesLengths.clear(); - haplotypeBasesArrayVector.resize(numHaplotypes); - haplotypeBasesLengths.resize(numHaplotypes); - jsize haplotypeBasesLength = 0; - for(unsigned j=0;jGetObjectArrayElement(haplotypeDataArray, j); - jbyteArray haplotypeBases = (jbyteArray)env->GetObjectField(haplotypeObject, g_load_time_initializer.m_haplotypeBasesFID); -#ifdef ENABLE_ASSERTIONS - assert(haplotypeBases && ("haplotypeBases is NULL at index : "+to_string(j)+"\n").c_str()); -#endif - //Need a global reference as this will be accessed across multiple JNI calls to JNIComputeLikelihoods() - jbyteArray haplotypeBasesGlobalRef = (jbyteArray)env->NewGlobalRef(haplotypeBases); -#ifdef ENABLE_ASSERTIONS - assert(haplotypeBasesGlobalRef && ("Could not get global ref to haplotypeBases at index : "+to_string(j)+"\n").c_str()); -#endif - env->DeleteLocalRef(haplotypeBases); //free the local reference - jbyte* haplotypeBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(haplotypeBasesGlobalRef, &is_copy); - haplotypeBasesLength = env->GetArrayLength(haplotypeBasesGlobalRef); -#ifdef ENABLE_ASSERTIONS - assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI"); - //assert(haplotypeBasesLength < MCOLS); -#endif -#ifdef DEBUG0_1 - cout << "JNI haplotype length "< >& haplotypeBasesArrayVector, vector& haplotypeBasesLengths - ) -{ - //Now release haplotype arrays - for(int j=haplotypeBasesArrayVector.size()-1;j>=0;--j) //note the order - reverse of GET - { - RELEASE_BYTE_ARRAY_ELEMENTS(haplotypeBasesArrayVector[j].first, haplotypeBasesArrayVector[j].second, JNI_RO_RELEASE_MODE); - env->DeleteGlobalRef(haplotypeBasesArrayVector[j].first); //free the global reference - } - haplotypeBasesArrayVector.clear(); - haplotypeBasesLengths.clear(); -} - - -vector > g_haplotypeBasesArrayVector; -vector g_haplotypeBasesLengths; -//Since the list of haplotypes against which the reads are evaluated in PairHMM is the same for a region, -//transfer the list only once -//Works only for ST case as the haplotype data is stored in global variables -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes - (JNIEnv * env, jobject thisObject, jint numHaplotypes, jobjectArray haplotypeDataArray) -{ -#ifdef SINGLE_THREADED_ONLY - //To ensure, GET_BYTE_ARRAY_ELEMENTS is invoked only once for each haplotype, store bytearrays in a vector - initializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray, g_haplotypeBasesArrayVector, g_haplotypeBasesLengths); -#endif -} - - -//Create a vector of testcases for computation - copy the references to bytearrays read/readQuals etc into the appropriate -//testcase struct -inline JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeTestcasesVector - (JNIEnv* env, jint numReads, jint numHaplotypes, jobjectArray& readDataArray, - vector > >& readBasesArrayVector, - vector >& haplotypeBasesArrayVector, vector& haplotypeBasesLengths, - vector& tc_array) -{ - jboolean is_copy = JNI_FALSE; - unsigned tc_idx = 0; - for(unsigned i=0;iGetObjectArrayElement(readDataArray, i); - jbyteArray readBases = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_readBasesFID); - jbyteArray insertionGOP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_insertionGOPFID); - jbyteArray deletionGOP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_deletionGOPFID); - 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 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()); - assert(overallGCP && ("overallGCP is NULL at index : "+to_string(i)+"\n").c_str()); - assert(readQuals && ("readQuals is NULL at index : "+to_string(i)+"\n").c_str()); -#endif - jsize readLength = env->GetArrayLength(readBases); - - jbyte* readBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readBases, &is_copy); //order of GET-RELEASE is important - jbyte* readQualsArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readQuals, &is_copy); - 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 DO_PROFILING - g_load_time_initializer.m_bytes_copied += (is_copy ? readLength*5 : 0); - g_load_time_initializer.update_stat(READ_LENGTH_IDX, readLength); -#endif -#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"); - assert(deletionGOPArray && "deletionGOP array not initialized in JNI"); - assert(overallGCPArray && "overallGCP array not initialized in JNI"); - //assert(readLength < MROWS); - assert(readLength == env->GetArrayLength(readQuals)); - assert(readLength == env->GetArrayLength(insertionGOP)); - assert(readLength == env->GetArrayLength(deletionGOP)); - assert(readLength == env->GetArrayLength(overallGCP)); -#endif -#ifdef DEBUG0_1 - cout << "JNI read length "<& tc_array, unsigned numTestCases, double* likelihoodDoubleArray, - unsigned maxNumThreadsToUse) -{ -#ifdef DO_REPEAT_PROFILING - for(unsigned i=0;i<10;++i) -#endif - { -#pragma omp parallel for schedule (dynamic,10000) num_threads(maxNumThreadsToUse) - for(unsigned tc_idx=0;tc_idx > >& readBasesArrayVector) -{ - //Release read arrays first - for(int i=readBasesArrayVector.size()-1;i>=0;--i)//note the order - reverse of GET - { - for(int j=readBasesArrayVector[i].size()-1;j>=0;--j) - RELEASE_BYTE_ARRAY_ELEMENTS(readBasesArrayVector[i][j].first, readBasesArrayVector[i][j].second, JNI_RO_RELEASE_MODE); - readBasesArrayVector[i].clear(); - } - readBasesArrayVector.clear(); -} - - -#ifdef DO_WARMUP -uint64_t g_sum = 0; -#endif -//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_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods - (JNIEnv* env, jobject thisObject, jint numReads, jint numHaplotypes, - jobjectArray readDataArray, jobjectArray haplotypeDataArray, jdoubleArray likelihoodArray, jint maxNumThreadsToUse) -{ -#ifdef DEBUG0_1 - cout << "JNI numReads "< tc_array; - tc_array.clear(); - tc_array.resize(numTestCases); - //Store read arrays for release later - vector > > readBasesArrayVector; - readBasesArrayVector.clear(); - readBasesArrayVector.resize(numReads); -#ifdef DUMP_TO_SANDBOX - g_load_time_initializer.open_sandbox(); -#endif -#ifdef DO_PROFILING - get_time(&start_time); -#endif - -#ifdef SINGLE_THREADED_ONLY - vector >& haplotypeBasesArrayVector = g_haplotypeBasesArrayVector; - vector& haplotypeBasesLengths = g_haplotypeBasesLengths; -#else - vector > l_haplotypeBasesArrayVector; - vector >& haplotypeBasesArrayVector = l_haplotypeBasesArrayVector; - vector l_haplotypeBasesLengths; - vector& haplotypeBasesLengths = l_haplotypeBasesLengths; - initializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray, haplotypeBasesArrayVector, haplotypeBasesLengths); -#endif - //Copy byte array references from Java memory into vector of testcase structs - Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeTestcasesVector(env, - numReads, numHaplotypes, readDataArray, readBasesArrayVector, haplotypeBasesArrayVector, haplotypeBasesLengths, tc_array); - -#ifdef DO_PROFILING - g_load_time_initializer.m_data_transfer_time += diff_time(start_time); -#endif - - //Get double array where results are stored (to pass back to java) - jdouble* likelihoodDoubleArray = (jdouble*)GET_DOUBLE_ARRAY_ELEMENTS(likelihoodArray, &is_copy); -#ifdef ENABLE_ASSERTIONS - assert(likelihoodDoubleArray && "likelihoodArray is NULL"); - assert(env->GetArrayLength(likelihoodArray) == numTestCases); -#endif -#ifdef DO_WARMUP //ignore - only for crazy profiling - for(unsigned i=0;iGetArrayLength(haplotypeBasesArrayVector[i].first); - for(unsigned j=0;jGetArrayLength(readBasesArrayVector[i][j].first); - for(unsigned k=0;k -/* Header for class org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM */ - -#ifndef _Included_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM -#define _Included_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM -#ifdef __cplusplus -extern "C" { -#endif -#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_TRISTATE_CORRECTION -#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_TRISTATE_CORRECTION 3.0 -#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse41Mask -#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse41Mask 1LL -#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse42Mask -#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse42Mask 2LL -#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_avxMask -#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_avxMask 4LL -#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_enableAll -#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_enableAll -1LL -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniGetMachineType - * Signature: ()J - */ -JNIEXPORT jlong JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniGetMachineType - (JNIEnv *, jobject); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniInitializeClassFieldsAndMachineMask - * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask - (JNIEnv *, jobject, jclass, jclass, jlong); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniInitializeHaplotypes - * Signature: (I[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIHaplotypeDataHolderClass;)V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes - (JNIEnv *, jobject, jint, jobjectArray); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniFinalizeRegion - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniFinalizeRegion - (JNIEnv *, jobject); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniComputeLikelihoods - * Signature: (II[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIReadDataHolderClass;[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIHaplotypeDataHolderClass;[DI)V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods - (JNIEnv *, jobject, jint, jint, jobjectArray, jobjectArray, jdoubleArray, jint); - -/* - * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM - * Method: jniClose - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniClose - (JNIEnv *, jobject); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc b/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc deleted file mode 100644 index 20e9910a6..000000000 --- a/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc +++ /dev/null @@ -1,65 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "headers.h" -#include "utils.h" -#include "LoadTimeInitializer.h" -using namespace std; - -int main(int argc, char** argv) -{ - if(argc < 2) - { - cerr << "Needs path to input file as argument\n"; - exit(0); - } - bool use_old_read_testcase = false; - if(argc >= 3 && string(argv[2]) == "1") - use_old_read_testcase = true; - unsigned chunk_size = 10000; - bool do_check = true; - uint64_t mask = ~(0ull); - for(int i=3;i -#include -#include - - -void CONCAT(CONCAT(precompute_masks_,SIMD_ENGINE), PRECISION)(const testcase& tc, int COLS, int numMaskVecs, MASK_TYPE (*maskArr)[NUM_DISTINCT_CHARS]) { - - const int maskBitCnt = MAIN_TYPE_SIZE ; - - for (int vi=0; vi < numMaskVecs; ++vi) { - for (int rs=0; rs < NUM_DISTINCT_CHARS; ++rs) { - maskArr[vi][rs] = 0 ; - } - maskArr[vi][AMBIG_CHAR] = MASK_ALL_ONES ; - } - - for (int col=1; col < COLS; ++col) { - int mIndex = (col-1) / maskBitCnt ; - int mOffset = (col-1) % maskBitCnt ; - MASK_TYPE bitMask = ((MASK_TYPE)0x1) << (maskBitCnt-1-mOffset) ; - - char hapChar = ConvertChar::get(tc.hap[col-1]); - - if (hapChar == AMBIG_CHAR) { - for (int ci=0; ci < NUM_DISTINCT_CHARS; ++ci) - maskArr[mIndex][ci] |= bitMask ; - } - - maskArr[mIndex][hapChar] |= bitMask ; - // bit corresponding to col 1 will be the MSB of the mask 0 - // bit corresponding to col 2 will be the MSB-1 of the mask 0 - // ... - // bit corresponding to col 32 will be the LSB of the mask 0 - // bit corresponding to col 33 will be the MSB of the mask 1 - // ... - } - -} - -void CONCAT(CONCAT(init_masks_for_row_,SIMD_ENGINE), PRECISION)(const testcase& tc, char* rsArr, MASK_TYPE* lastMaskShiftOut, int beginRowIndex, int numRowsToProcess) { - - for (int ri=0; ri < numRowsToProcess; ++ri) { - rsArr[ri] = ConvertChar::get(tc.rs[ri+beginRowIndex-1]) ; - } - - for (int ei=0; ei < AVX_LENGTH; ++ei) { - lastMaskShiftOut[ei] = 0 ; - } -} - -#define SET_MASK_WORD(__dstMask, __srcMask, __lastShiftOut, __shiftBy, __maskBitCnt){ \ - MASK_TYPE __bitMask = (((MASK_TYPE)0x1) << __shiftBy) - 1 ; \ - MASK_TYPE __nextShiftOut = (__srcMask & __bitMask) << (__maskBitCnt - __shiftBy) ; \ - __dstMask = (__srcMask >> __shiftBy) | __lastShiftOut ; \ - __lastShiftOut = __nextShiftOut ; \ -} - - -void CONCAT(CONCAT(update_masks_for_cols_,SIMD_ENGINE), PRECISION)(int maskIndex, BITMASK_VEC& bitMaskVec, MASK_TYPE (*maskArr) [NUM_DISTINCT_CHARS], char* rsArr, MASK_TYPE* lastMaskShiftOut, int maskBitCnt) { - - for (int ei=0; ei < AVX_LENGTH/2; ++ei) { - SET_MASK_WORD(bitMaskVec.getLowEntry(ei), maskArr[maskIndex][rsArr[ei]], - lastMaskShiftOut[ei], ei, maskBitCnt) ; - - int ei2 = ei + AVX_LENGTH/2 ; // the second entry index - SET_MASK_WORD(bitMaskVec.getHighEntry(ei), maskArr[maskIndex][rsArr[ei2]], - lastMaskShiftOut[ei2], ei2, maskBitCnt) ; - } - -} - - -inline void CONCAT(CONCAT(computeDistVec,SIMD_ENGINE), PRECISION) (BITMASK_VEC& bitMaskVec, SIMD_TYPE& distm, SIMD_TYPE& _1_distm, SIMD_TYPE& distmChosen) { - - distmChosen = VEC_BLENDV(distm, _1_distm, bitMaskVec.getCombinedMask()) ; - - bitMaskVec.shift_left_1bit() ; -} - -/* - * This function: - * 1- Intializes probability values p_MM, p_XX, P_YY, p_MX, p_GAPM and pack them into vectors (SSE or AVX) - * 2- Precompute parts of "distm" which only depeneds on a row number and pack it into vector - */ - -template void CONCAT(CONCAT(initializeVectors,SIMD_ENGINE), PRECISION)(int ROWS, int COLS, NUMBER* shiftOutM, NUMBER *shiftOutX, NUMBER *shiftOutY, Context ctx, testcase *tc, SIMD_TYPE *p_MM, SIMD_TYPE *p_GAPM, SIMD_TYPE *p_MX, SIMD_TYPE *p_XX, SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, SIMD_TYPE *distm1D) -{ - NUMBER zero = ctx._(0.0); - NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen); - for (int s=0;si[r-1] & 127; - int _d = tc->d[r-1] & 127; - int _c = tc->c[r-1] & 127; - - //*(ptr_p_MM+r-1) = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127]; - SET_MATCH_TO_MATCH_PROB(*(ptr_p_MM+r-1), _i, _d); - *(ptr_p_GAPM+r-1) = ctx._(1.0) - ctx.ph2pr[_c]; - *(ptr_p_MX+r-1) = ctx.ph2pr[_i]; - *(ptr_p_XX+r-1) = ctx.ph2pr[_c]; - *(ptr_p_MY+r-1) = ctx.ph2pr[_d]; - *(ptr_p_YY+r-1) = ctx.ph2pr[_c]; - } - - NUMBER *ptr_distm1D = (NUMBER *)distm1D; - for (int r = 1; r < ROWS; r++) - { - int _q = tc->q[r-1] & 127; - ptr_distm1D[r-1] = ctx.ph2pr[_q]; - } -} - -/* - * This function handles pre-stripe computation: - * 1- Retrieve probaility vectors from memory - * 2- Initialize M, X, Y vectors with all 0's (for the first stripe) and shifting the last row from previous stripe for the rest - */ - -template inline void CONCAT(CONCAT(stripeINITIALIZATION,SIMD_ENGINE), PRECISION)( - int stripeIdx, Context ctx, testcase *tc, SIMD_TYPE &pGAPM, SIMD_TYPE &pMM, SIMD_TYPE &pMX, SIMD_TYPE &pXX, SIMD_TYPE &pMY, SIMD_TYPE &pYY, - SIMD_TYPE &rs, UNION_TYPE &rsN, SIMD_TYPE &distm, SIMD_TYPE &_1_distm, SIMD_TYPE *distm1D, SIMD_TYPE N_packed256, SIMD_TYPE *p_MM , SIMD_TYPE *p_GAPM , - SIMD_TYPE *p_MX, SIMD_TYPE *p_XX , SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, UNION_TYPE &M_t_2, UNION_TYPE &X_t_2, UNION_TYPE &M_t_1, UNION_TYPE &X_t_1, - UNION_TYPE &Y_t_2, UNION_TYPE &Y_t_1, UNION_TYPE &M_t_1_y, NUMBER* shiftOutX, NUMBER* shiftOutM) -{ - int i = stripeIdx; - pGAPM = p_GAPM[i]; - pMM = p_MM[i]; - pMX = p_MX[i]; - pXX = p_XX[i]; - pMY = p_MY[i]; - pYY = p_YY[i]; - - NUMBER zero = ctx._(0.0); - NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen); - UNION_TYPE packed1; packed1.d = VEC_SET1_VAL(1.0); - UNION_TYPE packed3; packed3.d = VEC_SET1_VAL(3.0); - - distm = distm1D[i]; - _1_distm = VEC_SUB(packed1.d, distm); - - distm = VEC_DIV(distm, packed3.d); - - /* initialize M_t_2, M_t_1, X_t_2, X_t_1, Y_t_2, Y_t_1 */ - M_t_2.d = VEC_SET1_VAL(zero); - X_t_2.d = VEC_SET1_VAL(zero); - - if (i==0) { - M_t_1.d = VEC_SET1_VAL(zero); - X_t_1.d = VEC_SET1_VAL(zero); - Y_t_2.d = VEC_SET_LSE(init_Y); - Y_t_1.d = VEC_SET1_VAL(zero); - } - else { - X_t_1.d = VEC_SET_LSE(shiftOutX[AVX_LENGTH]); - M_t_1.d = VEC_SET_LSE(shiftOutM[AVX_LENGTH]); - Y_t_2.d = VEC_SET1_VAL(zero); - Y_t_1.d = VEC_SET1_VAL(zero); - } - M_t_1_y = M_t_1; -} - -/* - * This function is the main compute kernel to compute M, X and Y - */ - -inline void CONCAT(CONCAT(computeMXY,SIMD_ENGINE), PRECISION)(UNION_TYPE &M_t, UNION_TYPE &X_t, UNION_TYPE &Y_t, UNION_TYPE &M_t_y, - UNION_TYPE M_t_2, UNION_TYPE X_t_2, UNION_TYPE Y_t_2, UNION_TYPE M_t_1, UNION_TYPE X_t_1, UNION_TYPE M_t_1_y, UNION_TYPE Y_t_1, - SIMD_TYPE pMM, SIMD_TYPE pGAPM, SIMD_TYPE pMX, SIMD_TYPE pXX, SIMD_TYPE pMY, SIMD_TYPE pYY, SIMD_TYPE distmSel) -{ - /* Compute M_t <= distm * (p_MM*M_t_2 + p_GAPM*X_t_2 + p_GAPM*Y_t_2) */ - M_t.d = VEC_MUL(VEC_ADD(VEC_ADD(VEC_MUL(M_t_2.d, pMM), VEC_MUL(X_t_2.d, pGAPM)), VEC_MUL(Y_t_2.d, pGAPM)), distmSel); - //M_t.d = VEC_MUL( VEC_ADD(VEC_MUL(M_t_2.d, pMM), VEC_MUL(VEC_ADD(X_t_2.d, Y_t_2.d), pGAPM)), distmSel); - - M_t_y = M_t; - - /* Compute X_t */ - X_t.d = VEC_ADD(VEC_MUL(M_t_1.d, pMX) , VEC_MUL(X_t_1.d, pXX)); - - /* Compute Y_t */ - Y_t.d = VEC_ADD(VEC_MUL(M_t_1_y.d, pMY) , VEC_MUL(Y_t_1.d, pYY)); -} - -/* - * This is the main compute function. It operates on the matrix in s stripe manner. - * The stripe height is determined by the SIMD engine type. - * Stripe height: "AVX float": 8, "AVX double": 4, "SSE float": 4, "SSE double": 2 - * For each stripe the operations are anti-diagonal based. - * Each anti-diagonal (M_t, Y_t, X_t) depends on the two previous anti-diagonals (M_t_2, X_t_2, Y_t_2, M_t_1, X_t_1, Y_t_1). - * Each stripe (except the fist one) depends on the last row of the previous stripe. - * The last stripe computation handles the addition of the last row of M and X, that's the reason for loop spliting. - */ - -template NUMBER CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), PRECISION) (testcase *tc, NUMBER *before_last_log = NULL) -{ - int ROWS = tc->rslen + 1; - int COLS = tc->haplen + 1; - int MAVX_COUNT = (ROWS+AVX_LENGTH-1)/AVX_LENGTH; - - /* Probaility arrays */ - SIMD_TYPE p_MM [MAVX_COUNT], p_GAPM [MAVX_COUNT], p_MX [MAVX_COUNT]; - SIMD_TYPE p_XX [MAVX_COUNT], p_MY [MAVX_COUNT], p_YY [MAVX_COUNT]; - - /* For distm precomputation */ - SIMD_TYPE distm1D[MAVX_COUNT]; - - /* Carries the values from each stripe to the next stripe */ - NUMBER shiftOutM[ROWS+COLS+AVX_LENGTH], shiftOutX[ROWS+COLS+AVX_LENGTH], shiftOutY[ROWS+COLS+AVX_LENGTH]; - - /* The vector to keep the anti-diagonals of M, X, Y*/ - /* Current: M_t, X_t, Y_t */ - /* Previous: M_t_1, X_t_1, Y_t_1 */ - /* Previous to previous: M_t_2, X_t_2, Y_t_2 */ - UNION_TYPE M_t, M_t_1, M_t_2, X_t, X_t_1, X_t_2, Y_t, Y_t_1, Y_t_2, M_t_y, M_t_1_y; - - /* Probality vectors */ - SIMD_TYPE pGAPM, pMM, pMX, pXX, pMY, pYY; - - struct timeval start, end; - NUMBER result_avx2; - Context ctx; - UNION_TYPE rs , rsN; - HAP_TYPE hap; - SIMD_TYPE distmSel, distmChosen ; - SIMD_TYPE distm, _1_distm; - - int r, c; - NUMBER zero = ctx._(0.0); - UNION_TYPE packed1; packed1.d = VEC_SET1_VAL(1.0); - SIMD_TYPE N_packed256 = VEC_POPCVT_CHAR('N'); - NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen); - int remainingRows = (ROWS-1) % AVX_LENGTH; - int stripe_cnt = ((ROWS-1) / AVX_LENGTH) + (remainingRows!=0); - - const int maskBitCnt = MAIN_TYPE_SIZE ; - const int numMaskVecs = (COLS+ROWS+maskBitCnt-1)/maskBitCnt ; // ceil function - - /* Mask precomputation for distm*/ - MASK_TYPE maskArr[numMaskVecs][NUM_DISTINCT_CHARS] ; - CONCAT(CONCAT(precompute_masks_,SIMD_ENGINE), PRECISION)(*tc, COLS, numMaskVecs, maskArr) ; - - char rsArr[AVX_LENGTH] ; - MASK_TYPE lastMaskShiftOut[AVX_LENGTH] ; - - /* Precompute initialization for probabilities and shift vector*/ - CONCAT(CONCAT(initializeVectors,SIMD_ENGINE), PRECISION)(ROWS, COLS, shiftOutM, shiftOutX, shiftOutY, - ctx, tc, p_MM, p_GAPM, p_MX, p_XX, p_MY, p_YY, distm1D); - - for (int i=0;i(&tc[b]); - -#ifdef RUN_HYBRID -#define MIN_ACCEPTED 1e-28f - if (result_avxf < MIN_ACCEPTED) { - count++; - result_avxd = CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), d)(&tc[b]); - result[b] = log10(result_avxd) - log10(ldexp(1.0, 1020.f)); - } - else - result[b] = log10f(result_avxf) - log10f(ldexpf(1.f, 120.f)); -#endif - -#ifndef RUN_HYBRID - result[b] = log10f(result_avxf) - log10f(ldexpf(1.f, 120.f)); -#endif - } - aggregateTimeCompute += (getCurrClk() - lastClk) ; - lastClk = getCurrClk() ; - for (int b=0;b(testcase* tc, double* nextlog); -template float compute_full_prob_sses(testcase* tc, float* nextlog); diff --git a/public/VectorPairHMM/src/main/c++/template.h b/public/VectorPairHMM/src/main/c++/template.h deleted file mode 100644 index 550e76396..000000000 --- a/public/VectorPairHMM/src/main/c++/template.h +++ /dev/null @@ -1,119 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#ifndef TEMPLATES_H_ -#define TEMPLATES_H_ - -#include "headers.h" - - -#define ALIGNED __attribute__((aligned(32))) - -#ifdef SIMD_ENGINE_AVX -typedef union __attribute__((aligned(32))) { - ALIGNED __m256 ALIGNED d; - ALIGNED __m128i ALIGNED s[2]; - ALIGNED float ALIGNED f[8]; - ALIGNED __m256i ALIGNED i; -} ALIGNED mix_F ALIGNED; -#endif - -typedef union __attribute__((aligned(32))) { - ALIGNED __m128 ALIGNED d; - ALIGNED __m64 ALIGNED s[2]; - ALIGNED float ALIGNED f[4]; - ALIGNED __m128i ALIGNED i; -} ALIGNED mix_F128 ALIGNED; - -typedef union ALIGNED { - __m128i vec ; - __m128 vecf ; - uint32_t masks[4] ; -} MaskVec_F ; - -typedef union ALIGNED { - __m64 vec ; - __m64 vecf ; - uint32_t masks[2] ; -} MaskVec_F128 ; - -typedef union ALIGNED -{ - ALIGNED __m128i ALIGNED i; - ALIGNED __m128 ALIGNED f; -} ALIGNED IF_128f ALIGNED; - -typedef union ALIGNED -{ - ALIGNED int ALIGNED i; - ALIGNED float ALIGNED f; -} ALIGNED IF_32 ALIGNED; - -#ifdef SIMD_ENGINE_AVX -typedef union __attribute__((aligned(32))) { - ALIGNED __m256d ALIGNED d; - ALIGNED __m128i ALIGNED s[2]; - ALIGNED double ALIGNED f[4]; - ALIGNED __m256i ALIGNED i; -} ALIGNED mix_D ALIGNED; -#endif - -typedef union __attribute__((aligned(32))) { - ALIGNED __m128d ALIGNED d; - ALIGNED __m64 ALIGNED s[2]; - ALIGNED double ALIGNED f[2]; - ALIGNED __m128i ALIGNED i; -} ALIGNED mix_D128 ALIGNED; - -typedef union ALIGNED { - __m128i vec ; - __m128d vecf ; - uint64_t masks[2] ; -} MaskVec_D ; - -typedef union ALIGNED { - __m64 vec ; - __m64 vecf ; - uint64_t masks[1] ; -} MaskVec_D128 ; - -typedef union ALIGNED -{ - ALIGNED __m128i ALIGNED i; - ALIGNED __m128d ALIGNED f; -} ALIGNED IF_128d ALIGNED; - -typedef union ALIGNED -{ - ALIGNED int64_t ALIGNED i; - ALIGNED double ALIGNED f; -} ALIGNED IF_64 ALIGNED; - - -#include "common_data_structure.h" - -#endif - - diff --git a/public/VectorPairHMM/src/main/c++/utils.cc b/public/VectorPairHMM/src/main/c++/utils.cc deleted file mode 100644 index 89bd975ae..000000000 --- a/public/VectorPairHMM/src/main/c++/utils.cc +++ /dev/null @@ -1,567 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include "headers.h" -#include "utils.h" -#include "LoadTimeInitializer.h" -using namespace std; - -//static members from ConvertChar -uint8_t ConvertChar::conversionTable[255]; -//Global function pointers in utils.h -float (*g_compute_full_prob_float)(testcase *tc, float* before_last_log) = 0; -double (*g_compute_full_prob_double)(testcase *tc, double* before_last_log) = 0; -//Static members in ContextBase -template<> -bool ContextBase::staticMembersInitializedFlag = false; -template<> -double ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { }; -template<> -double ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { }; -template<> -bool ContextBase::staticMembersInitializedFlag = false; -template<> -float ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { }; -template<> -float ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { }; - - -bool search_file_for_string(string filename, string search_string) -{ - ifstream fptr; - fptr.open(filename.c_str(),ios::in); - if(fptr.is_open()) - { - string buffer; - buffer.clear(); - buffer.resize(4096); - bool retvalue = false; - while(!fptr.eof()) - { - fptr.getline(&(buffer[0]), 4096); - if(buffer.find(search_string) != string::npos) //found string - { - retvalue = true; - break; - } - } - buffer.clear(); - fptr.close(); - return retvalue; - } - else - return false; -} - -bool is_cpuid_ecx_bit_set(int eax, int bitidx) -{ - int ecx = 0, edx = 0, ebx = 0; - __asm__ ("cpuid" - :"=b" (ebx), - "=c" (ecx), - "=d" (edx) - :"a" (eax) - ); - return (((ecx >> bitidx)&1) == 1); -} - -bool is_avx_supported() -{ -#ifdef __INTEL_COMPILER - bool use_avx = _may_i_use_cpu_feature(_FEATURE_AVX); - if(use_avx) - return true; - else - { - //check if core supports AVX, but kernel does not and print info message - if(!is_cpuid_ecx_bit_set(1, 28)) //core does not support AVX - return false; - //else fall through to end of function - } -#else - if(!__builtin_cpu_supports("avx")) //core does not support AVX - return false; - else - { - //core supports AVX, check if kernel supports - if(search_file_for_string("/proc/cpuinfo","avx")) - return true; - //else fall through to end of function - - } -#endif //__INTEL_COMPILER - clog << "INFO: Your CPU supports AVX vector instructions, but your kernel does not. Try upgrading to a kernel that supports AVX.\n"; - clog << "INFO: Your program will run correctly, but slower than the AVX version\n"; - return false; -} - -bool is_sse41_supported() -{ -#ifdef __INTEL_COMPILER - return (_may_i_use_cpu_feature(_FEATURE_SSE4_1) > 0); -#else - return __builtin_cpu_supports("sse4.1"); -#endif - //return is_cpuid_ecx_bit_set(1, 19); -} - -bool is_sse42_supported() -{ -#ifdef __INTEL_COMPILER - return (_may_i_use_cpu_feature(_FEATURE_SSE4_2) > 0); -#else - return __builtin_cpu_supports("sse4.2"); -#endif - //return is_cpuid_ecx_bit_set(1, 20); -} - -uint64_t get_machine_capabilities() -{ - uint64_t machine_mask = 0ull; - if(is_avx_supported()) - machine_mask |= (1 << AVX_CUSTOM_IDX); - if(is_sse42_supported()) - machine_mask |= (1 << SSE42_CUSTOM_IDX); - if(is_sse41_supported()) - machine_mask |= (1 << SSE41_CUSTOM_IDX); - return machine_mask; -} - -void initialize_function_pointers(uint64_t mask) -{ - //mask = 0ull; - //mask = (1 << SSE41_CUSTOM_IDX); - if(is_avx_supported() && (mask & (1<< AVX_CUSTOM_IDX))) - { - cerr << "Using AVX accelerated implementation of PairHMM\n"; - g_compute_full_prob_float = compute_full_prob_avxs; - g_compute_full_prob_double = compute_full_prob_avxd; - } - else - if(is_sse41_supported() && (mask & ((1<< SSE41_CUSTOM_IDX) | (1<; - g_compute_full_prob_double = compute_full_prob_ssed; - } - else - { - cerr << "Using un-vectorized C++ implementation of PairHMM\n"; - g_compute_full_prob_float = compute_full_prob; - g_compute_full_prob_double = compute_full_prob; - } -} - -int normalize(char c) -{ - return ((int) (c - 33)); -} - -int read_testcase(testcase *tc, FILE* ifp) -{ - char *q, *i, *d, *c, *line = NULL; - int _q, _i, _d, _c; - int x, size = 0; - ssize_t read; - - - read = getline(&line, (size_t *) &size, ifp == 0 ? stdin : ifp); - if (read == -1) - { - free(line); - return -1; - } - - - tc->hap = (char *) malloc(size); - tc->rs = (char *) malloc(size); - q = (char *) malloc(size); - i = (char *) malloc(size); - d = (char *) malloc(size); - c = (char *) malloc(size); - - if (sscanf(line, "%s %s %s %s %s %s\n", tc->hap, tc->rs, q, i, d, c) != 6) - return -1; - - - tc->haplen = strlen(tc->hap); - tc->rslen = strlen(tc->rs); - assert(strlen(q) == (size_t)tc->rslen); - assert(strlen(i) == (size_t)tc->rslen); - assert(strlen(d) == (size_t)tc->rslen); - assert(strlen(c) == (size_t)tc->rslen); - - g_load_time_initializer.update_stat(READ_LENGTH_IDX, tc->rslen); - g_load_time_initializer.update_stat(HAPLOTYPE_LENGTH_IDX, tc->haplen); - g_load_time_initializer.update_stat(PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX, tc->haplen*tc->rslen); - //assert(tc->rslen < MROWS); - //tc->ihap = (int *) malloc(tc->haplen*sizeof(int)); - //tc->irs = (int *) malloc(tc->rslen*sizeof(int)); - - tc->q = (char *) malloc(sizeof(char) * tc->rslen); - tc->i = (char *) malloc(sizeof(char) * tc->rslen); - tc->d = (char *) malloc(sizeof(char) * tc->rslen); - tc->c = (char *) malloc(sizeof(char) * tc->rslen); - - for (x = 0; x < tc->rslen; x++) - { - _q = normalize(q[x]); - _i = normalize(i[x]); - _d = normalize(d[x]); - _c = normalize(c[x]); - tc->q[x] = (_q < 6) ? 6 : _q; - //tc->q[x] = _q; - tc->i[x] = _i; - tc->d[x] = _d; - tc->c[x] = _c; - //tc->irs[x] = tc->rs[x]; - } - //for (x = 0; x < tc->haplen; x++) - //tc->ihap[x] = tc->hap[x]; - - free(q); - free(i); - free(d); - free(c); - free(line); - - - - return 0; -} - -unsigned MAX_LINE_LENGTH = 65536; -int convToInt(std::string s) -{ - int i; - std::istringstream strin(s); - strin >> i; - return i; -} - -void tokenize(std::ifstream& fptr, std::vector& tokens) -{ - int i = 0; - std::string tmp; - std::vector myVec; - vector line; - line.clear(); - line.resize(MAX_LINE_LENGTH); - vector tmpline; - tmpline.clear(); - tmpline.resize(MAX_LINE_LENGTH); - myVec.clear(); - - while(!fptr.eof()) - { - i = 0; - bool still_read_line = true; - unsigned line_position = 0; - while(still_read_line) - { - fptr.getline(&(tmpline[0]), MAX_LINE_LENGTH); - if(line_position + MAX_LINE_LENGTH > line.size()) - line.resize(2*line.size()); - for(unsigned i=0;i> std::skipws >> tmp; - if(tmp != "") - { - myVec.push_back(tmp); - ++i; - //std::cerr < 0) - break; - } - tokens.clear(); - //std::cerr << "Why "< tokens; - tokens.clear(); - tokenize(fptr, tokens); - if(tokens.size() == 0) - return -1; - tc->hap = new char[tokens[0].size()+2]; - tc->haplen = tokens[0].size(); - memcpy(tc->hap, tokens[0].c_str(), tokens[0].size()); - tc->rs = new char[tokens[1].size()+2]; - tc->rslen = tokens[1].size(); - tc->q = new char[tc->rslen]; - tc->i = new char[tc->rslen]; - tc->d = new char[tc->rslen]; - tc->c = new char[tc->rslen]; - //cerr << "Lengths "<haplen <<" "<rslen<<"\n"; - memcpy(tc->rs, tokens[1].c_str(),tokens[1].size()); - assert(tokens.size() == (size_t)(2 + 4*(tc->rslen))); - //assert(tc->rslen < MROWS); - for(int j=0;jrslen;++j) - tc->q[j] = (char)convToInt(tokens[2+0*tc->rslen+j]); - for(int j=0;jrslen;++j) - tc->i[j] = (char)convToInt(tokens[2+1*tc->rslen+j]); - for(int j=0;jrslen;++j) - tc->d[j] = (char)convToInt(tokens[2+2*tc->rslen+j]); - for(int j=0;jrslen;++j) - tc->c[j] = (char)convToInt(tokens[2+3*tc->rslen+j]); - - if(reformat) - { - ofstream ofptr; - ofptr.open("reformat/debug_dump.txt",first_call ? ios::out : ios::app); - assert(ofptr.is_open()); - ofptr << tokens[0] << " "; - ofptr << tokens[1] << " "; - for(int j=0;jrslen;++j) - ofptr << ((char)(tc->q[j]+33)); - ofptr << " "; - for(int j=0;jrslen;++j) - ofptr << ((char)(tc->i[j]+33)); - ofptr << " "; - for(int j=0;jrslen;++j) - ofptr << ((char)(tc->d[j]+33)); - ofptr << " "; - for(int j=0;jrslen;++j) - ofptr << ((char)(tc->c[j]+33)); - ofptr << " 0 false\n"; - - ofptr.close(); - first_call = false; - } - - - return tokens.size(); -} - -double getCurrClk() { - struct timeval tv ; - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; -} - -inline unsigned long long rdtsc(void) -{ - unsigned hi, lo; - __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); - return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); -} - -void get_time(struct timespec* store_struct) -{ - clock_gettime(CLOCK_REALTIME, store_struct); -} - -uint64_t diff_time(struct timespec& prev_time) -{ - struct timespec curr_time; - clock_gettime(CLOCK_REALTIME, &curr_time); - return (uint64_t)((curr_time.tv_sec-prev_time.tv_sec)*1000000000+(curr_time.tv_nsec-prev_time.tv_nsec)); -} - - -#ifdef USE_PAPI -#include "papi.h" -#define NUM_PAPI_COUNTERS 4 -#endif - -void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, bool do_check) -{ - FILE* fptr = 0; - ifstream ifptr; - if(use_old_read_testcase) - { - fptr = fopen(filename,"r"); - assert(fptr); - } - else - { - ifptr.open(filename); - assert(ifptr.is_open()); - } -#ifdef PRINT_PER_INTERVAL_TIMINGS - ofstream times_fptr; - times_fptr.open("native_timed_intervals.csv",ios::out); -#endif - vector tc_vector; - tc_vector.clear(); - testcase tc; - uint64_t vector_compute_time = 0; - uint64_t baseline_compute_time = 0; - uint64_t num_double_calls = 0; - unsigned num_testcases = 0; - bool all_ok = do_check ? true : false; -#ifdef USE_PAPI - uint32_t all_mask = (0); - uint32_t no_usr_mask = (1 << 16); //bit 16 user mode, bit 17 kernel mode - uint32_t no_kernel_mask = (1 << 17); //bit 16 user mode, bit 17 kernel mode - PAPI_num_counters(); - int events[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; - char* eventnames[NUM_PAPI_COUNTERS]= { "cycles", "l1_pending_miss", "lfb_hit", "l2_hit" }; - assert(PAPI_event_name_to_code("UNHALTED_REFERENCE_CYCLES:u=1:k=1",&(events[0])) == PAPI_OK); - assert(PAPI_event_name_to_code("L1D_PEND_MISS:OCCURRENCES", &(events[1])) == PAPI_OK); - assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:HIT_LFB", &(events[2])) == PAPI_OK); - assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:L2_HIT", &(events[3])) == PAPI_OK); - long long values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; - long long accum_values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; -#endif - while(1) - { - int break_value = use_old_read_testcase ? read_testcase(&tc, fptr) : read_mod_testcase(ifptr,&tc,true); - if(break_value >= 0) - tc_vector.push_back(tc); - if(tc_vector.size() == BATCH_SIZE || (break_value < 0 && tc_vector.size() > 0)) - { - vector results_vec; - vector baseline_results_vec; - results_vec.clear(); - baseline_results_vec.clear(); - results_vec.resize(tc_vector.size()); - baseline_results_vec.resize(tc_vector.size()); - g_load_time_initializer.update_stat(NUM_TESTCASES_IDX, tc_vector.size()); - g_load_time_initializer.update_stat(NUM_READS_IDX, tc_vector.size()); - g_load_time_initializer.update_stat(NUM_HAPLOTYPES_IDX, tc_vector.size()); - struct timespec start_time; -#ifdef USE_PAPI - assert(PAPI_start_counters(events, NUM_PAPI_COUNTERS) == PAPI_OK); -#endif - get_time(&start_time); -#pragma omp parallel for schedule(dynamic,chunk_size) num_threads(12) -#ifdef DO_REPEAT_PROFILING - for(unsigned z=0;z<10;++z) -#endif - { - for(unsigned i=0;i(&tc); - baseline_result = log10(baseline_result) - log10(ldexp(1.0, 1020.0)); - baseline_results_vec[i] = baseline_result; - } - baseline_compute_time += diff_time(start_time); - for(unsigned i=0;i 1e-5 && rel_error > 1e-5) - { - cerr << std::scientific << baseline_result << " "< -std::string to_string(T obj) -{ - std::stringstream ss; - std::string ret_string; - ss.clear(); - ss << std::scientific << obj; - ss >> ret_string; - ss.clear(); - return ret_string; -} -void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline=true); - -int read_mod_testcase(std::ifstream& fptr, testcase* tc, bool reformat=false); - -bool is_avx_supported(); -bool is_sse42_supported(); -extern float (*g_compute_full_prob_float)(testcase *tc, float *before_last_log); -extern double (*g_compute_full_prob_double)(testcase *tc, double* before_last_log); -void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline); -template -NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log=0); -template -NUMBER compute_full_prob_avxd(testcase *tc, NUMBER *before_last_log=0); -template -NUMBER compute_full_prob_avxs(testcase *tc, NUMBER *before_last_log=0); -template -NUMBER compute_full_prob_ssed(testcase *tc, NUMBER *before_last_log=0); -template -NUMBER compute_full_prob_sses(testcase *tc, NUMBER *before_last_log=0); - -double getCurrClk(); -void get_time(struct timespec* x); -uint64_t diff_time(struct timespec& prev_time); - -//bit 0 is sse4.2, bit 1 is AVX -enum ProcessorCapabilitiesEnum -{ - SSE41_CUSTOM_IDX=0, - SSE42_CUSTOM_IDX, - AVX_CUSTOM_IDX -}; -#define ENABLE_ALL_HARDWARE_FEATURES 0xFFFFFFFFFFFFFFFFull -uint64_t get_machine_capabilities(); -void initialize_function_pointers(uint64_t mask=ENABLE_ALL_HARDWARE_FEATURES); -void do_compute(char* filename, bool use_old_read_testcase=true, unsigned chunk_size=10000, bool do_check=true); - -//#define DO_WARMUP -//#define DO_REPEAT_PROFILING -/*#define DUMP_COMPUTE_VALUES 1*/ -#define BATCH_SIZE 10000 -#define RUN_HYBRID -/*#define PRINT_PER_INTERVAL_TIMINGS 1*/ - -#endif diff --git a/public/gatk-root/pom.xml b/public/gatk-root/pom.xml index 96481ce57..d2ecf972b 100644 --- a/public/gatk-root/pom.xml +++ b/public/gatk-root/pom.xml @@ -89,7 +89,7 @@ com.intel.gkl gkl - 0.4.3 + 0.5.2 log4j diff --git a/public/gatk-tools-public/pom.xml b/public/gatk-tools-public/pom.xml index 8ee7cf4d3..9613e61c7 100644 --- a/public/gatk-tools-public/pom.xml +++ b/public/gatk-tools-public/pom.xml @@ -29,6 +29,11 @@ commons-jexl + + com.intel.gkl + gkl + + ${project.groupId} gatk-utils diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java index 697777408..fcad408c6 100644 --- a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java +++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java @@ -62,39 +62,16 @@ public abstract class PairHMM { LOGLESS_CACHING, /* Optimized AVX implementation of LOGLESS_CACHING called through JNI */ VECTOR_LOGLESS_CACHING, + /* Optimized, multi-threaded AVX implementation of LOGLESS_CACHING called through JNI */ + VECTOR_LOGLESS_CACHING_OMP, + /* Use fastest available implementation. OMP -> AVX -> LOGLESS_CACHING */ + FASTEST_AVAILABLE, /* Debugging for vector implementation of LOGLESS_CACHING */ DEBUG_VECTOR_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 } - /* Instruction sets for computing VectorLoglessHMM */ - public enum HMM_SUB_IMPLEMENTATION { - /* standard un-vectorized instructions */ - UNVECTORIZED(0x0L, false), - /* Streaming SIMD Extensions (SSE), version 4.1 */ - SSE41(0x1L, true), - /* Streaming SIMD Extensions (SSE), version 4.2 */ - SSE42(0x2L, true), - /* Advanced Vector Extensions (AVX) */ - AVX(0x4L, true), - /* For testing only, set bit beyond hardware capabilities */ - TEST_BEYOND_CAPABILITIES(0x400L, true), - /* Enable all implementations */ - ENABLE_ALL(0xFFFFFFFFFFFFFFFFl, false); - - /* Masks for machine capabilities */ - private final long mask; - /* Is a specific hardware instruction set requested? */ - private final boolean isSpecificHardwareRequest; - HMM_SUB_IMPLEMENTATION(long mask, boolean isSpecificHardwareRequest) { - this.mask = mask; - this.isSpecificHardwareRequest = isSpecificHardwareRequest; - } - long getMask() { return mask; } - boolean getIsSpecificHardwareRequest() { return isSpecificHardwareRequest; } - } - protected int maxHaplotypeLength, maxReadLength; protected int paddedMaxReadLength, paddedMaxHaplotypeLength; protected int paddedReadLength, paddedHaplotypeLength; diff --git a/public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so b/public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so deleted file mode 100644 index e734211ba3a6520228f757621ccaf516b922905f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 479437 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

{`7ZusGE(d=!I%7XJnMaxGq26wZ0f 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 z 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