1 package org.broadinstitute.hellbender.tools.dragstr;
2 
3 import org.broadinstitute.hellbender.engine.GATKPath;
4 import org.broadinstitute.hellbender.utils.Utils;
5 import org.broadinstitute.hellbender.utils.dragstr.DragstrParamUtils;
6 import org.broadinstitute.hellbender.utils.dragstr.DragstrParams;
7 import org.broadinstitute.hellbender.utils.tsv.DataLine;
8 import org.broadinstitute.hellbender.utils.tsv.TableReader;
9 import org.testng.Assert;
10 import org.testng.annotations.Test;
11 
12 import java.io.File;
13 import java.io.IOException;
14 import java.nio.file.Path;
15 
16 /**
17  * Tests the {@link DragstrParametersEstimator} code.
18  */
19 public class DragstrParametersEstimatorTest {
20 
21     private static final Path DRAGEN_USED_CASES = new File("src/test/resources/large/org/broadinstitute/hellbender/tools/dragstr/dragen-param-estimator-input.tab.gz").toPath();
22     private static final Path DRAGEN_ESPECTED_RESULT = new File("src/test/resources/large/org/broadinstitute/hellbender/tools/dragstr/dragen-param-estimator-expected-output.txt").toPath();
23     private static final DragstrHyperParameters HYPER_PARAMETERS = new DragstrHyperParameters();
24 
25     @Test
testMatchWithDragenValues()26     public void testMatchWithDragenValues()  {
27         final StratifiedDragstrLocusCases cases = composeInputCases();
28         final DragstrParametersEstimator subject = new DragstrParametersEstimator(HYPER_PARAMETERS);
29         final DragstrParams actual = Utils.runInParallel(0, () -> subject.estimate(cases));
30         final DragstrParams expected = DragstrParamUtils.parse(new GATKPath(DRAGEN_ESPECTED_RESULT.toString()));
31         Assert.assertEquals(actual.maximumPeriod(), expected.maximumPeriod());
32         Assert.assertEquals(actual.maximumRepeats(), expected.maximumRepeats());
33         for (int i = 1; i <= actual.maximumPeriod(); i++) {
34             for (int j = 1; j <= actual.maximumRepeats(); j++) {
35                 Assert.assertEquals(roundOf(actual.gop(i,j)), roundOf(expected.gop(i,j)));
36                 Assert.assertEquals(roundOf(actual.gcp(i,j)), roundOf(expected.gcp(i,j)));
37                 Assert.assertEquals(roundOf(actual.api(i,j)), roundOf(expected.api(i,j)));
38             }
39         }
40     }
41 
roundOf(final double dbl)42     private double roundOf(final double dbl) {
43         return Math.round(100 * dbl) / 100.0;
44     }
45 
composeInputCases()46     private StratifiedDragstrLocusCases composeInputCases() {
47         try (final DRAGENEstimationDataReader reader = new DRAGENEstimationDataReader(DRAGEN_USED_CASES)) {
48             return reader.stream()
49                     .map(DRAGENEstimationDataRecord::toCase)
50                     .reduce(StratifiedDragstrLocusCases.make(HYPER_PARAMETERS.maxPeriod, HYPER_PARAMETERS.maxRepeatLength),
51                             (accu, caze) -> { accu.add(caze); return accu; },
52                             StratifiedDragstrLocusCases::merge);
53         } catch (final IOException ex) {
54             Assert.fail("can't read input data test file: " + DRAGEN_USED_CASES, ex);
55             throw new RuntimeException("this should not be reached");
56         }
57     }
58 
59     static class DRAGENEstimationDataReader extends TableReader<DRAGENEstimationDataRecord> {
DRAGENEstimationDataReader(final Path path)60         DRAGENEstimationDataReader(final Path path) throws IOException {
61             super(path);
62         }
63 
64         @Override
createRecord(DataLine dataLine)65         protected DRAGENEstimationDataRecord createRecord(DataLine dataLine) {
66             return new DRAGENEstimationDataRecord(
67                     dataLine.getInt(), // 0
68                     dataLine.getLong(), // 1
69                     dataLine.getInt(), // 2
70                     dataLine.getInt(),  // 3
71                     dataLine.seek(6).getInt(), // 6 because we skip operiod (4) and orepeat (5) columns.
72                     dataLine.getInt()); // 7
73         }
74     }
75 
76     static class DRAGENEstimationDataRecord {
77         private final int chrIdx;
78         private final long pos;
79         private final int period;
80         private final int repeats;
81         private final int n;
82         private final int k;
83 
DRAGENEstimationDataRecord(int chrIdx, long pos, int period, int repeats, int n, int k)84         private DRAGENEstimationDataRecord(int chrIdx, long pos, int period, int repeats, int n, int k) {
85             this.chrIdx = chrIdx;
86             this.pos = pos;
87             this.period = period;
88             this.repeats = repeats;
89             this.n = n;
90             this.k = k;
91         }
92 
toCase()93         private DragstrLocusCase toCase() {
94             // 0 mask is irrelevant as these don't affect the test.
95             final DragstrLocus locus = DragstrLocus.make(chrIdx, pos, (byte) period, (short) (period * repeats), 0);
96             // 60,0 minMQ,nSup are not relevant as these do not affect the test.
97             return DragstrLocusCase.create(locus, n, k, 60, 0);
98         }
99     }
100 }
101