diff --git a/.github/workflows/pic-sure-hpds-test.yml b/.github/workflows/pic-sure-hpds-test.yml
new file mode 100644
index 000000000..a5993483b
--- /dev/null
+++ b/.github/workflows/pic-sure-hpds-test.yml
@@ -0,0 +1,22 @@
+name: pic-sure-hpds tests
+on:
+ pull_request:
+ paths: ['services/pic-sure-hpds/**']
+ push:
+ branches: [main]
+ paths: ['services/pic-sure-hpds/**']
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
+ - name: Set up JDK 25
+ uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 #v5.2.0
+ with:
+ java-version: '25'
+ distribution: 'temurin'
+ cache: maven
+ - name: Test with Maven
+ run: mvn -B -pl services/pic-sure-hpds/common,services/pic-sure-hpds/data,services/pic-sure-hpds/etl,services/pic-sure-hpds/processing,services/pic-sure-hpds/service,services/pic-sure-hpds/genomic-processor,services/pic-sure-hpds/war,services/pic-sure-hpds/docker -am verify
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
diff --git a/pom.xml b/pom.xml
index 98ce6343e..c2cc33acf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,6 +24,7 @@
services/picsure-dictionary/dictionaryweights
services/pic-sure-logging
services/pic-sure-auth-microapp
+ services/pic-sure-hpds
diff --git a/services/pic-sure-hpds/common/pom.xml b/services/pic-sure-hpds/common/pom.xml
index 75af6f689..5d08375bf 100644
--- a/services/pic-sure-hpds/common/pom.xml
+++ b/services/pic-sure-hpds/common/pom.xml
@@ -6,7 +6,7 @@
pic-sure-hpds
edu.harvard.hms.dbmi.avillach.hpds
- 3.0.0-SNAPSHOT
+ ${revision}
common
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/Crypto.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/Crypto.java
index e9245a42a..a6d014519 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/Crypto.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/Crypto.java
@@ -26,89 +26,95 @@
public class Crypto {
- public static final String DEFAULT_KEY_NAME = "DEFAULT";
-
- // This needs to be set in a static initializer block to be overridable in tests.
- private static final String DEFAULT_ENCRYPTION_KEY_PATH;
- static{
- DEFAULT_ENCRYPTION_KEY_PATH = "/opt/local/hpds/encryption_key";
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(Crypto.class);
-
- private static final HashMap keys = new HashMap();
-
- public static void loadDefaultKey() {
- loadKey(DEFAULT_KEY_NAME, DEFAULT_ENCRYPTION_KEY_PATH);
- }
-
- public static void loadKey(String keyName, String filePath) {
- try {
- setKey(keyName, IOUtils.toString(new FileInputStream(filePath), Charset.forName("UTF-8")).trim().getBytes());
- LOGGER.info("****LOADED CRYPTO KEY****");
- } catch (IOException e) {
- LOGGER.error("****CRYPTO KEY NOT FOUND****", e);
- }
- }
-
- public static byte[] encryptData(byte[] plaintextBytes) {
- return encryptData(DEFAULT_KEY_NAME, plaintextBytes);
- }
-
- public static byte[] encryptData(String keyName, byte[] plaintextBytes) {
- byte[] key = keys.get(keyName);
- SecureRandom secureRandom = new SecureRandom();
- SecretKey secretKey = new SecretKeySpec(key, "AES");
- byte[] iv = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
- secureRandom.nextBytes(iv);
- byte[] cipherText;
- Cipher cipher;
- try {
- cipher = Cipher.getInstance("AES/GCM/NoPadding");
- GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); //128 bit auth tag length
- cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
- cipherText = new byte[cipher.getOutputSize(plaintextBytes.length)];
- cipher.doFinal(plaintextBytes, 0, plaintextBytes.length, cipherText, 0);
- LOGGER.debug("Length of cipherText : " + cipherText.length);
- ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + cipherText.length);
- byteBuffer.putInt(iv.length);
- byteBuffer.put(iv);
- byteBuffer.put(cipherText);
- byte[] cipherMessage = byteBuffer.array();
- return cipherMessage;
- } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | ShortBufferException | IllegalBlockSizeException | BadPaddingException e) {
- throw new RuntimeException("Exception while trying to encrypt data : ", e);
- }
- }
-
- public static byte[] decryptData(byte[] encrypted) {
- return decryptData(DEFAULT_KEY_NAME, encrypted);
- }
-
- public static byte[] decryptData(String keyName, byte[] encrypted) {
- byte[] key = keys.get(keyName);
- ByteBuffer byteBuffer = ByteBuffer.wrap(encrypted);
- int ivLength = byteBuffer.getInt();
- byte[] iv = new byte[ivLength];
- byteBuffer.get(iv);
- byte[] cipherText = new byte[byteBuffer.remaining()];
- byteBuffer.get(cipherText);
- Cipher cipher;
- try {
- cipher = Cipher.getInstance("AES/GCM/NoPadding");
- cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
- return cipher.doFinal(cipherText);
- } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
- throw new RuntimeException("Exception caught trying to decrypt data : " + e, e);
- }
- }
-
- private static void setKey(String keyName, byte[] key) {
- keys.put(keyName, key);
- }
-
- public static boolean hasKey(String keyName) {
- return keys.containsKey(keyName);
- }
+ public static final String DEFAULT_KEY_NAME = "DEFAULT";
+
+ // This needs to be set in a static initializer block to be overridable in tests.
+ private static final String DEFAULT_ENCRYPTION_KEY_PATH;
+ static {
+ DEFAULT_ENCRYPTION_KEY_PATH = "/opt/local/hpds/encryption_key";
+ }
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Crypto.class);
+
+ private static final HashMap keys = new HashMap();
+
+ public static void loadDefaultKey() {
+ loadKey(DEFAULT_KEY_NAME, DEFAULT_ENCRYPTION_KEY_PATH);
+ }
+
+ public static void loadKey(String keyName, String filePath) {
+ try {
+ setKey(keyName, IOUtils.toString(new FileInputStream(filePath), Charset.forName("UTF-8")).trim().getBytes());
+ LOGGER.info("****LOADED CRYPTO KEY****");
+ } catch (IOException e) {
+ LOGGER.error("****CRYPTO KEY NOT FOUND****", e);
+ }
+ }
+
+ public static byte[] encryptData(byte[] plaintextBytes) {
+ return encryptData(DEFAULT_KEY_NAME, plaintextBytes);
+ }
+
+ public static byte[] encryptData(String keyName, byte[] plaintextBytes) {
+ byte[] key = keys.get(keyName);
+ SecureRandom secureRandom = new SecureRandom();
+ SecretKey secretKey = new SecretKeySpec(key, "AES");
+ byte[] iv = new byte[12]; // NEVER REUSE THIS IV WITH SAME KEY
+ secureRandom.nextBytes(iv);
+ byte[] cipherText;
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv); // 128 bit auth tag length
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
+ cipherText = new byte[cipher.getOutputSize(plaintextBytes.length)];
+ cipher.doFinal(plaintextBytes, 0, plaintextBytes.length, cipherText, 0);
+ LOGGER.debug("Length of cipherText : " + cipherText.length);
+ ByteBuffer byteBuffer = ByteBuffer.allocate(4 + iv.length + cipherText.length);
+ byteBuffer.putInt(iv.length);
+ byteBuffer.put(iv);
+ byteBuffer.put(cipherText);
+ byte[] cipherMessage = byteBuffer.array();
+ return cipherMessage;
+ } catch (
+ NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
+ | ShortBufferException | IllegalBlockSizeException | BadPaddingException e
+ ) {
+ throw new RuntimeException("Exception while trying to encrypt data : ", e);
+ }
+ }
+
+ public static byte[] decryptData(byte[] encrypted) {
+ return decryptData(DEFAULT_KEY_NAME, encrypted);
+ }
+
+ public static byte[] decryptData(String keyName, byte[] encrypted) {
+ byte[] key = keys.get(keyName);
+ ByteBuffer byteBuffer = ByteBuffer.wrap(encrypted);
+ int ivLength = byteBuffer.getInt();
+ byte[] iv = new byte[ivLength];
+ byteBuffer.get(iv);
+ byte[] cipherText = new byte[byteBuffer.remaining()];
+ byteBuffer.get(cipherText);
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
+ return cipher.doFinal(cipherText);
+ } catch (
+ NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException
+ | IllegalBlockSizeException | BadPaddingException e
+ ) {
+ throw new RuntimeException("Exception caught trying to decrypt data : " + e, e);
+ }
+ }
+
+ private static void setKey(String keyName, byte[] key) {
+ keys.put(keyName, key);
+ }
+
+ public static boolean hasKey(String keyName) {
+ return keys.containsKey(keyName);
+ }
}
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/NotEnoughMemoryException.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/NotEnoughMemoryException.java
index f75631ea9..5cb595abb 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/NotEnoughMemoryException.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/NotEnoughMemoryException.java
@@ -2,11 +2,13 @@
public class NotEnoughMemoryException extends RuntimeException {
- private static final long serialVersionUID = 2592915631853567560L;
+ private static final long serialVersionUID = 2592915631853567560L;
- public NotEnoughMemoryException() {
- super("Not enough available heap space to allocate results array."
- + "Please reduce ID_BATCH_SIZE or CACHE_SIZE system property or increase the heap available to this application. "
- + "This query will be retried up to 3 times.");
- }
+ public NotEnoughMemoryException() {
+ super(
+ "Not enough available heap space to allocate results array."
+ + "Please reduce ID_BATCH_SIZE or CACHE_SIZE system property or increase the heap available to this application. "
+ + "This query will be retried up to 3 times."
+ );
+ }
}
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/ResultSetTooLargeException.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/ResultSetTooLargeException.java
index 8d7dd1b19..051b6f049 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/ResultSetTooLargeException.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/exception/ResultSetTooLargeException.java
@@ -1,21 +1,20 @@
package edu.harvard.hms.dbmi.avillach.hpds.exception;
public class ResultSetTooLargeException extends RuntimeException {
- /**
- * This exception is thrown when a result set would be larger in memory than
- * Integer.MAX_INT bytes. This is a JVM limitation... but seriously people...
- *
- * You actually don't need that much data on the client side, work with us
- * to implement whatever filtering you need.
- *
- * @param multiplesOfCapacity The number of pieces to split this result to actually have it work.
- */
- public ResultSetTooLargeException(long multiplesOfCapacity) {
- super("The result set is too large to handle in one request. "
- + "We have a plan to fix this limitation, but for now try "
- + "splitting your selected fields array in " + multiplesOfCapacity + " equal pieces "
- + "and running " + multiplesOfCapacity + " queries. Additionally, do you actually "
- + "need all this data? Do you have the compute resources "
- + "to handle processing it?");
- }
+ /**
+ * This exception is thrown when a result set would be larger in memory than Integer.MAX_INT bytes. This is a JVM limitation... but
+ * seriously people...
+ *
+ * You actually don't need that much data on the client side, work with us to implement whatever filtering you need.
+ *
+ * @param multiplesOfCapacity The number of pieces to split this result to actually have it work.
+ */
+ public ResultSetTooLargeException(long multiplesOfCapacity) {
+ super(
+ "The result set is too large to handle in one request. " + "We have a plan to fix this limitation, but for now try "
+ + "splitting your selected fields array in " + multiplesOfCapacity + " equal pieces " + "and running " + multiplesOfCapacity
+ + " queries. Additionally, do you actually " + "need all this data? Do you have the compute resources "
+ + "to handle processing it?"
+ );
+ }
}
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedByteIndexedStorage.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedByteIndexedStorage.java
index b86b671f9..6c9ce95e2 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedByteIndexedStorage.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedByteIndexedStorage.java
@@ -5,68 +5,68 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
-public abstract class FileBackedByteIndexedStorage implements Serializable {
- private static final long serialVersionUID = -7297090745384302635L;
- protected transient RandomAccessFile storage;
- protected ConcurrentHashMap index;
- protected File storageFile;
- protected boolean completed = false;
+public abstract class FileBackedByteIndexedStorage implements Serializable {
+ private static final long serialVersionUID = -7297090745384302635L;
+ protected transient RandomAccessFile storage;
+ protected ConcurrentHashMap index;
+ protected File storageFile;
+ protected boolean completed = false;
- public FileBackedByteIndexedStorage(Class keyClass, Class valueClass, File storageFile) throws FileNotFoundException {
- this.index = new ConcurrentHashMap();
- this.storageFile = storageFile;
- this.storage = new RandomAccessFile(this.storageFile, "rw");
- }
+ public FileBackedByteIndexedStorage(Class keyClass, Class valueClass, File storageFile) throws FileNotFoundException {
+ this.index = new ConcurrentHashMap();
+ this.storageFile = storageFile;
+ this.storage = new RandomAccessFile(this.storageFile, "rw");
+ }
- public void updateStorageDirectory(File storageDirectory) {
- if (!storageDirectory.isDirectory()) {
- throw new IllegalArgumentException("storageDirectory is not a directory");
- }
- String currentStoreageFilename = storageFile.getName();
- storageFile = new File(storageDirectory, currentStoreageFilename);
- }
+ public void updateStorageDirectory(File storageDirectory) {
+ if (!storageDirectory.isDirectory()) {
+ throw new IllegalArgumentException("storageDirectory is not a directory");
+ }
+ String currentStoreageFilename = storageFile.getName();
+ storageFile = new File(storageDirectory, currentStoreageFilename);
+ }
- public Set keys(){
- return index.keySet();
- }
+ public Set keys() {
+ return index.keySet();
+ }
- public void put(K key, V value) {
- if(completed) {
- throw new RuntimeException("A completed FileBackedByteIndexedStorage cannot be modified.");
- }
- Long[] recordIndex;
- try (ByteArrayOutputStream out = writeObject(value)) {
- recordIndex = new Long[2];
- synchronized (storage) {
- storage.seek(storage.length());
- recordIndex[0] = storage.getFilePointer();
- storage.write(out.toByteArray());
- recordIndex[1] = storage.getFilePointer() - recordIndex[0];
- }
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- index.put(key, recordIndex);
- }
+ public void put(K key, V value) {
+ if (completed) {
+ throw new RuntimeException("A completed FileBackedByteIndexedStorage cannot be modified.");
+ }
+ Long[] recordIndex;
+ try (ByteArrayOutputStream out = writeObject(value)) {
+ recordIndex = new Long[2];
+ synchronized (storage) {
+ storage.seek(storage.length());
+ recordIndex[0] = storage.getFilePointer();
+ storage.write(out.toByteArray());
+ recordIndex[1] = storage.getFilePointer() - recordIndex[0];
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ index.put(key, recordIndex);
+ }
- public void load(Iterable values, Function mapper) {
- //make sure we start fresh
- if(this.storageFile.exists()) {
- this.storageFile.delete();
- }
- try (RandomAccessFile storage = new RandomAccessFile(storageFile, "rw");) {
- this.storage = storage;
- for(V value : values) {
- put(mapper.apply(value), value);
- }
- complete();
- } catch (IOException e) {
+ public void load(Iterable values, Function mapper) {
+ // make sure we start fresh
+ if (this.storageFile.exists()) {
+ this.storageFile.delete();
+ }
+ try (RandomAccessFile storage = new RandomAccessFile(storageFile, "rw");) {
+ this.storage = storage;
+ for (V value : values) {
+ put(mapper.apply(value), value);
+ }
+ complete();
+ } catch (IOException e) {
throw new UncheckedIOException(e);
}
}
- public void open() {
+ public void open() {
try {
this.storage = new RandomAccessFile(this.storageFile, "rwd");
} catch (FileNotFoundException e) {
@@ -74,48 +74,48 @@ public void open() {
}
}
- public void complete() {
- this.completed = true;
- }
+ public void complete() {
+ this.completed = true;
+ }
- public V get(K key) {
- try {
- // todo: make this class immutable and remove this lock/check altogether
- synchronized(this) {
- if(this.storage==null) {
- this.open();
- }
- }
- Long[] offsetsInStorage = index.get(key);
- if(offsetsInStorage != null) {
- Long offsetInStorage = index.get(key)[0];
- int offsetLength = index.get(key)[1].intValue();
- if(offsetInStorage != null && offsetLength>0) {
- byte[] buffer = new byte[offsetLength];
- synchronized(storage) {
- storage.seek(offsetInStorage);
- storage.readFully(buffer);
- }
- V readObject = readObject(buffer);
- return readObject;
- }else {
- return null;
- }
- } else {
- return null;
- }
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
+ public V get(K key) {
+ try {
+ // todo: make this class immutable and remove this lock/check altogether
+ synchronized (this) {
+ if (this.storage == null) {
+ this.open();
+ }
+ }
+ Long[] offsetsInStorage = index.get(key);
+ if (offsetsInStorage != null) {
+ Long offsetInStorage = index.get(key)[0];
+ int offsetLength = index.get(key)[1].intValue();
+ if (offsetInStorage != null && offsetLength > 0) {
+ byte[] buffer = new byte[offsetLength];
+ synchronized (storage) {
+ storage.seek(offsetInStorage);
+ storage.readFully(buffer);
+ }
+ V readObject = readObject(buffer);
+ return readObject;
+ } else {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
- protected abstract V readObject(byte[] buffer);
+ protected abstract V readObject(byte[] buffer);
- protected abstract ByteArrayOutputStream writeObject(V value) throws IOException;
+ protected abstract ByteArrayOutputStream writeObject(V value) throws IOException;
- public V getOrELse(K key, V defaultValue) {
- V result = get(key);
- return result == null ? defaultValue : result;
- }
+ public V getOrELse(K key, V defaultValue) {
+ V result = get(key);
+ return result == null ? defaultValue : result;
+ }
}
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJavaIndexedStorage.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJavaIndexedStorage.java
index d70c65a2d..dc30ada05 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJavaIndexedStorage.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJavaIndexedStorage.java
@@ -4,15 +4,16 @@
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-public class FileBackedJavaIndexedStorage extends FileBackedByteIndexedStorage {
+public class FileBackedJavaIndexedStorage extends FileBackedByteIndexedStorage {
public FileBackedJavaIndexedStorage(Class keyClass, Class valueClass, File storageFile) throws FileNotFoundException {
super(keyClass, valueClass, storageFile);
}
protected ByteArrayOutputStream writeObject(V value) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
- try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out);
- ObjectOutputStream oos = new ObjectOutputStream(gzipOutputStream)) {
+ try (
+ GZIPOutputStream gzipOutputStream = new GZIPOutputStream(out); ObjectOutputStream oos = new ObjectOutputStream(gzipOutputStream)
+ ) {
oos.writeObject(value);
oos.flush();
}
diff --git a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJsonIndexStorage.java b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJsonIndexStorage.java
index f93a206fd..89e5133df 100644
--- a/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJsonIndexStorage.java
+++ b/services/pic-sure-hpds/common/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/storage/FileBackedJsonIndexStorage.java
@@ -7,7 +7,7 @@
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
-public abstract class FileBackedJsonIndexStorage extends FileBackedByteIndexedStorage {
+public abstract class FileBackedJsonIndexStorage extends FileBackedByteIndexedStorage {
private static final long serialVersionUID = -1086729119489479152L;
protected transient ObjectMapper objectMapper = new ObjectMapper();
diff --git a/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoDefaultKeyTest.java b/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoDefaultKeyTest.java
index 8f93aeea7..d5f59fd73 100644
--- a/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoDefaultKeyTest.java
+++ b/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoDefaultKeyTest.java
@@ -13,38 +13,37 @@
@Disabled // We should rewrite the crypto class to make it more testable, these tests don't work on certain JDKs
public class CryptoDefaultKeyTest {
-
- String TEST_MESSAGE = "This is a test.";
-
- @BeforeTestClass
- public static void overrideDefaultKeyLocation() throws IllegalArgumentException, IllegalAccessException {
- }
-
- @Test
- public void testCryptoLoadsKey() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
- Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
- field.setAccessible(true);
- Field modifiersField = Field.class.getDeclaredField("modifiers");
+
+ String TEST_MESSAGE = "This is a test.";
+
+ @BeforeTestClass
+ public static void overrideDefaultKeyLocation() throws IllegalArgumentException, IllegalAccessException {}
+
+ @Test
+ public void testCryptoLoadsKey() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
+ field.setAccessible(true);
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
+ field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
Crypto.loadDefaultKey();
assertTrue(Crypto.hasKey(Crypto.DEFAULT_KEY_NAME));
- }
+ }
- @Test
- public void testEncryptDecrypt() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
- Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
- field.setAccessible(true);
- Field modifiersField = Field.class.getDeclaredField("modifiers");
+ @Test
+ public void testEncryptDecrypt() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
+ field.setAccessible(true);
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
- Crypto.loadDefaultKey();
- byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
- assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
- String plaintext = new String(Crypto.decryptData(ciphertext));
- assertEquals(plaintext, TEST_MESSAGE);
- }
-
+ field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
+ Crypto.loadDefaultKey();
+ byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
+ assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
+ String plaintext = new String(Crypto.decryptData(ciphertext));
+ assertEquals(plaintext, TEST_MESSAGE);
+ }
+
}
diff --git a/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoNamedKeyTest.java b/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoNamedKeyTest.java
index 435b51508..d18d1495e 100644
--- a/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoNamedKeyTest.java
+++ b/services/pic-sure-hpds/common/src/test/java/edu/harvard/hms/dbmi/avillach/hpds/crypto/CryptoNamedKeyTest.java
@@ -15,49 +15,50 @@
@Disabled // We should rewrite the crypto class to make it more testable, these tests don't work on certain JDKs
public class CryptoNamedKeyTest {
- private static final String TEST_NAMED_ENCRYPTIOON_KEY_PATH = "src/test/resources/test_named_encryption_key";
-
- String TEST_MESSAGE = "This is a test.";
-
- String TEST_NAMED_KEY = "TEST_NAMED_KEY";
-
- @BeforeTestClass
- public static void overrideDefaultKeyLocation() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
- Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
- field.setAccessible(true);
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
- field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
- Crypto.loadDefaultKey();
- }
-
- @Test
- public void testNamedKeyEncryptDecrypt() {
- Crypto.loadKey("TEST_NAMED_KEY", TEST_NAMED_ENCRYPTIOON_KEY_PATH);
- byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
- assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
- String plaintext = new String(Crypto.decryptData(ciphertext));
- assertEquals(plaintext, TEST_MESSAGE);
- }
-
- @Test
- public void testNamedKeyEncryptNotUsingDefaultKey() {
- assertThrows(AEADBadTagException.class, () -> {
- Crypto.loadKey(TEST_NAMED_KEY, TEST_NAMED_ENCRYPTIOON_KEY_PATH);
- byte[] ciphertext = Crypto.encryptData(TEST_NAMED_KEY, TEST_MESSAGE.getBytes());
- assertFalse(new String(ciphertext).contentEquals(TEST_MESSAGE));
- Crypto.decryptData(ciphertext);
- });
- }
-
- @Test
- public void testNamedKeyDecryptNotUsingDefaultKey() {
- assertThrows(AEADBadTagException.class, () -> {
- Crypto.loadKey(TEST_NAMED_KEY, TEST_NAMED_ENCRYPTIOON_KEY_PATH);
- byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
- assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
- Crypto.decryptData(TEST_NAMED_KEY, ciphertext);
- });
- }
+ private static final String TEST_NAMED_ENCRYPTIOON_KEY_PATH = "src/test/resources/test_named_encryption_key";
+
+ String TEST_MESSAGE = "This is a test.";
+
+ String TEST_NAMED_KEY = "TEST_NAMED_KEY";
+
+ @BeforeTestClass
+ public static void overrideDefaultKeyLocation()
+ throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
+ Field field = Crypto.class.getDeclaredField("DEFAULT_ENCRYPTION_KEY_PATH");
+ field.setAccessible(true);
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ field.set(Crypto.class, new File("src/test/resources/test_encryption_key").getAbsolutePath());
+ Crypto.loadDefaultKey();
+ }
+
+ @Test
+ public void testNamedKeyEncryptDecrypt() {
+ Crypto.loadKey("TEST_NAMED_KEY", TEST_NAMED_ENCRYPTIOON_KEY_PATH);
+ byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
+ assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
+ String plaintext = new String(Crypto.decryptData(ciphertext));
+ assertEquals(plaintext, TEST_MESSAGE);
+ }
+
+ @Test
+ public void testNamedKeyEncryptNotUsingDefaultKey() {
+ assertThrows(AEADBadTagException.class, () -> {
+ Crypto.loadKey(TEST_NAMED_KEY, TEST_NAMED_ENCRYPTIOON_KEY_PATH);
+ byte[] ciphertext = Crypto.encryptData(TEST_NAMED_KEY, TEST_MESSAGE.getBytes());
+ assertFalse(new String(ciphertext).contentEquals(TEST_MESSAGE));
+ Crypto.decryptData(ciphertext);
+ });
+ }
+
+ @Test
+ public void testNamedKeyDecryptNotUsingDefaultKey() {
+ assertThrows(AEADBadTagException.class, () -> {
+ Crypto.loadKey(TEST_NAMED_KEY, TEST_NAMED_ENCRYPTIOON_KEY_PATH);
+ byte[] ciphertext = Crypto.encryptData(TEST_MESSAGE.getBytes());
+ assertTrue(!new String(ciphertext).contentEquals(TEST_MESSAGE));
+ Crypto.decryptData(TEST_NAMED_KEY, ciphertext);
+ });
+ }
}
diff --git a/services/pic-sure-hpds/data/pom.xml b/services/pic-sure-hpds/data/pom.xml
index c1f5f2f48..abcff078a 100644
--- a/services/pic-sure-hpds/data/pom.xml
+++ b/services/pic-sure-hpds/data/pom.xml
@@ -5,7 +5,7 @@
pic-sure-hpds
edu.harvard.hms.dbmi.avillach.hpds
- 3.0.0-SNAPSHOT
+ ${revision}
data
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/BucketIndexBySample.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/BucketIndexBySample.java
index cf653a72b..afa68be0d 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/BucketIndexBySample.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/BucketIndexBySample.java
@@ -13,184 +13,179 @@
import edu.harvard.hms.dbmi.avillach.hpds.storage.FileBackedByteIndexedStorage;
public class BucketIndexBySample implements Serializable {
- private static final long serialVersionUID = -1230735595028630687L;
- private static final String STORAGE_FILE_NAME = "BucketIndexBySampleStorage.javabin";
-
- List patientIds;
- ArrayList contigSet;
-
- transient Logger log = LoggerFactory.getLogger(BucketIndexBySample.class);
-
- /**
- * Threadsafe Map of patientNum to a BigInteger which acts as a bitmask of the buckets in which each patient
- * has a variant. The bits in the BigInteger are indexed by the bucketList. To find the offset of a bucket's
- * bit in the mask use patientBucketMask.get(patientId).testBit(Collections
- */
- private FileBackedByteIndexedStorage patientBucketMasks;
-
- /**
- * ArrayList containing all bucket keys in the dataset used as an index for the patientBucketMask offsets.
- * This list is in natural sort order so Collections.binarySearch should be used instead of indexOf when
- * finding the offset of a given bucket.
- */
- private ArrayList bucketList = new ArrayList();
-
- public BucketIndexBySample(VariantStore variantStore, String storageDir) throws FileNotFoundException {
- log.info("Creating new Bucket Index by Sample");
- final String storageFileStr = storageDir + STORAGE_FILE_NAME;
-
- contigSet = new ArrayList(variantStore.getVariantMaskStorage().keySet());
-
- //Create a bucketList, containing keys for all buckets in the variantStore
- for(String contig: contigSet){
- FileBackedByteIndexedStorage> contigStore = variantStore.getVariantMaskStorage().get(contig);
- if(contigStore != null && contigStore.keys() != null) {
- bucketList.addAll(contigStore.keys().stream().map(
- (Integer bucket)->{
- return contig + ":" + bucket;
- }).collect(Collectors.toList()));
- log.debug("Found " + contigStore.keys().size() + " buckets in contig " + contig);
- } else {
- log.debug("null entry for contig " + contig);
- }
- }
-
- // bucketList must be sorted so we can later use binarySearch to find offsets for specific buckets
- // in the patientBucketMask records
- Collections.sort(bucketList);
-
- log.debug("Found " + bucketList.size() + " total buckets");
-
- // get all patientIds as Integers, eventually this should be fixed in variantStore so they are
- // Integers to begin with, which would mean reloading all variant data everywhere so that will
- // have to wait.
- patientIds = Arrays.stream(variantStore.getPatientIds()).map(id->{
- return Integer.parseInt(id);
- }).collect(Collectors.toList());
-
- // create empty char arrays for each patient
- char[][] patientBucketCharMasks = new char[patientIds.size()][bucketList.size()];
- for(int x = 0;x{
- FileBackedByteIndexedStorage> contigStore =
- variantStore.getVariantMaskStorage().get(contig);
- if(contigStore != null && contigStore.keys() != null) {
- contigStore.keys().stream().forEach(
- (Integer bucket)->{
- String bucketKey = contig + ":" + bucket;
-
- // Create a bitmask with 1 values for each patient who has any variant in this bucket
- VariantMask[] patientMaskForBucket = {new VariantMaskSparseImpl(Set.of())};
- contigStore.get(bucket).values().forEach((VariableVariantMasks masks)->{
- if(masks.heterozygousMask!=null) {
- patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.heterozygousMask);
- }
- //add hetreo no call bits to mask
- if(masks.heterozygousNoCallMask!=null) {
- patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.heterozygousNoCallMask);
- }
- if(masks.homozygousMask!=null) {
- patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.homozygousMask);
- }
- });
-
- // For each patient set the patientBucketCharMask entry to 0 or 1 if they have a variant in the bucket.
- int indexOfBucket = Collections.binarySearch(bucketList, bucketKey) + 2; //patientBucketCharMasks has bookend bits
- for(int x = 0; x < patientIds.size(); x++) {
- if(patientMaskForBucket[0].testBit(x)) {
- patientBucketCharMasks[x][indexOfBucket] = '1';
- }else {
- patientBucketCharMasks[x][indexOfBucket] = '0';
- }
- }
- });
- } else {
- log.info("null entry for contig " + contig);
- }
- log.info("completed contig " + contig);
- });
-
- // populate patientBucketMasks with bucketMasks for each patient
- patientBucketMasks = new FileBackedJavaIndexedStorage(Integer.class, BigInteger.class, new File(storageFileStr));
-
- int[] processedPatients = new int[1];
- patientIds.parallelStream().forEach((patientId)->{
- BigInteger patientMask = new BigInteger(new String(patientBucketCharMasks[patientIds.indexOf(patientId)]),2);
- patientBucketMasks.put(patientId, patientMask);
- processedPatients[0] += 1;
- int processedPatientsCount = processedPatients[0];
- if (processedPatientsCount % 1000 == 0) {
- log.debug("wrote " + processedPatientsCount + " patient bucket masks");
- }
- });
- patientBucketMasks.complete();
- log.info("Done creating patient bucket masks");
- }
-
- /**
- * Given a set of variants and a set of patientNums, filter out variants which no patients in the patientSet
- * have any variant in the bucket. This operation is extremely fast and cuts down on processing by excluding
- * variants for queries where not all patients are included.
- *
- * @param variantSet
- * @param patientSet
- * @return
- * @throws IOException
- */
- public Set filterVariantSetForPatientSet(Set variantSet, Collection patientSet) throws IOException{
-
- BigInteger patientBucketMask = patientSet.stream().findFirst()
- .map(id -> patientBucketMasks.get(id))
- .orElseGet(() -> new BigInteger(new String(emptyBucketMaskChar()),2));
-
- BigInteger _defaultMask = patientBucketMask;
- List patientBucketmasksForSet = patientSet.parallelStream()
- .map((patientNum)-> patientBucketMasks.get(patientNum))
- .collect(Collectors.toList());
- for(BigInteger patientMask : patientBucketmasksForSet) {
- patientBucketMask = patientMask.or(patientBucketMask);
- }
-
- BigInteger _bucketMask = patientBucketMask;
- int maxIndex = bucketList.size() - 1; //use to invert testBit index
- return variantSet.parallelStream().filter((variantSpec)->{
- String bucketKey = variantSpec.split(",")[0] + ":" + (Integer.parseInt(variantSpec.split(",")[1])/1000);
-
- //testBit uses inverted indexes include +2 offset for bookends
- int bucketKeyIndex = Collections.binarySearch(bucketList, bucketKey);
- if (bucketKeyIndex < 0) {
- return false;
- }
- return _bucketMask.testBit(maxIndex - bucketKeyIndex + 2);
- }).collect(Collectors.toSet());
- }
-
- private char[] _emptyBucketMaskChar = null;
-
- /**
- * Produce an empty patientBucketMask char[] by cloning a momoized empty patientBucketMask after the
- * first has been created.
- *
- * @return
- */
- private char[] emptyBucketMaskChar() {
- if(_emptyBucketMaskChar == null) {
- char[] bucketMaskChar = new char[bucketList.size()+4];
- bucketMaskChar[0] = '1';
- bucketMaskChar[1] = '1';
- bucketMaskChar[bucketMaskChar.length-1] = '1';
- bucketMaskChar[bucketMaskChar.length-2]='1';
- for(int x = 2;x patientIds;
+ ArrayList contigSet;
+
+ transient Logger log = LoggerFactory.getLogger(BucketIndexBySample.class);
+
+ /**
+ * Threadsafe Map of patientNum to a BigInteger which acts as a bitmask of the buckets in which each patient has a variant. The bits in
+ * the BigInteger are indexed by the bucketList. To find the offset of a bucket's bit in the mask use
+ * patientBucketMask.get(patientId).testBit(Collections
+ */
+ private FileBackedByteIndexedStorage patientBucketMasks;
+
+ /**
+ * ArrayList containing all bucket keys in the dataset used as an index for the patientBucketMask offsets. This list is in natural sort
+ * order so Collections.binarySearch should be used instead of indexOf when finding the offset of a given bucket.
+ */
+ private ArrayList bucketList = new ArrayList();
+
+ public BucketIndexBySample(VariantStore variantStore, String storageDir) throws FileNotFoundException {
+ log.info("Creating new Bucket Index by Sample");
+ final String storageFileStr = storageDir + STORAGE_FILE_NAME;
+
+ contigSet = new ArrayList(variantStore.getVariantMaskStorage().keySet());
+
+ // Create a bucketList, containing keys for all buckets in the variantStore
+ for (String contig : contigSet) {
+ FileBackedByteIndexedStorage> contigStore =
+ variantStore.getVariantMaskStorage().get(contig);
+ if (contigStore != null && contigStore.keys() != null) {
+ bucketList.addAll(contigStore.keys().stream().map((Integer bucket) -> {
+ return contig + ":" + bucket;
+ }).collect(Collectors.toList()));
+ log.debug("Found " + contigStore.keys().size() + " buckets in contig " + contig);
+ } else {
+ log.debug("null entry for contig " + contig);
+ }
+ }
+
+ // bucketList must be sorted so we can later use binarySearch to find offsets for specific buckets
+ // in the patientBucketMask records
+ Collections.sort(bucketList);
+
+ log.debug("Found " + bucketList.size() + " total buckets");
+
+ // get all patientIds as Integers, eventually this should be fixed in variantStore so they are
+ // Integers to begin with, which would mean reloading all variant data everywhere so that will
+ // have to wait.
+ patientIds = Arrays.stream(variantStore.getPatientIds()).map(id -> {
+ return Integer.parseInt(id);
+ }).collect(Collectors.toList());
+
+ // create empty char arrays for each patient
+ char[][] patientBucketCharMasks = new char[patientIds.size()][bucketList.size()];
+ for (int x = 0; x < patientBucketCharMasks.length; x++) {
+ patientBucketCharMasks[x] = emptyBucketMaskChar();
+ }
+ contigSet.parallelStream().forEach((contig) -> {
+ FileBackedByteIndexedStorage> contigStore =
+ variantStore.getVariantMaskStorage().get(contig);
+ if (contigStore != null && contigStore.keys() != null) {
+ contigStore.keys().stream().forEach((Integer bucket) -> {
+ String bucketKey = contig + ":" + bucket;
+
+ // Create a bitmask with 1 values for each patient who has any variant in this bucket
+ VariantMask[] patientMaskForBucket = {new VariantMaskSparseImpl(Set.of())};
+ contigStore.get(bucket).values().forEach((VariableVariantMasks masks) -> {
+ if (masks.heterozygousMask != null) {
+ patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.heterozygousMask);
+ }
+ // add hetreo no call bits to mask
+ if (masks.heterozygousNoCallMask != null) {
+ patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.heterozygousNoCallMask);
+ }
+ if (masks.homozygousMask != null) {
+ patientMaskForBucket[0] = patientMaskForBucket[0].union(masks.homozygousMask);
+ }
+ });
+
+ // For each patient set the patientBucketCharMask entry to 0 or 1 if they have a variant in the bucket.
+ int indexOfBucket = Collections.binarySearch(bucketList, bucketKey) + 2; // patientBucketCharMasks has bookend bits
+ for (int x = 0; x < patientIds.size(); x++) {
+ if (patientMaskForBucket[0].testBit(x)) {
+ patientBucketCharMasks[x][indexOfBucket] = '1';
+ } else {
+ patientBucketCharMasks[x][indexOfBucket] = '0';
+ }
+ }
+ });
+ } else {
+ log.info("null entry for contig " + contig);
+ }
+ log.info("completed contig " + contig);
+ });
+
+ // populate patientBucketMasks with bucketMasks for each patient
+ patientBucketMasks = new FileBackedJavaIndexedStorage(Integer.class, BigInteger.class, new File(storageFileStr));
+
+ int[] processedPatients = new int[1];
+ patientIds.parallelStream().forEach((patientId) -> {
+ BigInteger patientMask = new BigInteger(new String(patientBucketCharMasks[patientIds.indexOf(patientId)]), 2);
+ patientBucketMasks.put(patientId, patientMask);
+ processedPatients[0] += 1;
+ int processedPatientsCount = processedPatients[0];
+ if (processedPatientsCount % 1000 == 0) {
+ log.debug("wrote " + processedPatientsCount + " patient bucket masks");
+ }
+ });
+ patientBucketMasks.complete();
+ log.info("Done creating patient bucket masks");
+ }
+
+ /**
+ * Given a set of variants and a set of patientNums, filter out variants which no patients in the patientSet have any variant in the
+ * bucket. This operation is extremely fast and cuts down on processing by excluding variants for queries where not all patients are
+ * included.
+ *
+ * @param variantSet
+ * @param patientSet
+ * @return
+ * @throws IOException
+ */
+ public Set filterVariantSetForPatientSet(Set variantSet, Collection patientSet) throws IOException {
+
+ BigInteger patientBucketMask = patientSet.stream().findFirst().map(id -> patientBucketMasks.get(id))
+ .orElseGet(() -> new BigInteger(new String(emptyBucketMaskChar()), 2));
+
+ BigInteger _defaultMask = patientBucketMask;
+ List patientBucketmasksForSet =
+ patientSet.parallelStream().map((patientNum) -> patientBucketMasks.get(patientNum)).collect(Collectors.toList());
+ for (BigInteger patientMask : patientBucketmasksForSet) {
+ patientBucketMask = patientMask.or(patientBucketMask);
+ }
+
+ BigInteger _bucketMask = patientBucketMask;
+ int maxIndex = bucketList.size() - 1; // use to invert testBit index
+ return variantSet.parallelStream().filter((variantSpec) -> {
+ String bucketKey = variantSpec.split(",")[0] + ":" + (Integer.parseInt(variantSpec.split(",")[1]) / 1000);
+
+ // testBit uses inverted indexes include +2 offset for bookends
+ int bucketKeyIndex = Collections.binarySearch(bucketList, bucketKey);
+ if (bucketKeyIndex < 0) {
+ return false;
+ }
+ return _bucketMask.testBit(maxIndex - bucketKeyIndex + 2);
+ }).collect(Collectors.toSet());
+ }
+
+ private char[] _emptyBucketMaskChar = null;
+
+ /**
+ * Produce an empty patientBucketMask char[] by cloning a momoized empty patientBucketMask after the first has been created.
+ *
+ * @return
+ */
+ private char[] emptyBucketMaskChar() {
+ if (_emptyBucketMaskChar == null) {
+ char[] bucketMaskChar = new char[bucketList.size() + 4];
+ bucketMaskChar[0] = '1';
+ bucketMaskChar[1] = '1';
+ bucketMaskChar[bucketMaskChar.length - 1] = '1';
+ bucketMaskChar[bucketMaskChar.length - 2] = '1';
+ for (int x = 2; x < bucketMaskChar.length - 2; x++) {
+ bucketMaskChar[x] = '0';
+ }
+ _emptyBucketMaskChar = bucketMaskChar;
+ }
+ return _emptyBucketMaskChar.clone();
+ }
+
+ public void updateStorageDirectory(File storageDirectory) {
+ patientBucketMasks.updateStorageDirectory(storageDirectory);
+ }
+}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/CompressedIndex.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/CompressedIndex.java
index edf7c2bd7..224b9273b 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/CompressedIndex.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/CompressedIndex.java
@@ -23,168 +23,158 @@
public class CompressedIndex implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 5089713203903957829L;
- private static final Logger log = LoggerFactory.getLogger(CompressedIndex.class);
- public Float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
- private HashMap, byte[]> compressedRangeMap;
- private int valueCount;
-
- public TreeMap> buildContinuousValuesMap(FileBackedByteIndexedStorage allValues) {
- TreeMap> continuousValueMap = new TreeMap<>();
- for(String key : allValues.keys()) {
- try{
- Float DoubleValue = Float.parseFloat(key.trim());
- TreeSet currentValues = continuousValueMap.get(DoubleValue);
- if(currentValues == null) {
- currentValues = new TreeSet<>();
- continuousValueMap.put(DoubleValue, currentValues);
- }
- currentValues.add(key);
- continuousValueMap.put(DoubleValue, currentValues);
- setMinAndMax(DoubleValue);
- }catch(NumberFormatException e) {
- String[] valuesInKey = key.split(",");
- if(valuesInKey.length > 1) {
- for(String value : valuesInKey) {
- try {
- Float DoubleValue = Float.parseFloat(value.trim());
- TreeSet currentValues = continuousValueMap.get(DoubleValue);
- if(currentValues == null) {
- currentValues = new TreeSet<>();
- continuousValueMap.put(DoubleValue, currentValues);
- }
- currentValues.add(key);
- continuousValueMap.put(DoubleValue, currentValues);
- setMinAndMax(DoubleValue);
- }catch(NumberFormatException e3) {
- log.info("Unable to parse value : " + value.trim());
- }
- }
- }
- }
- }
- this.setValueCount(continuousValueMap.size());
- return continuousValueMap;
- }
-
- private void setMinAndMax(Float DoubleValue) {
- if(min > DoubleValue) {
- min = DoubleValue;
- }
- if(max < DoubleValue) {
- max = DoubleValue;
- }
- }
-
- public void buildIndex(TreeMap> continuousValueMap) {
- Set continuousValuesMapKeys = new TreeSet(continuousValueMap.keySet());
- List> partitions = Lists.partition(new ArrayList(continuousValuesMapKeys), 1000);
- HashMap, TreeMap>> rangeMap = new HashMap<>();
- List partition = partitions.get(0);
- SortedMap> partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size()-1));
- rangeMap.put(
- Range.openClosed(partition.get(0), partition.get(partition.size()-1)),
- new TreeMap<>(partitionMap));
- for(int x = 0; x < partitions.size()-1; x++) {
- partition = partitions.get(x);
- partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size()-1));
- rangeMap.put(Range.openClosed(partition.get(0), partitions.get(x+1).get(0)), new TreeMap<>(partitionMap));
- }
- partition = partitions.get(partitions.size()-1);
- partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size()-1));
- rangeMap.put(Range.openClosed(partition.get(0), partition.get(partition.size()-1)), new TreeMap<>(partitionMap));
- compressedRangeMap = new HashMap<>(rangeMap.entrySet().stream().collect(
- Collectors.toMap(
- (key)->{return key.getKey();},
- (part)->{
- byte[] compressed = null;
- try(
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- GZIPOutputStream gzos = new GZIPOutputStream(baos);
- ObjectOutputStream out = new ObjectOutputStream(gzos);
- ){
- out.writeObject(part.getValue());
- out.flush();
- out.close();
- gzos.flush();
- gzos.close();
- compressed = baos.toByteArray();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- return compressed;
- })
- ));
- }
-
- public List getValuesInRange(Range targetRange) {
-
- log.debug("Getting valuesInRange : " + targetRange);
- // Get a list of ranges that are connected to the target range
- List connectedRanges = compressedRangeMap.keySet().stream().filter((range)->{
- return range.isConnected(targetRange);
- }).collect(Collectors.toList());
-
- // Get a list of ranges that enclose the target range completely
- List enclosingRanges = connectedRanges.stream().filter((range)->{
- return targetRange.encloses(range);
- }).collect(Collectors.toList());
-
- List valuesInRange = new ArrayList<>();
-
- // Add all variants from enclosing ranges
- enclosingRanges.forEach(
- range->{
- TreeMap> continousValueMap = retrieveRangeMap(range);
- continousValueMap.values().forEach(
- variantSet->{
- valuesInRange.addAll(variantSet);
- });
- });
-
- // We already added all variants in the enclosing ranges
- connectedRanges.removeAll(enclosingRanges);
-
- connectedRanges.forEach(
- range ->{
- TreeMap> continousValueMap = retrieveRangeMap(range);
- log.debug("Searching within : " + range.lowerEndpoint() + " : " + range.upperEndpoint());
- continousValueMap.entrySet().stream().forEach(
- entry->{
- if(targetRange.contains(entry.getKey())) {
- log.debug("Adding : " + entry.getValue().first() + " : " + entry.getValue().last());
- valuesInRange.addAll(entry.getValue());
- }
- });
- });
- return valuesInRange;
- }
-
- private TreeMap> retrieveRangeMap(Range range) {
- TreeMap> continousValueMap = null;
- try(
- ByteArrayInputStream bais = new ByteArrayInputStream(compressedRangeMap.get(range));
- GZIPInputStream gzis = new GZIPInputStream(bais);
- ObjectInputStream ois = new ObjectInputStream(gzis);
- ){
- continousValueMap = (TreeMap>)ois.readObject();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
- return continousValueMap;
- }
-
- public int getValueCount() {
- return valueCount;
- }
-
- public void setValueCount(int valueCount) {
- this.valueCount = valueCount;
- }
+ /**
+ *
+ */
+ private static final long serialVersionUID = 5089713203903957829L;
+ private static final Logger log = LoggerFactory.getLogger(CompressedIndex.class);
+ public Float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
+ private HashMap, byte[]> compressedRangeMap;
+ private int valueCount;
+
+ public TreeMap> buildContinuousValuesMap(FileBackedByteIndexedStorage allValues) {
+ TreeMap> continuousValueMap = new TreeMap<>();
+ for (String key : allValues.keys()) {
+ try {
+ Float DoubleValue = Float.parseFloat(key.trim());
+ TreeSet currentValues = continuousValueMap.get(DoubleValue);
+ if (currentValues == null) {
+ currentValues = new TreeSet<>();
+ continuousValueMap.put(DoubleValue, currentValues);
+ }
+ currentValues.add(key);
+ continuousValueMap.put(DoubleValue, currentValues);
+ setMinAndMax(DoubleValue);
+ } catch (NumberFormatException e) {
+ String[] valuesInKey = key.split(",");
+ if (valuesInKey.length > 1) {
+ for (String value : valuesInKey) {
+ try {
+ Float DoubleValue = Float.parseFloat(value.trim());
+ TreeSet currentValues = continuousValueMap.get(DoubleValue);
+ if (currentValues == null) {
+ currentValues = new TreeSet<>();
+ continuousValueMap.put(DoubleValue, currentValues);
+ }
+ currentValues.add(key);
+ continuousValueMap.put(DoubleValue, currentValues);
+ setMinAndMax(DoubleValue);
+ } catch (NumberFormatException e3) {
+ log.info("Unable to parse value : " + value.trim());
+ }
+ }
+ }
+ }
+ }
+ this.setValueCount(continuousValueMap.size());
+ return continuousValueMap;
+ }
+
+ private void setMinAndMax(Float DoubleValue) {
+ if (min > DoubleValue) {
+ min = DoubleValue;
+ }
+ if (max < DoubleValue) {
+ max = DoubleValue;
+ }
+ }
+
+ public void buildIndex(TreeMap> continuousValueMap) {
+ Set continuousValuesMapKeys = new TreeSet(continuousValueMap.keySet());
+ List> partitions = Lists.partition(new ArrayList(continuousValuesMapKeys), 1000);
+ HashMap, TreeMap>> rangeMap = new HashMap<>();
+ List partition = partitions.get(0);
+ SortedMap> partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size() - 1));
+ rangeMap.put(Range.openClosed(partition.get(0), partition.get(partition.size() - 1)), new TreeMap<>(partitionMap));
+ for (int x = 0; x < partitions.size() - 1; x++) {
+ partition = partitions.get(x);
+ partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size() - 1));
+ rangeMap.put(Range.openClosed(partition.get(0), partitions.get(x + 1).get(0)), new TreeMap<>(partitionMap));
+ }
+ partition = partitions.get(partitions.size() - 1);
+ partitionMap = continuousValueMap.subMap(partition.get(0), partition.get(partition.size() - 1));
+ rangeMap.put(Range.openClosed(partition.get(0), partition.get(partition.size() - 1)), new TreeMap<>(partitionMap));
+ compressedRangeMap = new HashMap<>(rangeMap.entrySet().stream().collect(Collectors.toMap((key) -> {
+ return key.getKey();
+ }, (part) -> {
+ byte[] compressed = null;
+ try (
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzos =
+ new GZIPOutputStream(baos); ObjectOutputStream out = new ObjectOutputStream(gzos);
+ ) {
+ out.writeObject(part.getValue());
+ out.flush();
+ out.close();
+ gzos.flush();
+ gzos.close();
+ compressed = baos.toByteArray();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ return compressed;
+ })));
+ }
+
+ public List getValuesInRange(Range targetRange) {
+
+ log.debug("Getting valuesInRange : " + targetRange);
+ // Get a list of ranges that are connected to the target range
+ List connectedRanges = compressedRangeMap.keySet().stream().filter((range) -> {
+ return range.isConnected(targetRange);
+ }).collect(Collectors.toList());
+
+ // Get a list of ranges that enclose the target range completely
+ List enclosingRanges = connectedRanges.stream().filter((range) -> {
+ return targetRange.encloses(range);
+ }).collect(Collectors.toList());
+
+ List valuesInRange = new ArrayList<>();
+
+ // Add all variants from enclosing ranges
+ enclosingRanges.forEach(range -> {
+ TreeMap> continousValueMap = retrieveRangeMap(range);
+ continousValueMap.values().forEach(variantSet -> {
+ valuesInRange.addAll(variantSet);
+ });
+ });
+
+ // We already added all variants in the enclosing ranges
+ connectedRanges.removeAll(enclosingRanges);
+
+ connectedRanges.forEach(range -> {
+ TreeMap> continousValueMap = retrieveRangeMap(range);
+ log.debug("Searching within : " + range.lowerEndpoint() + " : " + range.upperEndpoint());
+ continousValueMap.entrySet().stream().forEach(entry -> {
+ if (targetRange.contains(entry.getKey())) {
+ log.debug("Adding : " + entry.getValue().first() + " : " + entry.getValue().last());
+ valuesInRange.addAll(entry.getValue());
+ }
+ });
+ });
+ return valuesInRange;
+ }
+
+ private TreeMap> retrieveRangeMap(Range range) {
+ TreeMap> continousValueMap = null;
+ try (
+ ByteArrayInputStream bais = new ByteArrayInputStream(compressedRangeMap.get(range)); GZIPInputStream gzis =
+ new GZIPInputStream(bais); ObjectInputStream ois = new ObjectInputStream(gzis);
+ ) {
+ continousValueMap = (TreeMap>) ois.readObject();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ return continousValueMap;
+ }
+
+ public int getValueCount() {
+ return valueCount;
+ }
+
+ public void setValueCount(int valueCount) {
+ this.valueCount = valueCount;
+ }
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/FileBackedByteIndexedInfoStore.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/FileBackedByteIndexedInfoStore.java
index 3d730765c..35b6de942 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/FileBackedByteIndexedInfoStore.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/FileBackedByteIndexedInfoStore.java
@@ -15,142 +15,142 @@
public class FileBackedByteIndexedInfoStore implements Serializable {
- private static final long serialVersionUID = 6478256007934827195L;
- private static final Logger log = LoggerFactory.getLogger(FileBackedByteIndexedInfoStore.class);
- public final String column_key;
- public final String description;
- public boolean isContinuous;
- public Float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
-
- private FileBackedByteIndexedStorage allValues;
- public TreeMap> continuousValueMap;
-
- public CompressedIndex continuousValueIndex;
-
- public FileBackedByteIndexedStorage getAllValues() {
- return allValues;
- }
-
- public List search(String term) {
- if(isContinuous) {
- return new ArrayList();
- }else {
- return allValues.keys().stream().filter((value)->{
- String lowerTerm = term.toLowerCase(Locale.ENGLISH);
- return value.toLowerCase(Locale.ENGLISH).contains(lowerTerm);
- }).collect(Collectors.toList());
- }
- }
-
- public void addEntry(String value, Integer[] variantIds) throws IOException {
- allValues.put(value, variantIds);
- }
-
-
- public void complete() {
- this.allValues.complete();
- }
-
- public FileBackedByteIndexedInfoStore(File storageFolder, InfoStore infoStore) throws IOException {
- this.allValues = new FileBackedStorageVariantIndexImpl(new File(storageFolder, infoStore.column_key + "_infoStoreStorage.javabin"));
- this.description = infoStore.description;
- this.column_key = infoStore.column_key;
- this.isContinuous = infoStore.isNumeric();
- this.allValues.open();
- if(isContinuous) {
- normalizeNumericStore(infoStore);
- }
- TreeSet sortedKeys = new TreeSet(infoStore.allValues.keySet());
- log.debug(infoStore.column_key + " : " + sortedKeys.size() + " values");
- int x = 0;
- for(String key : sortedKeys){
- if(key.contentEquals(".")) {
- log.debug("Skipping . value for " + infoStore.column_key);
- }else {
- if(x%10000 == 0) {
- log.debug(infoStore.column_key + " " + ((((double)x) / sortedKeys.size()) * 100) + "% done");
- }
- ConcurrentSkipListSet variantIds = infoStore.allValues.get(key);
- addEntry(key, variantIds.toArray(new Integer[variantIds.size()]));
- x++;
- }
- }
- this.allValues.complete();
- if(isContinuous) {
- log.debug(this.column_key + " is continuous, building continuousValueIndex and nulling continuousValueMap.");
- this.continuousValueIndex = new CompressedIndex();
- TreeMap> continuousValueMap = this.continuousValueIndex.buildContinuousValuesMap(this.allValues);
- this.continuousValueIndex.buildIndex(continuousValueMap);
- this.continuousValueMap = null;
- }
- }
-
- private static void normalizeNumericStore(InfoStore store) {
- TreeSet allKeys = new TreeSet(store.allValues.keySet());
-
- ConcurrentHashMap> normalizedValues = new ConcurrentHashMap<>();
- for(String key : allKeys) {
- String[] keys = key.split(",");
- ConcurrentSkipListSet variantIds = store.allValues.get(key);
- if(key.contentEquals(".")) {
- //don't add it
- }else if(keyHasMultipleValues(keys)) {
- for(String value : keys) {
- if(value.contentEquals(".")) {
-
- }else {
- ConcurrentSkipListSet normalizedVariantIds = normalizedValues.get(value);
- if(normalizedVariantIds == null) {
- normalizedVariantIds = variantIds;
- }else {
- normalizedVariantIds.addAll(variantIds);
- }
- normalizedValues.put(value, normalizedVariantIds);
- }
- }
- }else {
- if(key.contentEquals(".")) {
-
- }else {
- ConcurrentSkipListSet normalizedVariantIds = normalizedValues.get(key);
- if(normalizedVariantIds == null) {
- normalizedVariantIds = variantIds;
- }else {
- normalizedVariantIds.addAll(variantIds);
- }
- normalizedValues.put(key, normalizedVariantIds);
- }
- }
-
- }
- store.allValues = normalizedValues;
- }
-
- private static boolean keyHasMultipleValues(String[] keys) {
- int x = 0;
- for(String k : keys) {
- if(k == null || k.isEmpty()) {
-
- }else {
- x++;
- }
- }
- return x>1;
- }
-
- public void updateStorageDirectory(File storageDirectory) {
- allValues.updateStorageDirectory(storageDirectory);
- }
-
- public void write(File outputFile) {
- try(
- FileOutputStream fos = new FileOutputStream(outputFile);
- GZIPOutputStream gzos = new GZIPOutputStream(fos);
- ObjectOutputStream oos = new ObjectOutputStream(gzos);) {
- oos.writeObject(this);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
+ private static final long serialVersionUID = 6478256007934827195L;
+ private static final Logger log = LoggerFactory.getLogger(FileBackedByteIndexedInfoStore.class);
+ public final String column_key;
+ public final String description;
+ public boolean isContinuous;
+ public Float min = Float.MAX_VALUE, max = Float.MIN_VALUE;
+
+ private FileBackedByteIndexedStorage allValues;
+ public TreeMap> continuousValueMap;
+
+ public CompressedIndex continuousValueIndex;
+
+ public FileBackedByteIndexedStorage getAllValues() {
+ return allValues;
+ }
+
+ public List search(String term) {
+ if (isContinuous) {
+ return new ArrayList();
+ } else {
+ return allValues.keys().stream().filter((value) -> {
+ String lowerTerm = term.toLowerCase(Locale.ENGLISH);
+ return value.toLowerCase(Locale.ENGLISH).contains(lowerTerm);
+ }).collect(Collectors.toList());
+ }
+ }
+
+ public void addEntry(String value, Integer[] variantIds) throws IOException {
+ allValues.put(value, variantIds);
+ }
+
+
+ public void complete() {
+ this.allValues.complete();
+ }
+
+ public FileBackedByteIndexedInfoStore(File storageFolder, InfoStore infoStore) throws IOException {
+ this.allValues = new FileBackedStorageVariantIndexImpl(new File(storageFolder, infoStore.column_key + "_infoStoreStorage.javabin"));
+ this.description = infoStore.description;
+ this.column_key = infoStore.column_key;
+ this.isContinuous = infoStore.isNumeric();
+ this.allValues.open();
+ if (isContinuous) {
+ normalizeNumericStore(infoStore);
+ }
+ TreeSet sortedKeys = new TreeSet(infoStore.allValues.keySet());
+ log.debug(infoStore.column_key + " : " + sortedKeys.size() + " values");
+ int x = 0;
+ for (String key : sortedKeys) {
+ if (key.contentEquals(".")) {
+ log.debug("Skipping . value for " + infoStore.column_key);
+ } else {
+ if (x % 10000 == 0) {
+ log.debug(infoStore.column_key + " " + ((((double) x) / sortedKeys.size()) * 100) + "% done");
+ }
+ ConcurrentSkipListSet variantIds = infoStore.allValues.get(key);
+ addEntry(key, variantIds.toArray(new Integer[variantIds.size()]));
+ x++;
+ }
+ }
+ this.allValues.complete();
+ if (isContinuous) {
+ log.debug(this.column_key + " is continuous, building continuousValueIndex and nulling continuousValueMap.");
+ this.continuousValueIndex = new CompressedIndex();
+ TreeMap> continuousValueMap = this.continuousValueIndex.buildContinuousValuesMap(this.allValues);
+ this.continuousValueIndex.buildIndex(continuousValueMap);
+ this.continuousValueMap = null;
+ }
+ }
+
+ private static void normalizeNumericStore(InfoStore store) {
+ TreeSet allKeys = new TreeSet(store.allValues.keySet());
+
+ ConcurrentHashMap> normalizedValues = new ConcurrentHashMap<>();
+ for (String key : allKeys) {
+ String[] keys = key.split(",");
+ ConcurrentSkipListSet variantIds = store.allValues.get(key);
+ if (key.contentEquals(".")) {
+ // don't add it
+ } else if (keyHasMultipleValues(keys)) {
+ for (String value : keys) {
+ if (value.contentEquals(".")) {
+
+ } else {
+ ConcurrentSkipListSet normalizedVariantIds = normalizedValues.get(value);
+ if (normalizedVariantIds == null) {
+ normalizedVariantIds = variantIds;
+ } else {
+ normalizedVariantIds.addAll(variantIds);
+ }
+ normalizedValues.put(value, normalizedVariantIds);
+ }
+ }
+ } else {
+ if (key.contentEquals(".")) {
+
+ } else {
+ ConcurrentSkipListSet normalizedVariantIds = normalizedValues.get(key);
+ if (normalizedVariantIds == null) {
+ normalizedVariantIds = variantIds;
+ } else {
+ normalizedVariantIds.addAll(variantIds);
+ }
+ normalizedValues.put(key, normalizedVariantIds);
+ }
+ }
+
+ }
+ store.allValues = normalizedValues;
+ }
+
+ private static boolean keyHasMultipleValues(String[] keys) {
+ int x = 0;
+ for (String k : keys) {
+ if (k == null || k.isEmpty()) {
+
+ } else {
+ x++;
+ }
+ }
+ return x > 1;
+ }
+
+ public void updateStorageDirectory(File storageDirectory) {
+ allValues.updateStorageDirectory(storageDirectory);
+ }
+
+ public void write(File outputFile) {
+ try (
+ FileOutputStream fos = new FileOutputStream(outputFile); GZIPOutputStream gzos =
+ new GZIPOutputStream(fos); ObjectOutputStream oos = new ObjectOutputStream(gzos);
+ ) {
+ oos.writeObject(this);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/InfoStore.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/InfoStore.java
index 272d32caf..8669df967 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/InfoStore.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/InfoStore.java
@@ -13,79 +13,79 @@
import java.util.stream.Collectors;
public class InfoStore implements Serializable {
-
- private static final long serialVersionUID = 6478256007934827195L;
- private static final Logger log = LoggerFactory.getLogger(InfoStore.class);
- public final String column_key;
- public final String description;
- public ConcurrentHashMap> allValues = new ConcurrentHashMap<>();
- private String prefix;
+ private static final long serialVersionUID = 6478256007934827195L;
+ private static final Logger log = LoggerFactory.getLogger(InfoStore.class);
+ public final String column_key;
+ public final String description;
- public List search(String term) {
- if(isNumeric()) {
- return new ArrayList();
- }else {
- return allValues.keySet().stream().filter((value)->{
- String lowerTerm = term.toLowerCase(Locale.ENGLISH);
- return value.toLowerCase(Locale.ENGLISH).contains(lowerTerm);
- }).collect(Collectors.toList());
- }
- }
+ public ConcurrentHashMap> allValues = new ConcurrentHashMap<>();
+ private String prefix;
- public InfoStore(String description, String delimiter, String key) {
- this.prefix = key + "=";
- this.description = description;
- this.column_key = key;
- }
+ public List search(String term) {
+ if (isNumeric()) {
+ return new ArrayList();
+ } else {
+ return allValues.keySet().stream().filter((value) -> {
+ String lowerTerm = term.toLowerCase(Locale.ENGLISH);
+ return value.toLowerCase(Locale.ENGLISH).contains(lowerTerm);
+ }).collect(Collectors.toList());
+ }
+ }
- public boolean isNumeric() {
- int nonNumericCount = 0;
- int numericCount = 0;
- log.debug("Testing for numeric : " + this.column_key + " : " + allValues.size() + " values");
- KeySetView> allKeys = allValues.keySet();
- for(String key : allKeys){
- try {
- Double.parseDouble(key);
- numericCount++;
- }catch(NumberFormatException e) {
- String[] keys = key.split(",");
- for(String key2 : keys) {
- try {
- Double.parseDouble(key2);
- numericCount++;
- }catch(NumberFormatException e2) {
- if(key.contentEquals(".")) {
- nonNumericCount++;
- }
- }
- }
- }
- if(nonNumericCount > 1) {
- log.debug(this.column_key + " is not numeric");
- return false;
- }
- if(numericCount > 10000 || numericCount > (allKeys.size()/2)) {
- log.debug(this.column_key + " is numeric");
- return true;
- }
- };
- log.debug(this.column_key + " is not numeric");
- return false;
- }
+ public InfoStore(String description, String delimiter, String key) {
+ this.prefix = key + "=";
+ this.description = description;
+ this.column_key = key;
+ }
- public void processRecord(Integer variantId, String[] infoValues) {
- for(String value : infoValues) {
- if(value.startsWith(prefix)) {
- String valueWithoutkey = value.substring(prefix.length());
- ConcurrentSkipListSet entriesForValue = allValues.get(valueWithoutkey);
- if(entriesForValue == null) {
- entriesForValue = new ConcurrentSkipListSet<>();
- allValues.put(valueWithoutkey, entriesForValue);
- }
- entriesForValue.add(variantId);
- }
- }
- }
+ public boolean isNumeric() {
+ int nonNumericCount = 0;
+ int numericCount = 0;
+ log.debug("Testing for numeric : " + this.column_key + " : " + allValues.size() + " values");
+ KeySetView> allKeys = allValues.keySet();
+ for (String key : allKeys) {
+ try {
+ Double.parseDouble(key);
+ numericCount++;
+ } catch (NumberFormatException e) {
+ String[] keys = key.split(",");
+ for (String key2 : keys) {
+ try {
+ Double.parseDouble(key2);
+ numericCount++;
+ } catch (NumberFormatException e2) {
+ if (key.contentEquals(".")) {
+ nonNumericCount++;
+ }
+ }
+ }
+ }
+ if (nonNumericCount > 1) {
+ log.debug(this.column_key + " is not numeric");
+ return false;
+ }
+ if (numericCount > 10000 || numericCount > (allKeys.size() / 2)) {
+ log.debug(this.column_key + " is numeric");
+ return true;
+ }
+ } ;
+ log.debug(this.column_key + " is not numeric");
+ return false;
+ }
-}
\ No newline at end of file
+ public void processRecord(Integer variantId, String[] infoValues) {
+ for (String value : infoValues) {
+ if (value.startsWith(prefix)) {
+ String valueWithoutkey = value.substring(prefix.length());
+ ConcurrentSkipListSet entriesForValue = allValues.get(valueWithoutkey);
+ if (entriesForValue == null) {
+ entriesForValue = new ConcurrentSkipListSet<>();
+ allValues.put(valueWithoutkey, entriesForValue);
+ }
+ entriesForValue.add(variantId);
+ }
+ }
+ }
+
+}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariableVariantMasks.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariableVariantMasks.java
index 7c56828f5..cebb3fffd 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariableVariantMasks.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariableVariantMasks.java
@@ -13,257 +13,251 @@
public class VariableVariantMasks implements Serializable {
- private static Logger log = LoggerFactory.getLogger(VariableVariantMasks.class);
-
- private static final long serialVersionUID = 6225420483804601477L;
- private static final String oneone = "11";
- private static final char one = '1';
- private static final char zero = '0';
- private static final String hetero = "0/1";
- private static final String heteroDel = "1/0";
- private static final String heteroPhased = "0|1";
- private static final String heteroPhased2 = "1|0";
- private static final String homo = "1/1";
- private static final String homoPhased = "1|1";
- private static final String homoNoCall = "./.";
- private static final String heteroNoCall = "./1";
-
- private static Map emptyBitmaskMap = new ConcurrentHashMap<>();
-
- public static int SPARSE_VARIANT_THRESHOLD = 5;
-
- /*
- * These indices result from the char values of the 3 characters in a VCF sample
- * record summed as integers % 7
- *
- * This allows us to not actually do string comparisons, instead we add 3 values,
- * do one modulus operation, then use the result as the index into the result array.
- */
-
- // ./0 = (46 + 47 + 48) % 7 = 1
- // 0|. = (48 + 124 + 46) % 7 = 1
- // .|0 = (46 + 124 + 48) % 7 = 1
- public static final int HETERO_NOCALL_REF_CHAR_INDEX = 1;
-
- // ./1 = (46 + 47 + 49) % 7 = 2
- // 1|. = (49 + 124 + 46) % 7 = 2
- // .|1 = (46 + 124 + 49) % 7 = 2
- // ./1 = (46 + 47 + 49) % 7 = 2
- // 1|. = (49 + 124 + 46) % 7 = 2
- // .|1 = (46 + 124 + 49) % 7 = 2
- public static final int HETERO_NOCALL_VARIANT_CHAR_INDEX = 2;
-
- // 0/0 = (48 + 47 + 48) % 7 = 3
- // 0|0 = (48 + 124 + 48) % 7 = 3
- public static final int ZERO_ZERO_CHAR_INDEX = 3;
-
- // 0/1 = (48 + 47 + 49) % 7 = 4
- // 1|0 = (49 + 124 + 48) % 7 = 4
- // 0|1 = (48 + 124 + 49) % 7 = 4
- public static final int ZERO_ONE_CHAR_INDEX = 4;
-
- // 1/1 = (49 + 47 + 49) % 7 = 5
- // 1|1 = (49 + 124 + 49) % 7 = 5
- public static final int ONE_ONE_CHAR_INDEX = 5;
-
- // ./. = (46 + 47 + 46) % 7 = 6
- // .|. = (46 + 124 + 46) % 7 = 6
- public static final int HOMO_NOCALL_CHAR_INDEX = 6;
-
- public VariableVariantMasks(char[][] maskValues) {
- String heteroMaskStringRaw = new String(maskValues[ZERO_ONE_CHAR_INDEX]);
- String homoMaskStringRaw = new String(maskValues[ONE_ONE_CHAR_INDEX]);
- String heteroNoCallMaskStringRaw = new String(maskValues[HETERO_NOCALL_VARIANT_CHAR_INDEX]);
- String homoNoCallMaskStringRaw = new String(maskValues[HOMO_NOCALL_CHAR_INDEX]);
-
- heterozygousMask = variantMaskFromRawString(heteroMaskStringRaw);
- homozygousMask = variantMaskFromRawString(homoMaskStringRaw);
- heterozygousNoCallMask = variantMaskFromRawString(heteroNoCallMaskStringRaw);
- homozygousNoCallMask = variantMaskFromRawString(homoNoCallMaskStringRaw);
- }
-
- private VariantMask variantMaskFromRawString(String maskStringRaw) {
- if (!maskStringRaw.contains("1")) {
- return null;
- }
-
- VariantMask variantMask;
- BigInteger bitmask = new BigInteger(oneone + new StringBuilder(maskStringRaw).reverse() + oneone, 2);
- if (bitmask.bitCount() - 4 > VariableVariantMasks.SPARSE_VARIANT_THRESHOLD) {
- variantMask = new VariantMaskBitmaskImpl(bitmask);
- } else {
- Set patientIndexes = new HashSet<>();
- for(int i = 0; i < bitmask.bitLength() - 4; i++) {
- // i + 2 because the mask is padded with 2 bits on each end
- if (bitmask.testBit(i + 2)) {
- patientIndexes.add(i);
- }
- }
- variantMask = new VariantMaskSparseImpl(patientIndexes);
- }
- return variantMask;
- }
-
- public VariableVariantMasks() {
- }
-
- @JsonProperty("ho")
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public VariantMask homozygousMask;
-
- @JsonProperty("he")
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public VariantMask heterozygousMask;
-
- @JsonProperty("hon")
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public VariantMask homozygousNoCallMask;
-
- @JsonProperty("hen")
- @JsonInclude(JsonInclude.Include.NON_NULL)
- public VariantMask heterozygousNoCallMask;
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- VariableVariantMasks that = (VariableVariantMasks) o;
- return Objects.equals(homozygousMask, that.homozygousMask) && Objects.equals(heterozygousMask, that.heterozygousMask) && Objects.equals(homozygousNoCallMask, that.homozygousNoCallMask) && Objects.equals(heterozygousNoCallMask, that.heterozygousNoCallMask);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(homozygousMask, heterozygousMask, homozygousNoCallMask, heterozygousNoCallMask);
- }
-
- public static BigInteger emptyBitmask(int length) {
- BigInteger emptyBitmask = emptyBitmaskMap.get(length);
- if (emptyBitmask == null) {
- String emptyVariantMask = "";
- for (int i = 0; i < length; i++) {
- emptyVariantMask = emptyVariantMask + "0";
- }
- BigInteger newEmptyBitmask = new BigInteger("11" + emptyVariantMask + "11", 2);
- emptyBitmaskMap.put(length, newEmptyBitmask);
- return newEmptyBitmask;
- }
- return emptyBitmask;
- }
-
- public static VariableVariantMasks append(VariableVariantMasks masks1, int length1, VariableVariantMasks masks2, int length2) {
- VariableVariantMasks appendedMasks = new VariableVariantMasks();
- appendedMasks.homozygousMask = appendMask(masks1.homozygousMask, masks2.homozygousMask, length1, length2);
- appendedMasks.heterozygousMask = appendMask(masks1.heterozygousMask, masks2.heterozygousMask, length1, length2);
- appendedMasks.homozygousNoCallMask = appendMask(masks1.homozygousNoCallMask, masks2.homozygousNoCallMask, length1, length2);
- appendedMasks.heterozygousNoCallMask = appendMask(masks1.heterozygousNoCallMask, masks2.heterozygousNoCallMask, length1, length2);
- return appendedMasks;
- }
-
- public static VariantMask appendMask(VariantMask variantMask1, VariantMask variantMask2, int length1, int length2) {
- if (variantMask1 == null) {
- variantMask1 = VariantMask.emptyInstance();
- }
- if (variantMask2 == null) {
- variantMask2 = VariantMask.emptyInstance();
- }
- if (variantMask1.equals(VariantMask.emptyInstance()) && variantMask2.equals(VariantMask.emptyInstance())) {
- return null;
- }
-
- if (variantMask1 instanceof VariantMaskSparseImpl) {
- if (variantMask2 instanceof VariantMaskSparseImpl) {
- return append((VariantMaskSparseImpl) variantMask1, (VariantMaskSparseImpl) variantMask2, length1, length2);
- } else if (variantMask2 instanceof VariantMaskBitmaskImpl) {
- return append((VariantMaskSparseImpl) variantMask1, (VariantMaskBitmaskImpl) variantMask2, length1, length2);
- } else {
- throw new RuntimeException("Unknown VariantMask implementation");
- }
- }
- else if (variantMask1 instanceof VariantMaskBitmaskImpl) {
- if (variantMask2 instanceof VariantMaskSparseImpl) {
- return append((VariantMaskBitmaskImpl) variantMask1, (VariantMaskSparseImpl) variantMask2, length1, length2);
- } else if (variantMask2 instanceof VariantMaskBitmaskImpl) {
- return append((VariantMaskBitmaskImpl) variantMask1, (VariantMaskBitmaskImpl) variantMask2, length1, length2);
- } else {
- throw new RuntimeException("Unknown VariantMask implementation");
- }
- }
- else {
- throw new RuntimeException("Unknown VariantMask implementation");
- }
- }
-
- private static VariantMask append(VariantMaskSparseImpl variantMask1, VariantMaskBitmaskImpl variantMask2, int length1, int length2) {
- BigInteger mask1 = emptyBitmask(length1);
- for (Integer patientIndex : variantMask1.patientIndexes) {
- mask1 = mask1.setBit(patientIndex + 2);
- }
- String binaryMask1 = mask1.toString(2);
-
- String binaryMask2 = variantMask2.bitmask.toString(2);
- if (binaryMask2.length() - 4 != length2) {
- throw new IllegalArgumentException("Bitmask does not match length (" + length2 + "): " + variantMask2.bitmask);
- }
-
- String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) +
- binaryMask1.substring(2);
- return new VariantMaskBitmaskImpl(new BigInteger(appendedString, 2));
- }
-
- private static VariantMask append(VariantMaskBitmaskImpl variantMask1, VariantMaskSparseImpl variantMask2, int length1, int length2) {
- String binaryMask1 = variantMask1.bitmask.toString(2);
- if (binaryMask1.length() - 4 != length1) {
- throw new IllegalArgumentException("Bitmask does not match length (" + length1 + "): " + variantMask1.bitmask);
- }
-
- BigInteger mask2 = emptyBitmask(length2);
- for (Integer patientId : variantMask2.patientIndexes) {
- mask2 = mask2.setBit(patientId + 2);
- }
- String binaryMask2 = mask2.toString(2);
-
- String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) +
- binaryMask1.substring(2);
- return new VariantMaskBitmaskImpl(new BigInteger(appendedString, 2));
- }
-
- private static VariantMask append(VariantMaskBitmaskImpl variantMask1, VariantMaskBitmaskImpl variantMask2, int length1, int length2) {
- String binaryMask1 = variantMask1.bitmask.toString(2);
- String binaryMask2 = variantMask2.bitmask.toString(2);
-
- if (binaryMask1.length() - 4 != length1) {
- throw new IllegalArgumentException("Bitmask does not match length (" + length1 + "): " + variantMask1.bitmask);
- }
- if (binaryMask2.length() - 4 != length2) {
- throw new IllegalArgumentException("Bitmask does not match length (" + length2 + "): " + variantMask2.bitmask);
- }
-
- String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) +
- binaryMask1.substring(2);
- BigInteger bitmask = new BigInteger(appendedString, 2);
- return new VariantMaskBitmaskImpl(bitmask);
- }
-
- private static VariantMask append(VariantMaskSparseImpl variantMask1, VariantMaskSparseImpl variantMask2, int length1, int length2) {
- if (variantMask1.patientIndexes.size() + variantMask2.patientIndexes.size() > SPARSE_VARIANT_THRESHOLD) {
- BigInteger mask = emptyBitmask(length1 + length2);
- for (Integer patientId : variantMask1.patientIndexes) {
- mask = mask.setBit(patientId + 2);
- }
- // We start writing mask 2 where mask 1 ends. So the 0th index of mask 2 is now following the last bit of mask 1
- for (Integer patientId : variantMask2.patientIndexes) {
- mask = mask.setBit(patientId + length1 + 2);
- }
- return new VariantMaskBitmaskImpl(mask);
- }
- else {
- Set patientIndexSet = new HashSet<>();
- patientIndexSet.addAll(variantMask1.patientIndexes);
- // The indexes for mask 2 are shifted by the length of mask 1, corresponding to the corresponding patient id array
- // for mask 2 being appended to those of mask 1
- patientIndexSet.addAll(variantMask2.patientIndexes.stream().map(i -> i + length1).collect(Collectors.toSet()));
- return new VariantMaskSparseImpl(patientIndexSet);
- }
- }
+ private static Logger log = LoggerFactory.getLogger(VariableVariantMasks.class);
+
+ private static final long serialVersionUID = 6225420483804601477L;
+ private static final String oneone = "11";
+ private static final char one = '1';
+ private static final char zero = '0';
+ private static final String hetero = "0/1";
+ private static final String heteroDel = "1/0";
+ private static final String heteroPhased = "0|1";
+ private static final String heteroPhased2 = "1|0";
+ private static final String homo = "1/1";
+ private static final String homoPhased = "1|1";
+ private static final String homoNoCall = "./.";
+ private static final String heteroNoCall = "./1";
+
+ private static Map emptyBitmaskMap = new ConcurrentHashMap<>();
+
+ public static int SPARSE_VARIANT_THRESHOLD = 5;
+
+ /*
+ * These indices result from the char values of the 3 characters in a VCF sample record summed as integers % 7
+ *
+ * This allows us to not actually do string comparisons, instead we add 3 values, do one modulus operation, then use the result as the
+ * index into the result array.
+ */
+
+ // ./0 = (46 + 47 + 48) % 7 = 1
+ // 0|. = (48 + 124 + 46) % 7 = 1
+ // .|0 = (46 + 124 + 48) % 7 = 1
+ public static final int HETERO_NOCALL_REF_CHAR_INDEX = 1;
+
+ // ./1 = (46 + 47 + 49) % 7 = 2
+ // 1|. = (49 + 124 + 46) % 7 = 2
+ // .|1 = (46 + 124 + 49) % 7 = 2
+ // ./1 = (46 + 47 + 49) % 7 = 2
+ // 1|. = (49 + 124 + 46) % 7 = 2
+ // .|1 = (46 + 124 + 49) % 7 = 2
+ public static final int HETERO_NOCALL_VARIANT_CHAR_INDEX = 2;
+
+ // 0/0 = (48 + 47 + 48) % 7 = 3
+ // 0|0 = (48 + 124 + 48) % 7 = 3
+ public static final int ZERO_ZERO_CHAR_INDEX = 3;
+
+ // 0/1 = (48 + 47 + 49) % 7 = 4
+ // 1|0 = (49 + 124 + 48) % 7 = 4
+ // 0|1 = (48 + 124 + 49) % 7 = 4
+ public static final int ZERO_ONE_CHAR_INDEX = 4;
+
+ // 1/1 = (49 + 47 + 49) % 7 = 5
+ // 1|1 = (49 + 124 + 49) % 7 = 5
+ public static final int ONE_ONE_CHAR_INDEX = 5;
+
+ // ./. = (46 + 47 + 46) % 7 = 6
+ // .|. = (46 + 124 + 46) % 7 = 6
+ public static final int HOMO_NOCALL_CHAR_INDEX = 6;
+
+ public VariableVariantMasks(char[][] maskValues) {
+ String heteroMaskStringRaw = new String(maskValues[ZERO_ONE_CHAR_INDEX]);
+ String homoMaskStringRaw = new String(maskValues[ONE_ONE_CHAR_INDEX]);
+ String heteroNoCallMaskStringRaw = new String(maskValues[HETERO_NOCALL_VARIANT_CHAR_INDEX]);
+ String homoNoCallMaskStringRaw = new String(maskValues[HOMO_NOCALL_CHAR_INDEX]);
+
+ heterozygousMask = variantMaskFromRawString(heteroMaskStringRaw);
+ homozygousMask = variantMaskFromRawString(homoMaskStringRaw);
+ heterozygousNoCallMask = variantMaskFromRawString(heteroNoCallMaskStringRaw);
+ homozygousNoCallMask = variantMaskFromRawString(homoNoCallMaskStringRaw);
+ }
+
+ private VariantMask variantMaskFromRawString(String maskStringRaw) {
+ if (!maskStringRaw.contains("1")) {
+ return null;
+ }
+
+ VariantMask variantMask;
+ BigInteger bitmask = new BigInteger(oneone + new StringBuilder(maskStringRaw).reverse() + oneone, 2);
+ if (bitmask.bitCount() - 4 > VariableVariantMasks.SPARSE_VARIANT_THRESHOLD) {
+ variantMask = new VariantMaskBitmaskImpl(bitmask);
+ } else {
+ Set patientIndexes = new HashSet<>();
+ for (int i = 0; i < bitmask.bitLength() - 4; i++) {
+ // i + 2 because the mask is padded with 2 bits on each end
+ if (bitmask.testBit(i + 2)) {
+ patientIndexes.add(i);
+ }
+ }
+ variantMask = new VariantMaskSparseImpl(patientIndexes);
+ }
+ return variantMask;
+ }
+
+ public VariableVariantMasks() {}
+
+ @JsonProperty("ho")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public VariantMask homozygousMask;
+
+ @JsonProperty("he")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public VariantMask heterozygousMask;
+
+ @JsonProperty("hon")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public VariantMask homozygousNoCallMask;
+
+ @JsonProperty("hen")
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ public VariantMask heterozygousNoCallMask;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ VariableVariantMasks that = (VariableVariantMasks) o;
+ return Objects.equals(homozygousMask, that.homozygousMask) && Objects.equals(heterozygousMask, that.heterozygousMask)
+ && Objects.equals(homozygousNoCallMask, that.homozygousNoCallMask)
+ && Objects.equals(heterozygousNoCallMask, that.heterozygousNoCallMask);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(homozygousMask, heterozygousMask, homozygousNoCallMask, heterozygousNoCallMask);
+ }
+
+ public static BigInteger emptyBitmask(int length) {
+ BigInteger emptyBitmask = emptyBitmaskMap.get(length);
+ if (emptyBitmask == null) {
+ String emptyVariantMask = "";
+ for (int i = 0; i < length; i++) {
+ emptyVariantMask = emptyVariantMask + "0";
+ }
+ BigInteger newEmptyBitmask = new BigInteger("11" + emptyVariantMask + "11", 2);
+ emptyBitmaskMap.put(length, newEmptyBitmask);
+ return newEmptyBitmask;
+ }
+ return emptyBitmask;
+ }
+
+ public static VariableVariantMasks append(VariableVariantMasks masks1, int length1, VariableVariantMasks masks2, int length2) {
+ VariableVariantMasks appendedMasks = new VariableVariantMasks();
+ appendedMasks.homozygousMask = appendMask(masks1.homozygousMask, masks2.homozygousMask, length1, length2);
+ appendedMasks.heterozygousMask = appendMask(masks1.heterozygousMask, masks2.heterozygousMask, length1, length2);
+ appendedMasks.homozygousNoCallMask = appendMask(masks1.homozygousNoCallMask, masks2.homozygousNoCallMask, length1, length2);
+ appendedMasks.heterozygousNoCallMask = appendMask(masks1.heterozygousNoCallMask, masks2.heterozygousNoCallMask, length1, length2);
+ return appendedMasks;
+ }
+
+ public static VariantMask appendMask(VariantMask variantMask1, VariantMask variantMask2, int length1, int length2) {
+ if (variantMask1 == null) {
+ variantMask1 = VariantMask.emptyInstance();
+ }
+ if (variantMask2 == null) {
+ variantMask2 = VariantMask.emptyInstance();
+ }
+ if (variantMask1.equals(VariantMask.emptyInstance()) && variantMask2.equals(VariantMask.emptyInstance())) {
+ return null;
+ }
+
+ if (variantMask1 instanceof VariantMaskSparseImpl) {
+ if (variantMask2 instanceof VariantMaskSparseImpl) {
+ return append((VariantMaskSparseImpl) variantMask1, (VariantMaskSparseImpl) variantMask2, length1, length2);
+ } else if (variantMask2 instanceof VariantMaskBitmaskImpl) {
+ return append((VariantMaskSparseImpl) variantMask1, (VariantMaskBitmaskImpl) variantMask2, length1, length2);
+ } else {
+ throw new RuntimeException("Unknown VariantMask implementation");
+ }
+ } else if (variantMask1 instanceof VariantMaskBitmaskImpl) {
+ if (variantMask2 instanceof VariantMaskSparseImpl) {
+ return append((VariantMaskBitmaskImpl) variantMask1, (VariantMaskSparseImpl) variantMask2, length1, length2);
+ } else if (variantMask2 instanceof VariantMaskBitmaskImpl) {
+ return append((VariantMaskBitmaskImpl) variantMask1, (VariantMaskBitmaskImpl) variantMask2, length1, length2);
+ } else {
+ throw new RuntimeException("Unknown VariantMask implementation");
+ }
+ } else {
+ throw new RuntimeException("Unknown VariantMask implementation");
+ }
+ }
+
+ private static VariantMask append(VariantMaskSparseImpl variantMask1, VariantMaskBitmaskImpl variantMask2, int length1, int length2) {
+ BigInteger mask1 = emptyBitmask(length1);
+ for (Integer patientIndex : variantMask1.patientIndexes) {
+ mask1 = mask1.setBit(patientIndex + 2);
+ }
+ String binaryMask1 = mask1.toString(2);
+
+ String binaryMask2 = variantMask2.bitmask.toString(2);
+ if (binaryMask2.length() - 4 != length2) {
+ throw new IllegalArgumentException("Bitmask does not match length (" + length2 + "): " + variantMask2.bitmask);
+ }
+
+ String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) + binaryMask1.substring(2);
+ return new VariantMaskBitmaskImpl(new BigInteger(appendedString, 2));
+ }
+
+ private static VariantMask append(VariantMaskBitmaskImpl variantMask1, VariantMaskSparseImpl variantMask2, int length1, int length2) {
+ String binaryMask1 = variantMask1.bitmask.toString(2);
+ if (binaryMask1.length() - 4 != length1) {
+ throw new IllegalArgumentException("Bitmask does not match length (" + length1 + "): " + variantMask1.bitmask);
+ }
+
+ BigInteger mask2 = emptyBitmask(length2);
+ for (Integer patientId : variantMask2.patientIndexes) {
+ mask2 = mask2.setBit(patientId + 2);
+ }
+ String binaryMask2 = mask2.toString(2);
+
+ String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) + binaryMask1.substring(2);
+ return new VariantMaskBitmaskImpl(new BigInteger(appendedString, 2));
+ }
+
+ private static VariantMask append(VariantMaskBitmaskImpl variantMask1, VariantMaskBitmaskImpl variantMask2, int length1, int length2) {
+ String binaryMask1 = variantMask1.bitmask.toString(2);
+ String binaryMask2 = variantMask2.bitmask.toString(2);
+
+ if (binaryMask1.length() - 4 != length1) {
+ throw new IllegalArgumentException("Bitmask does not match length (" + length1 + "): " + variantMask1.bitmask);
+ }
+ if (binaryMask2.length() - 4 != length2) {
+ throw new IllegalArgumentException("Bitmask does not match length (" + length2 + "): " + variantMask2.bitmask);
+ }
+
+ String appendedString = binaryMask2.substring(0, binaryMask2.length() - 2) + binaryMask1.substring(2);
+ BigInteger bitmask = new BigInteger(appendedString, 2);
+ return new VariantMaskBitmaskImpl(bitmask);
+ }
+
+ private static VariantMask append(VariantMaskSparseImpl variantMask1, VariantMaskSparseImpl variantMask2, int length1, int length2) {
+ if (variantMask1.patientIndexes.size() + variantMask2.patientIndexes.size() > SPARSE_VARIANT_THRESHOLD) {
+ BigInteger mask = emptyBitmask(length1 + length2);
+ for (Integer patientId : variantMask1.patientIndexes) {
+ mask = mask.setBit(patientId + 2);
+ }
+ // We start writing mask 2 where mask 1 ends. So the 0th index of mask 2 is now following the last bit of mask 1
+ for (Integer patientId : variantMask2.patientIndexes) {
+ mask = mask.setBit(patientId + length1 + 2);
+ }
+ return new VariantMaskBitmaskImpl(mask);
+ } else {
+ Set patientIndexSet = new HashSet<>();
+ patientIndexSet.addAll(variantMask1.patientIndexes);
+ // The indexes for mask 2 are shifted by the length of mask 1, corresponding to the corresponding patient id array
+ // for mask 2 being appended to those of mask 1
+ patientIndexSet.addAll(variantMask2.patientIndexes.stream().map(i -> i + length1).collect(Collectors.toSet()));
+ return new VariantMaskSparseImpl(patientIndexSet);
+ }
+ }
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMask.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMask.java
index cca6ee847..376fcc432 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMask.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMask.java
@@ -8,16 +8,11 @@
import java.util.Set;
import java.util.stream.Collectors;
-@JsonTypeInfo(
- use = JsonTypeInfo.Id.NAME,
- include = JsonTypeInfo.As.PROPERTY,
- property = "type",
- defaultImpl = VariantMaskBitmaskImpl.class
+@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type", defaultImpl = VariantMaskBitmaskImpl.class)
+@JsonSubTypes(
+ {@JsonSubTypes.Type(value = VariantMaskBitmaskImpl.class, name = "b"),
+ @JsonSubTypes.Type(value = VariantMaskSparseImpl.class, name = "s")}
)
-@JsonSubTypes({
- @JsonSubTypes.Type(value = VariantMaskBitmaskImpl.class, name = "b"),
- @JsonSubTypes.Type(value = VariantMaskSparseImpl.class, name = "s")
-})
public interface VariantMask {
VariantMask intersection(VariantMask variantMask);
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskBitmaskImpl.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskBitmaskImpl.java
index fb6b81b86..8fa2922ce 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskBitmaskImpl.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskBitmaskImpl.java
@@ -36,7 +36,7 @@ public VariantMaskBitmaskImpl(BigInteger bitmask) {
public VariantMask intersection(VariantMask variantMask) {
if (variantMask instanceof VariantMaskBitmaskImpl) {
return intersection((VariantMaskBitmaskImpl) variantMask);
- } else if (variantMask instanceof VariantMaskSparseImpl) {
+ } else if (variantMask instanceof VariantMaskSparseImpl) {
return variantMask.intersection(this);
} else {
throw new RuntimeException("Unknown VariantMask implementation");
@@ -47,7 +47,7 @@ public VariantMask intersection(VariantMask variantMask) {
public VariantMask union(VariantMask variantMask) {
if (variantMask instanceof VariantMaskBitmaskImpl) {
return union((VariantMaskBitmaskImpl) variantMask);
- } else if (variantMask instanceof VariantMaskSparseImpl) {
+ } else if (variantMask instanceof VariantMaskSparseImpl) {
return variantMask.union(this);
} else {
throw new RuntimeException("Unknown VariantMask implementation");
@@ -67,8 +67,8 @@ public int bitCount() {
@Override
public Set patientMaskToPatientIdSet(List patientIds) {
Set ids = new HashSet<>();
- for(int x = 0;x < bitmask.bitLength()-4;x++) {
- if(testBit(x)) {
+ for (int x = 0; x < bitmask.bitLength() - 4; x++) {
+ if (testBit(x)) {
String patientId = patientIds.get(x).trim();
ids.add(Integer.parseInt(patientId));
}
@@ -86,6 +86,7 @@ public boolean isEmpty() {
private VariantMask union(VariantMaskBitmaskImpl variantMaskBitmask) {
return new VariantMaskBitmaskImpl(variantMaskBitmask.bitmask.or(this.bitmask));
}
+
private VariantMask intersection(VariantMaskBitmaskImpl variantMaskBitmask) {
// we could consider using a sparse variant index here if we are ever going to be storing the
// result of this anywhere
@@ -107,8 +108,6 @@ public int hashCode() {
@Override
public String toString() {
- return "VariantMaskBitmaskImpl{" +
- "bitmask=" + bitmask.toString() +
- '}';
+ return "VariantMaskBitmaskImpl{" + "bitmask=" + bitmask.toString() + '}';
}
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskSparseImpl.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskSparseImpl.java
index bf020aeea..9b78c51da 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskSparseImpl.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMaskSparseImpl.java
@@ -25,16 +25,14 @@ public Set getPatientIndexes() {
@Override
public VariantMask intersection(VariantMask variantMask) {
- return new VariantMaskSparseImpl(this.patientIndexes.stream()
- .filter(variantMask::testBit)
- .collect(Collectors.toSet()));
+ return new VariantMaskSparseImpl(this.patientIndexes.stream().filter(variantMask::testBit).collect(Collectors.toSet()));
}
@Override
public VariantMask union(VariantMask variantMask) {
if (variantMask instanceof VariantMaskBitmaskImpl) {
return union((VariantMaskBitmaskImpl) variantMask);
- } else if (variantMask instanceof VariantMaskSparseImpl) {
+ } else if (variantMask instanceof VariantMaskSparseImpl) {
return union((VariantMaskSparseImpl) variantMask);
} else {
throw new RuntimeException("Unknown VariantMask implementation");
@@ -53,11 +51,7 @@ public int bitCount() {
@Override
public Set patientMaskToPatientIdSet(List patientIds) {
- return patientIndexes.stream()
- .map(patientIds::get)
- .map(String::trim)
- .map(Integer::parseInt)
- .collect(Collectors.toSet());
+ return patientIndexes.stream().map(patientIds::get).map(String::trim).map(Integer::parseInt).collect(Collectors.toSet());
}
@Override
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMasks.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMasks.java
index 5647b613c..a0d024984 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMasks.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantMasks.java
@@ -11,238 +11,240 @@
import java.util.Objects;
public class VariantMasks implements Serializable {
- private static final long serialVersionUID = 6225420483804601477L;
- private static final String oneone = "11";
- private static final char one = '1';
- private static final char zero = '0';
- private static final String hetero = "0/1";
- private static final String heteroDel = "1/0";
- private static final String heteroPhased = "0|1";
- private static final String heteroPhased2 = "1|0";
- private static final String homo = "1/1";
- private static final String homoPhased = "1|1";
- private static final String homoNoCall = "./.";
- private static final String heteroNoCall = "./1";
-
- /*
- * These indices result from the char values of the 3 characters in a VCF sample
- * record summed as integers % 7
- *
- * This allows us to not actually do string comparisons, instead we add 3 values,
- * do one modulus operation, then use the result as the index into the result array.
- */
-
- // ./0 = (46 + 47 + 48) % 7 = 1
- // 0|. = (48 + 124 + 46) % 7 = 1
- // .|0 = (46 + 124 + 48) % 7 = 1
- public static final int HETERO_NOCALL_REF_CHAR_INDEX = 1;
-
- // ./1 = (46 + 47 + 49) % 7 = 2
- // 1|. = (49 + 124 + 46) % 7 = 2
- // .|1 = (46 + 124 + 49) % 7 = 2
- // ./1 = (46 + 47 + 49) % 7 = 2
- // 1|. = (49 + 124 + 46) % 7 = 2
- // .|1 = (46 + 124 + 49) % 7 = 2
- public static final int HETERO_NOCALL_VARIANT_CHAR_INDEX = 2;
-
- // 0/0 = (48 + 47 + 48) % 7 = 3
- // 0|0 = (48 + 124 + 48) % 7 = 3
- public static final int ZERO_ZERO_CHAR_INDEX = 3;
-
- // 0/1 = (48 + 47 + 49) % 7 = 4
- // 1|0 = (49 + 124 + 48) % 7 = 4
- // 0|1 = (48 + 124 + 49) % 7 = 4
- public static final int ZERO_ONE_CHAR_INDEX = 4;
-
- // 1/1 = (49 + 47 + 49) % 7 = 5
- // 1|1 = (49 + 124 + 49) % 7 = 5
- public static final int ONE_ONE_CHAR_INDEX = 5;
-
- // ./. = (46 + 47 + 46) % 7 = 6
- // .|. = (46 + 124 + 46) % 7 = 6
- public static final int HOMO_NOCALL_CHAR_INDEX = 6;
-
- public VariantMasks(String[] values) {
- char[] homozygousBits = new char[values.length];
- char[] heterozygousBits = new char[values.length];
- char[] homozygousNoCallBits = new char[values.length];
- char[] heterozygousNoCallBits = new char[values.length];
- boolean hasHetero = false;
- boolean hasHomo = false;
- boolean hasHeteroNoCall = false;
- boolean hasHomoNoCall = false;
-
- for(int x = 0;x metadata, instead of the
- * metadata -> variant-spec map that is used for searching and identifying patients.
+ * This class will create a set of FBBIS objects that allow lookups of variant-spec -> metadata, instead of the metadata -> variant-spec map
+ * that is used for searching and identifying patients.
*
- * The loading and reading of this class must take place separately; the flush() function will write out the in-memory contents to
- * a fast, disk-based backing store.
+ * The loading and reading of this class must take place separately; the flush() function will write out the in-memory contents to a fast,
+ * disk-based backing store.
*/
public class VariantMetadataIndex implements Serializable {
- public static final String VARIANT_METADATA_FILENAME = "VariantMetadata.javabin";
- public static String VARIANT_METADATA_BIN_FILE = "/opt/local/hpds/all/" + VARIANT_METADATA_FILENAME;
-
- private static final long serialVersionUID = 5917054606643971537L;
- private static Logger log = LoggerFactory.getLogger(VariantMetadataIndex.class);
-
- // (String) contig --> (Integer) Bucket --> (String) variant spec --> INFO column data[].
- private final Map> > indexMap = new HashMap<>();
-
- public static final String VARIANT_METADATA_STORAGE_FILE_PREFIX = "VariantMetadataStorage";
- private String fileStoragePrefix = "/opt/local/hpds/all/" + VARIANT_METADATA_STORAGE_FILE_PREFIX;
-
- /**
- * This map allows us to load millions of variants without re-writing the fbbis each time (which would blow up the disk space).
- * We need to remember to flush() between each contig this gets saved to the fbbis array.
- */
- private transient Map> > loadingMap = new HashMap<>();
-
- /**
- * This constructor should only be used for testing; we expect the files to be in the default locations in production
- * @param storageFile
- * @throws IOException
- */
- public VariantMetadataIndex(String storageFile) throws IOException {
- fileStoragePrefix = storageFile;
- }
-
- /**
- * creates a default metadata index that maps variant spec -> metadata using an array of one file per contig.
- * @throws IOException
- */
- public VariantMetadataIndex() throws IOException {
- }
-
- /**
- * This will always return a value, including an empty array if there is no data or an error.
- * @param variantSpec
- * @return
- */
- public Set findBySingleVariantSpec(String variantSpec, VariantBucketHolder bucketCache) {
- try {
- String[] segments = variantSpec.split(",");
- if (segments.length < 2) {
- log.error("Less than 2 segments found in this variant : " + variantSpec);
- }
-
- int chrOffset = Integer.parseInt(segments[1]) / VariantStore.BUCKET_SIZE;
- String contig = segments[0];
-
- //see if we can reuse the cache
- if (bucketCache.lastValue == null || !contig.contentEquals(bucketCache.lastContig)
- || chrOffset != bucketCache.lastChunkOffset) {
- FileBackedByteIndexedStorage> ContigFbbis = indexMap.get(contig);
- if(ContigFbbis == null) {
- return Set.of();
- }
- bucketCache.lastValue = ContigFbbis.get(chrOffset);
- bucketCache.lastContig = contig;
- bucketCache.lastChunkOffset = chrOffset;
- }
-
- if( bucketCache.lastValue != null) {
- if(bucketCache.lastValue.get(variantSpec) == null) {
- log.warn("No variant data found for spec " + variantSpec);
- return Set.of();
- }
- return Set.of(bucketCache.lastValue.get(variantSpec));
- }
- log.warn("No bucket found for spec " + variantSpec + " in bucket " + chrOffset);
- return Set.of();
-
- } catch (UncheckedIOException e) {
- log.warn("IOException caught looking up variantSpec : " + variantSpec, e);
- return Set.of();
- }
- }
-
- public Map> findByMultipleVariantSpec(Collection varientSpecList) {
-// log.debug("SPEC list " + varientSpecList.size() + " :: " + Arrays.deepToString(varientSpecList.toArray()));
-
- VariantBucketHolder bucketCache = new VariantBucketHolder();
- return varientSpecList.stream().collect(Collectors.toMap(
- variant->{return variant;},
- variant->{return findBySingleVariantSpec(variant, bucketCache);}
- ));
- }
-
- /**
- * Get/put symmetry is broken here, since we want the ETL process to build the fbbis objects, so we only
- * have to write them to disk once. The data will be written to disk only when the flush() method is called.
- *
- * @param variantSpec
- * @throws IOException
- */
- public void put(String variantSpec, String metaData ) throws IOException {
-
- String[] segments = variantSpec.split(",");
- if (segments.length < 2) {
- log.error("Less than 2 segments found in this variant : " + variantSpec);
- }
-
- int chrOffset = Integer.parseInt(segments[1]) / VariantStore.BUCKET_SIZE;
- String contig = segments[0];
-
- ConcurrentHashMap> contigMap = loadingMap.get(contig);
- if(contigMap == null) {
- contigMap = new ConcurrentHashMap>();
- loadingMap.put(contig, contigMap);
- }
-
- ConcurrentHashMap bucket = contigMap.get(chrOffset);
- if(bucket == null) {
- bucket = new ConcurrentHashMap();
- contigMap.put(chrOffset, bucket);
- }
-
- List existingRecords = new ArrayList();
- if(bucket.get(variantSpec) != null) {
- Collections.addAll(existingRecords, bucket.get(variantSpec));
- }
- existingRecords.add(metaData);
- bucket.put(variantSpec, existingRecords.toArray(new String[existingRecords.size()]));
- }
-
- /**
- * This will write out the current contents of the in-memory cache to file based storage. it should be called
- * between processing each contig so that the memory usage doesn't overwhelm the system.
- *
- * This will overwrite any existing data, so it should only be called once per contig.
- * @throws IOException
- */
- public synchronized void flush() throws IOException {
-
- for(String contig : loadingMap.keySet()) {
- log.debug("writing contig " + contig);
-
- FileBackedByteIndexedStorage> contigFbbis = indexMap.get(contig);
- if(contigFbbis == null) {
- log.info("creating new file for " + contig);
- String filePath = fileStoragePrefix + "_" + contig + ".bin";
- contigFbbis = new FileBackedJavaIndexedStorage(Integer.class, ConcurrentHashMap.class, new File(filePath));
- indexMap.put(contig, contigFbbis);
- }
-
- ConcurrentHashMap> contigMap = loadingMap.get(contig);
- for(Integer bucketNumber : contigMap.keySet()) {
- //make sure we don't lose any existing data
- ConcurrentHashMap bucketStorage = contigFbbis.get(bucketNumber);
- if(bucketStorage == null) {
- bucketStorage = contigMap.get(bucketNumber);
- } else {
- bucketStorage.putAll(contigMap.get(bucketNumber));
- }
-
- contigFbbis.put(bucketNumber, bucketStorage);
- }
-
- log.debug("Saved " + contig + " to FBBIS");
- }
- //now reset the map
- loadingMap = new HashMap> >();
- }
-
- public void complete() throws IOException {
- flush();
-
- for(String contig : indexMap.keySet()) {
- FileBackedByteIndexedStorage> contigFbbis = indexMap.get(contig);
- contigFbbis.complete();
- }
-
- }
-
- public static VariantMetadataIndex createInstance(String metadataIndexPath) {
- try(ObjectInputStream in = new ObjectInputStream(new GZIPInputStream(
- new FileInputStream(metadataIndexPath + VARIANT_METADATA_FILENAME)))){
- VariantMetadataIndex variantMetadataIndex = (VariantMetadataIndex) in.readObject();
- variantMetadataIndex.updateStorageDirectory(new File(metadataIndexPath));
- return variantMetadataIndex;
- } catch(Exception e) {
- // todo: handle exceptions better
- log.info("No Metadata Index found at " + metadataIndexPath);
- return null;
- }
- }
-
- public static void merge(VariantMetadataIndex variantMetadataIndex1, VariantMetadataIndex variantMetadataIndex2, String outputDirectory) throws IOException {
- VariantMetadataIndex merged = new VariantMetadataIndex(outputDirectory + VARIANT_METADATA_STORAGE_FILE_PREFIX);
- if (!variantMetadataIndex1.indexMap.keySet().equals(variantMetadataIndex2.indexMap.keySet())) {
- log.warn("Merging incompatible variant indexes. Index1 keys: " + Joiner.on(",").join(variantMetadataIndex1.indexMap.keySet()) + ". Index 2 keys: " + Joiner.on(",").join(variantMetadataIndex2.indexMap.keySet()));
- throw new IllegalStateException("Cannot merge variant metadata index with different contig keys");
- }
- for (String contig : variantMetadataIndex1.indexMap.keySet()) {
- String filePath = outputDirectory + VARIANT_METADATA_STORAGE_FILE_PREFIX + "_" + contig + ".bin";
- FileBackedByteIndexedStorage> mergedFbbis = new FileBackedJavaIndexedStorage(Integer.class, ConcurrentHashMap.class, new File(filePath));
-
- // Store the merged result here because FileBackedByteIndexedStorage must be written all at once
- Map> mergedStagedFbbis = new HashMap<>();
-
- FileBackedByteIndexedStorage> fbbis1 = variantMetadataIndex1.indexMap.get(contig);
- FileBackedByteIndexedStorage> fbbis2 = variantMetadataIndex2.indexMap.get(contig);
-
- fbbis1.keys().forEach(key -> {
- mergedStagedFbbis.put(key, fbbis1.get(key));
- });
- fbbis2.keys().forEach(key -> {
- ConcurrentHashMap metadataMap = mergedStagedFbbis.get(key);
- if (metadataMap == null) {
- mergedStagedFbbis.put(key, fbbis2.get(key));
- } else {
- metadataMap.putAll(fbbis2.get(key));
- }
- });
-
- mergedStagedFbbis.forEach(mergedFbbis::put);
- mergedFbbis.complete();
- merged.indexMap.put(contig, mergedFbbis);
- }
-
- try(ObjectOutputStream out = new ObjectOutputStream(new GZIPOutputStream(Files.newOutputStream(new File(outputDirectory + VARIANT_METADATA_FILENAME).toPath())))){
- out.writeObject(merged);
- out.flush();
- }
- }
-
- public void updateStorageDirectory(File genomicDataDirectory) {
- indexMap.values().forEach(value -> value.updateStorageDirectory(genomicDataDirectory));
- }
-}
\ No newline at end of file
+ public static final String VARIANT_METADATA_FILENAME = "VariantMetadata.javabin";
+ public static String VARIANT_METADATA_BIN_FILE = "/opt/local/hpds/all/" + VARIANT_METADATA_FILENAME;
+
+ private static final long serialVersionUID = 5917054606643971537L;
+ private static Logger log = LoggerFactory.getLogger(VariantMetadataIndex.class);
+
+ // (String) contig --> (Integer) Bucket --> (String) variant spec --> INFO column data[].
+ private final Map>> indexMap = new HashMap<>();
+
+ public static final String VARIANT_METADATA_STORAGE_FILE_PREFIX = "VariantMetadataStorage";
+ private String fileStoragePrefix = "/opt/local/hpds/all/" + VARIANT_METADATA_STORAGE_FILE_PREFIX;
+
+ /**
+ * This map allows us to load millions of variants without re-writing the fbbis each time (which would blow up the disk space). We need
+ * to remember to flush() between each contig this gets saved to the fbbis array.
+ */
+ private transient Map>> loadingMap = new HashMap<>();
+
+ /**
+ * This constructor should only be used for testing; we expect the files to be in the default locations in production
+ * @param storageFile
+ * @throws IOException
+ */
+ public VariantMetadataIndex(String storageFile) throws IOException {
+ fileStoragePrefix = storageFile;
+ }
+
+ /**
+ * creates a default metadata index that maps variant spec -> metadata using an array of one file per contig.
+ * @throws IOException
+ */
+ public VariantMetadataIndex() throws IOException {}
+
+ /**
+ * This will always return a value, including an empty array if there is no data or an error.
+ * @param variantSpec
+ * @return
+ */
+ public Set findBySingleVariantSpec(String variantSpec, VariantBucketHolder bucketCache) {
+ try {
+ String[] segments = variantSpec.split(",");
+ if (segments.length < 2) {
+ log.error("Less than 2 segments found in this variant : " + variantSpec);
+ }
+
+ int chrOffset = Integer.parseInt(segments[1]) / VariantStore.BUCKET_SIZE;
+ String contig = segments[0];
+
+ // see if we can reuse the cache
+ if (
+ bucketCache.lastValue == null || !contig.contentEquals(bucketCache.lastContig) || chrOffset != bucketCache.lastChunkOffset
+ ) {
+ FileBackedByteIndexedStorage> ContigFbbis = indexMap.get(contig);
+ if (ContigFbbis == null) {
+ return Set.of();
+ }
+ bucketCache.lastValue = ContigFbbis.get(chrOffset);
+ bucketCache.lastContig = contig;
+ bucketCache.lastChunkOffset = chrOffset;
+ }
+
+ if (bucketCache.lastValue != null) {
+ if (bucketCache.lastValue.get(variantSpec) == null) {
+ log.warn("No variant data found for spec " + variantSpec);
+ return Set.of();
+ }
+ return Set.of(bucketCache.lastValue.get(variantSpec));
+ }
+ log.warn("No bucket found for spec " + variantSpec + " in bucket " + chrOffset);
+ return Set.of();
+
+ } catch (UncheckedIOException e) {
+ log.warn("IOException caught looking up variantSpec : " + variantSpec, e);
+ return Set.of();
+ }
+ }
+
+ public Map> findByMultipleVariantSpec(Collection varientSpecList) {
+ // log.debug("SPEC list " + varientSpecList.size() + " :: " + Arrays.deepToString(varientSpecList.toArray()));
+
+ VariantBucketHolder bucketCache = new VariantBucketHolder();
+ return varientSpecList.stream().collect(Collectors.toMap(variant -> {
+ return variant;
+ }, variant -> {
+ return findBySingleVariantSpec(variant, bucketCache);
+ }));
+ }
+
+ /**
+ * Get/put symmetry is broken here, since we want the ETL process to build the fbbis objects, so we only have to write them to disk
+ * once. The data will be written to disk only when the flush() method is called.
+ *
+ * @param variantSpec
+ * @throws IOException
+ */
+ public void put(String variantSpec, String metaData) throws IOException {
+
+ String[] segments = variantSpec.split(",");
+ if (segments.length < 2) {
+ log.error("Less than 2 segments found in this variant : " + variantSpec);
+ }
+
+ int chrOffset = Integer.parseInt(segments[1]) / VariantStore.BUCKET_SIZE;
+ String contig = segments[0];
+
+ ConcurrentHashMap> contigMap = loadingMap.get(contig);
+ if (contigMap == null) {
+ contigMap = new ConcurrentHashMap>();
+ loadingMap.put(contig, contigMap);
+ }
+
+ ConcurrentHashMap bucket = contigMap.get(chrOffset);
+ if (bucket == null) {
+ bucket = new ConcurrentHashMap();
+ contigMap.put(chrOffset, bucket);
+ }
+
+ List existingRecords = new ArrayList();
+ if (bucket.get(variantSpec) != null) {
+ Collections.addAll(existingRecords, bucket.get(variantSpec));
+ }
+ existingRecords.add(metaData);
+ bucket.put(variantSpec, existingRecords.toArray(new String[existingRecords.size()]));
+ }
+
+ /**
+ * This will write out the current contents of the in-memory cache to file based storage. it should be called between processing each
+ * contig so that the memory usage doesn't overwhelm the system.
+ *
+ * This will overwrite any existing data, so it should only be called once per contig.
+ * @throws IOException
+ */
+ public synchronized void flush() throws IOException {
+
+ for (String contig : loadingMap.keySet()) {
+ log.debug("writing contig " + contig);
+
+ FileBackedByteIndexedStorage> contigFbbis = indexMap.get(contig);
+ if (contigFbbis == null) {
+ log.info("creating new file for " + contig);
+ String filePath = fileStoragePrefix + "_" + contig + ".bin";
+ contigFbbis = new FileBackedJavaIndexedStorage(Integer.class, ConcurrentHashMap.class, new File(filePath));
+ indexMap.put(contig, contigFbbis);
+ }
+
+ ConcurrentHashMap> contigMap = loadingMap.get(contig);
+ for (Integer bucketNumber : contigMap.keySet()) {
+ // make sure we don't lose any existing data
+ ConcurrentHashMap bucketStorage = contigFbbis.get(bucketNumber);
+ if (bucketStorage == null) {
+ bucketStorage = contigMap.get(bucketNumber);
+ } else {
+ bucketStorage.putAll(contigMap.get(bucketNumber));
+ }
+
+ contigFbbis.put(bucketNumber, bucketStorage);
+ }
+
+ log.debug("Saved " + contig + " to FBBIS");
+ }
+ // now reset the map
+ loadingMap = new HashMap>>();
+ }
+
+ public void complete() throws IOException {
+ flush();
+
+ for (String contig : indexMap.keySet()) {
+ FileBackedByteIndexedStorage> contigFbbis = indexMap.get(contig);
+ contigFbbis.complete();
+ }
+
+ }
+
+ public static VariantMetadataIndex createInstance(String metadataIndexPath) {
+ try (
+ ObjectInputStream in =
+ new ObjectInputStream(new GZIPInputStream(new FileInputStream(metadataIndexPath + VARIANT_METADATA_FILENAME)))
+ ) {
+ VariantMetadataIndex variantMetadataIndex = (VariantMetadataIndex) in.readObject();
+ variantMetadataIndex.updateStorageDirectory(new File(metadataIndexPath));
+ return variantMetadataIndex;
+ } catch (Exception e) {
+ // todo: handle exceptions better
+ log.info("No Metadata Index found at " + metadataIndexPath);
+ return null;
+ }
+ }
+
+ public static void merge(VariantMetadataIndex variantMetadataIndex1, VariantMetadataIndex variantMetadataIndex2, String outputDirectory)
+ throws IOException {
+ VariantMetadataIndex merged = new VariantMetadataIndex(outputDirectory + VARIANT_METADATA_STORAGE_FILE_PREFIX);
+ if (!variantMetadataIndex1.indexMap.keySet().equals(variantMetadataIndex2.indexMap.keySet())) {
+ log.warn(
+ "Merging incompatible variant indexes. Index1 keys: " + Joiner.on(",").join(variantMetadataIndex1.indexMap.keySet())
+ + ". Index 2 keys: " + Joiner.on(",").join(variantMetadataIndex2.indexMap.keySet())
+ );
+ throw new IllegalStateException("Cannot merge variant metadata index with different contig keys");
+ }
+ for (String contig : variantMetadataIndex1.indexMap.keySet()) {
+ String filePath = outputDirectory + VARIANT_METADATA_STORAGE_FILE_PREFIX + "_" + contig + ".bin";
+ FileBackedByteIndexedStorage> mergedFbbis =
+ new FileBackedJavaIndexedStorage(Integer.class, ConcurrentHashMap.class, new File(filePath));
+
+ // Store the merged result here because FileBackedByteIndexedStorage must be written all at once
+ Map> mergedStagedFbbis = new HashMap<>();
+
+ FileBackedByteIndexedStorage> fbbis1 = variantMetadataIndex1.indexMap.get(contig);
+ FileBackedByteIndexedStorage> fbbis2 = variantMetadataIndex2.indexMap.get(contig);
+
+ fbbis1.keys().forEach(key -> {
+ mergedStagedFbbis.put(key, fbbis1.get(key));
+ });
+ fbbis2.keys().forEach(key -> {
+ ConcurrentHashMap metadataMap = mergedStagedFbbis.get(key);
+ if (metadataMap == null) {
+ mergedStagedFbbis.put(key, fbbis2.get(key));
+ } else {
+ metadataMap.putAll(fbbis2.get(key));
+ }
+ });
+
+ mergedStagedFbbis.forEach(mergedFbbis::put);
+ mergedFbbis.complete();
+ merged.indexMap.put(contig, mergedFbbis);
+ }
+
+ try (
+ ObjectOutputStream out = new ObjectOutputStream(
+ new GZIPOutputStream(Files.newOutputStream(new File(outputDirectory + VARIANT_METADATA_FILENAME).toPath()))
+ )
+ ) {
+ out.writeObject(merged);
+ out.flush();
+ }
+ }
+
+ public void updateStorageDirectory(File genomicDataDirectory) {
+ indexMap.values().forEach(value -> value.updateStorageDirectory(genomicDataDirectory));
+ }
+}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantSpec.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantSpec.java
index 833597895..dcaedce25 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantSpec.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantSpec.java
@@ -7,114 +7,116 @@
public class VariantSpec implements Serializable, Comparable {
- public class VariantCoords implements Serializable {
- public String chromosome;
- public Integer offset;
- public String name;
- public String ref;
- public String alt;
- public int qual;
- public String format;
- public String gene;
- public String consequence;
+ public class VariantCoords implements Serializable {
+ public String chromosome;
+ public Integer offset;
+ public String name;
+ public String ref;
+ public String alt;
+ public int qual;
+ public String format;
+ public String gene;
+ public String consequence;
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- VariantCoords that = (VariantCoords) o;
- return qual == that.qual && Objects.equals(chromosome, that.chromosome) && Objects.equals(offset, that.offset) && Objects.equals(name, that.name) && Objects.equals(ref, that.ref) && Objects.equals(alt, that.alt) && Objects.equals(format, that.format) && Objects.equals(gene, that.gene) && Objects.equals(consequence, that.consequence);
- }
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ VariantCoords that = (VariantCoords) o;
+ return qual == that.qual && Objects.equals(chromosome, that.chromosome) && Objects.equals(offset, that.offset)
+ && Objects.equals(name, that.name) && Objects.equals(ref, that.ref) && Objects.equals(alt, that.alt)
+ && Objects.equals(format, that.format) && Objects.equals(gene, that.gene) && Objects.equals(consequence, that.consequence);
+ }
- @Override
- public int hashCode() {
- return Objects.hash(chromosome, offset, name, ref, alt, qual, format, gene, consequence);
- }
- }
- public static int CHR = 0, OFF = 1, NAME = 2, REF = 3, ALT = 4, QUAL = 5, FILTER = 6, INFO = 7, FORMAT = 8, DATA = 9;
- public long heteroOffset;
- public long homoOffset;
- public VariantCoords metadata;
+ @Override
+ public int hashCode() {
+ return Objects.hash(chromosome, offset, name, ref, alt, qual, format, gene, consequence);
+ }
+ }
- public VariantSpec(CSVRecord r) {
- this.metadata = new VariantCoords();
- this.metadata.chromosome = r.get(CHR);
- this.metadata.offset = Integer.parseInt(r.get(OFF));
- this.metadata.name = r.get(NAME);
- this.metadata.ref = r.get(REF);
- this.metadata.alt = r.get(ALT);
- try {
- this.metadata.qual = Integer.parseInt(r.get(QUAL));
- }catch(NumberFormatException e) {
- this.metadata.qual = -1;
- }
+ public static int CHR = 0, OFF = 1, NAME = 2, REF = 3, ALT = 4, QUAL = 5, FILTER = 6, INFO = 7, FORMAT = 8, DATA = 9;
+ public long heteroOffset;
+ public long homoOffset;
+ public VariantCoords metadata;
- String[] variantInfo = r.get(INFO).split("[=;]");
- String gene = "NULL";
- String consequence = "NULL";
- for (int i = 0; i < variantInfo.length; i = i + 2) {
- if ("Gene_with_variant".equals(variantInfo[i])) {
- gene = variantInfo[i + 1];
- }
- if ("Variant_consequence_calculated".equals(variantInfo[i])) {
- consequence = variantInfo[i + 1];
- }
- }
- this.metadata.gene = gene;
- this.metadata.consequence = consequence;
- }
+ public VariantSpec(CSVRecord r) {
+ this.metadata = new VariantCoords();
+ this.metadata.chromosome = r.get(CHR);
+ this.metadata.offset = Integer.parseInt(r.get(OFF));
+ this.metadata.name = r.get(NAME);
+ this.metadata.ref = r.get(REF);
+ this.metadata.alt = r.get(ALT);
+ try {
+ this.metadata.qual = Integer.parseInt(r.get(QUAL));
+ } catch (NumberFormatException e) {
+ this.metadata.qual = -1;
+ }
- public VariantSpec(String variant) {
- this.metadata = new VariantCoords();
- String[] segments = variant.split(",");
- this.metadata.chromosome = segments[0];
- this.metadata.offset = Integer.parseInt(segments[1]);
- this.metadata.name = null;
- this.metadata.ref = segments[2];
- this.metadata.alt = segments[3];
- this.metadata.qual = -1;
- this.metadata.gene = segments[4];
- this.metadata.consequence = segments[5];
- }
+ String[] variantInfo = r.get(INFO).split("[=;]");
+ String gene = "NULL";
+ String consequence = "NULL";
+ for (int i = 0; i < variantInfo.length; i = i + 2) {
+ if ("Gene_with_variant".equals(variantInfo[i])) {
+ gene = variantInfo[i + 1];
+ }
+ if ("Variant_consequence_calculated".equals(variantInfo[i])) {
+ consequence = variantInfo[i + 1];
+ }
+ }
+ this.metadata.gene = gene;
+ this.metadata.consequence = consequence;
+ }
- public String specNotation() {
- return this.metadata.chromosome + ","
- + this.metadata.offset + "," +
- this.metadata.ref + "," + this.metadata.alt + "," + this.metadata.gene + "," + this.metadata.consequence;
- }
+ public VariantSpec(String variant) {
+ this.metadata = new VariantCoords();
+ String[] segments = variant.split(",");
+ this.metadata.chromosome = segments[0];
+ this.metadata.offset = Integer.parseInt(segments[1]);
+ this.metadata.name = null;
+ this.metadata.ref = segments[2];
+ this.metadata.alt = segments[3];
+ this.metadata.qual = -1;
+ this.metadata.gene = segments[4];
+ this.metadata.consequence = segments[5];
+ }
- public int compareTo(VariantSpec o) {
- int ret = 0;
- ret = this.metadata.chromosome.compareTo(o.metadata.chromosome);
- if (ret == 0) {
- ret = this.metadata.offset.compareTo(o.metadata.offset);
- }
- if (ret == 0) {
- ret = this.metadata.ref.compareTo(o.metadata.ref);
- }
- if (ret == 0) {
- ret = this.metadata.alt.compareTo(o.metadata.alt);
- }
- if (ret == 0) {
- ret = this.metadata.gene.compareTo(o.metadata.gene);
- }
- if (ret == 0) {
- ret = this.metadata.consequence.compareTo(o.metadata.consequence);
- }
+ public String specNotation() {
+ return this.metadata.chromosome + "," + this.metadata.offset + "," + this.metadata.ref + "," + this.metadata.alt + ","
+ + this.metadata.gene + "," + this.metadata.consequence;
+ }
- return ret;
- }
+ public int compareTo(VariantSpec o) {
+ int ret = 0;
+ ret = this.metadata.chromosome.compareTo(o.metadata.chromosome);
+ if (ret == 0) {
+ ret = this.metadata.offset.compareTo(o.metadata.offset);
+ }
+ if (ret == 0) {
+ ret = this.metadata.ref.compareTo(o.metadata.ref);
+ }
+ if (ret == 0) {
+ ret = this.metadata.alt.compareTo(o.metadata.alt);
+ }
+ if (ret == 0) {
+ ret = this.metadata.gene.compareTo(o.metadata.gene);
+ }
+ if (ret == 0) {
+ ret = this.metadata.consequence.compareTo(o.metadata.consequence);
+ }
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- VariantSpec that = (VariantSpec) o;
- return heteroOffset == that.heteroOffset && homoOffset == that.homoOffset && Objects.equals(metadata, that.metadata);
- }
+ return ret;
+ }
- @Override
- public int hashCode() {
- return Objects.hash(heteroOffset, homoOffset, metadata);
- }
-}
\ No newline at end of file
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ VariantSpec that = (VariantSpec) o;
+ return heteroOffset == that.heteroOffset && homoOffset == that.homoOffset && Objects.equals(metadata, that.metadata);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(heteroOffset, homoOffset, metadata);
+ }
+}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantStore.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantStore.java
index 312bede2b..32e24c5a9 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantStore.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/VariantStore.java
@@ -15,152 +15,167 @@
import java.util.zip.GZIPOutputStream;
public class VariantStore implements Serializable {
- private static final long serialVersionUID = -6970128712587609414L;
- public static final String VARIANT_STORE_JAVABIN_FILENAME = "variantStore.javabin";
- public static final String VARIANT_SPEC_INDEX_JAVABIN_FILENAME = "variantSpecIndex.javabin";
- private static Logger log = LoggerFactory.getLogger(VariantStore.class);
- public static final int BUCKET_SIZE = 1000;
-
- private BigInteger emptyBitmask;
- private String[] patientIds;
-
- private transient String[] variantSpecIndex;
-
- private Map>> variantMaskStorage = new TreeMap<>();
-
- public Map>> getVariantMaskStorage() {
- return variantMaskStorage;
- }
-
- public void setVariantMaskStorage(Map>> variantMaskStorage) {
- this.variantMaskStorage = variantMaskStorage;
- }
-
- public String[] getVariantSpecIndex() {
- return variantSpecIndex;
- }
- public void setVariantSpecIndex(String[] variantSpecIndex) {
- this.variantSpecIndex = variantSpecIndex;
- }
-
- public static VariantStore readInstance(String genomicDataDirectory) throws IOException, ClassNotFoundException {
- try (GZIPInputStream gzipInputStream = new GZIPInputStream(new FileInputStream(genomicDataDirectory + VARIANT_STORE_JAVABIN_FILENAME));
- ObjectInputStream ois = new ObjectInputStream(gzipInputStream)) {
- VariantStore variantStore = (VariantStore) ois.readObject();
- ois.close();
- variantStore.getVariantMaskStorage().values().forEach(store -> {
- store.updateStorageDirectory(new File(genomicDataDirectory));
- });
- variantStore.open();
- variantStore.setVariantSpecIndex(loadVariantIndexFromFile(genomicDataDirectory));
- return variantStore;
- }
- }
-
- public void writeInstance(String genomicDirectory) {
- try (FileOutputStream fos = new FileOutputStream(new File(genomicDirectory, VARIANT_STORE_JAVABIN_FILENAME));
- GZIPOutputStream gzos = new GZIPOutputStream(fos);
- ObjectOutputStream oos = new ObjectOutputStream(gzos);) {
- oos.writeObject(this);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- try (FileOutputStream fos = new FileOutputStream(new File(genomicDirectory, VARIANT_SPEC_INDEX_JAVABIN_FILENAME));
- GZIPOutputStream gzos = new GZIPOutputStream(fos);
- ObjectOutputStream oos = new ObjectOutputStream(gzos);) {
- oos.writeObject(Arrays.asList(variantSpecIndex));
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public String[] getPatientIds() {
- return patientIds;
- }
-
- public Optional getMasks(String variant, VariantBucketHolder bucketCache) throws IOException {
- String[] segments = variant.split(",");
- if (segments.length < 2) {
- log.error("Less than 2 segments found in this variant : " + variant);
- }
-
- int chrOffset = Integer.parseInt(segments[1]) / BUCKET_SIZE;
- String contig = segments[0];
-
- if (bucketCache.lastValue != null && contig.contentEquals(bucketCache.lastContig)
- && chrOffset == bucketCache.lastChunkOffset) {
- // TODO : This is a temporary efficiency hack, NOT THREADSAFE!!!
- } else {
- // todo: don't bother doing a lookup if this node does not have the chromosome specified
- FileBackedJsonIndexStorage> indexedStorage = variantMaskStorage.get(contig);
- if (indexedStorage == null) {
- return Optional.empty();
- }
- bucketCache.lastValue = indexedStorage.get(chrOffset);
- bucketCache.lastContig = contig;
- bucketCache.lastChunkOffset = chrOffset;
- }
- return bucketCache.lastValue == null ? Optional.empty() : Optional.ofNullable(bucketCache.lastValue.get(variant));
- }
- public List getMasksForDbSnpSpec(String variant) {
- String[] segments = variant.split(",");
- if (segments.length < 2) {
- log.error("Less than 2 segments found in this variant : " + variant);
- }
-
- int chrOffset = Integer.parseInt(segments[1]) / BUCKET_SIZE;
- String contig = segments[0];
-
- // todo: don't bother doing a lookup if this node does not have the chromosome specified
- FileBackedJsonIndexStorage> indexedStorage = variantMaskStorage.get(contig);
- if (indexedStorage == null) {
- return List.of();
- } else {
- ConcurrentHashMap specToMaskMap = indexedStorage.getOrELse(chrOffset, new ConcurrentHashMap<>());
- return specToMaskMap.entrySet().stream()
- .filter(entry -> entry.getKey().startsWith(variant))
- .map(Map.Entry::getValue)
- .collect(Collectors.toList());
- }
- }
-
- public void open() {
- variantMaskStorage.values().stream().forEach((fbbis -> {
- if (fbbis != null) {
- fbbis.open();
- }
- }));
- }
-
- public VariantStore() {
-
- }
-
- public void setPatientIds(String[] patientIds) {
- this.patientIds = patientIds;
- }
-
- public BigInteger emptyBitmask() {
- if (emptyBitmask == null || emptyBitmask.testBit(emptyBitmask.bitLength() / 2)) {
- String emptyVariantMask = "";
- for (String patientId : patientIds) {
- emptyVariantMask = emptyVariantMask + "0";
- }
- emptyBitmask = new BigInteger("11" + emptyVariantMask + "11", 2);
- }
- return emptyBitmask;
- }
-
- @SuppressWarnings("unchecked")
- public static String[] loadVariantIndexFromFile(String genomicDataDirectory) {
- try (ObjectInputStream objectInputStream = new ObjectInputStream(new GZIPInputStream(new FileInputStream(genomicDataDirectory + "/" + VARIANT_SPEC_INDEX_JAVABIN_FILENAME)));){
-
- List variants = (List) objectInputStream.readObject();
- return variants.toArray(new String[0]);
-
- } catch (IOException | ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
+ private static final long serialVersionUID = -6970128712587609414L;
+ public static final String VARIANT_STORE_JAVABIN_FILENAME = "variantStore.javabin";
+ public static final String VARIANT_SPEC_INDEX_JAVABIN_FILENAME = "variantSpecIndex.javabin";
+ private static Logger log = LoggerFactory.getLogger(VariantStore.class);
+ public static final int BUCKET_SIZE = 1000;
+
+ private BigInteger emptyBitmask;
+ private String[] patientIds;
+
+ private transient String[] variantSpecIndex;
+
+ private Map>> variantMaskStorage =
+ new TreeMap<>();
+
+ public Map>> getVariantMaskStorage() {
+ return variantMaskStorage;
+ }
+
+ public void setVariantMaskStorage(
+ Map>> variantMaskStorage
+ ) {
+ this.variantMaskStorage = variantMaskStorage;
+ }
+
+ public String[] getVariantSpecIndex() {
+ return variantSpecIndex;
+ }
+
+ public void setVariantSpecIndex(String[] variantSpecIndex) {
+ this.variantSpecIndex = variantSpecIndex;
+ }
+
+ public static VariantStore readInstance(String genomicDataDirectory) throws IOException, ClassNotFoundException {
+ try (
+ GZIPInputStream gzipInputStream =
+ new GZIPInputStream(new FileInputStream(genomicDataDirectory + VARIANT_STORE_JAVABIN_FILENAME)); ObjectInputStream ois =
+ new ObjectInputStream(gzipInputStream)
+ ) {
+ VariantStore variantStore = (VariantStore) ois.readObject();
+ ois.close();
+ variantStore.getVariantMaskStorage().values().forEach(store -> {
+ store.updateStorageDirectory(new File(genomicDataDirectory));
+ });
+ variantStore.open();
+ variantStore.setVariantSpecIndex(loadVariantIndexFromFile(genomicDataDirectory));
+ return variantStore;
+ }
+ }
+
+ public void writeInstance(String genomicDirectory) {
+ try (
+ FileOutputStream fos = new FileOutputStream(new File(genomicDirectory, VARIANT_STORE_JAVABIN_FILENAME)); GZIPOutputStream gzos =
+ new GZIPOutputStream(fos); ObjectOutputStream oos = new ObjectOutputStream(gzos);
+ ) {
+ oos.writeObject(this);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ try (
+ FileOutputStream fos =
+ new FileOutputStream(new File(genomicDirectory, VARIANT_SPEC_INDEX_JAVABIN_FILENAME)); GZIPOutputStream gzos =
+ new GZIPOutputStream(fos); ObjectOutputStream oos = new ObjectOutputStream(gzos);
+ ) {
+ oos.writeObject(Arrays.asList(variantSpecIndex));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public String[] getPatientIds() {
+ return patientIds;
+ }
+
+ public Optional getMasks(String variant, VariantBucketHolder bucketCache)
+ throws IOException {
+ String[] segments = variant.split(",");
+ if (segments.length < 2) {
+ log.error("Less than 2 segments found in this variant : " + variant);
+ }
+
+ int chrOffset = Integer.parseInt(segments[1]) / BUCKET_SIZE;
+ String contig = segments[0];
+
+ if (bucketCache.lastValue != null && contig.contentEquals(bucketCache.lastContig) && chrOffset == bucketCache.lastChunkOffset) {
+ // TODO : This is a temporary efficiency hack, NOT THREADSAFE!!!
+ } else {
+ // todo: don't bother doing a lookup if this node does not have the chromosome specified
+ FileBackedJsonIndexStorage> indexedStorage =
+ variantMaskStorage.get(contig);
+ if (indexedStorage == null) {
+ return Optional.empty();
+ }
+ bucketCache.lastValue = indexedStorage.get(chrOffset);
+ bucketCache.lastContig = contig;
+ bucketCache.lastChunkOffset = chrOffset;
+ }
+ return bucketCache.lastValue == null ? Optional.empty() : Optional.ofNullable(bucketCache.lastValue.get(variant));
+ }
+
+ public List getMasksForDbSnpSpec(String variant) {
+ String[] segments = variant.split(",");
+ if (segments.length < 2) {
+ log.error("Less than 2 segments found in this variant : " + variant);
+ }
+
+ int chrOffset = Integer.parseInt(segments[1]) / BUCKET_SIZE;
+ String contig = segments[0];
+
+ // todo: don't bother doing a lookup if this node does not have the chromosome specified
+ FileBackedJsonIndexStorage> indexedStorage =
+ variantMaskStorage.get(contig);
+ if (indexedStorage == null) {
+ return List.of();
+ } else {
+ ConcurrentHashMap specToMaskMap = indexedStorage.getOrELse(chrOffset, new ConcurrentHashMap<>());
+ return specToMaskMap.entrySet().stream().filter(entry -> entry.getKey().startsWith(variant)).map(Map.Entry::getValue)
+ .collect(Collectors.toList());
+ }
+ }
+
+ public void open() {
+ variantMaskStorage.values().stream().forEach((fbbis -> {
+ if (fbbis != null) {
+ fbbis.open();
+ }
+ }));
+ }
+
+ public VariantStore() {
+
+ }
+
+ public void setPatientIds(String[] patientIds) {
+ this.patientIds = patientIds;
+ }
+
+ public BigInteger emptyBitmask() {
+ if (emptyBitmask == null || emptyBitmask.testBit(emptyBitmask.bitLength() / 2)) {
+ String emptyVariantMask = "";
+ for (String patientId : patientIds) {
+ emptyVariantMask = emptyVariantMask + "0";
+ }
+ emptyBitmask = new BigInteger("11" + emptyVariantMask + "11", 2);
+ }
+ return emptyBitmask;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String[] loadVariantIndexFromFile(String genomicDataDirectory) {
+ try (
+ ObjectInputStream objectInputStream = new ObjectInputStream(
+ new GZIPInputStream(new FileInputStream(genomicDataDirectory + "/" + VARIANT_SPEC_INDEX_JAVABIN_FILENAME))
+ );
+ ) {
+
+ List variants = (List) objectInputStream.readObject();
+ return variants.toArray(new String[0]);
+
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/caching/VariantBucketHolder.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/caching/VariantBucketHolder.java
index 83018c812..c23cd4331 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/caching/VariantBucketHolder.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/genotype/caching/VariantBucketHolder.java
@@ -3,7 +3,7 @@
import java.util.concurrent.ConcurrentHashMap;
public class VariantBucketHolder {
- public ConcurrentHashMap lastValue;
- public String lastContig;
- public int lastChunkOffset;
+ public ConcurrentHashMap lastValue;
+ public String lastContig;
+ public int lastChunkOffset;
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/KeyAndValue.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/KeyAndValue.java
index 9124b7890..2a11a0655 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/KeyAndValue.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/KeyAndValue.java
@@ -4,59 +4,59 @@
public class KeyAndValue> implements Serializable, Comparable> {
- private static final long serialVersionUID = -3714097509955396941L;
-
- int key;
-
- V value;
-
- Long timestamp;
-
- public KeyAndValue() {
-
- }
-
- public KeyAndValue(int key, V value) {
- this.key = key;
- this.value = value;
- this.setTimestamp(Long.MIN_VALUE);
- }
-
-
- public KeyAndValue(int key, V value, Long timestamp) {
- this.key = key;
- this.value = value;
- this.setTimestamp(timestamp);
- }
-
- public V getValue() {
- return value;
- }
-
- public KeyAndValue setValue(V value) {
- this.value = value;
- return this;
- }
-
- public Integer getKey() {
- return key;
- }
-
- public KeyAndValue setKey(Integer key) {
- this.key = key;
- return this;
- }
-
- @Override
- public int compareTo(KeyAndValue> o) {
- return this.key - o.key;
- }
-
- public Long getTimestamp() {
- return timestamp;
- }
-
- public void setTimestamp(Long timestamp) {
- this.timestamp = timestamp;
- }
+ private static final long serialVersionUID = -3714097509955396941L;
+
+ int key;
+
+ V value;
+
+ Long timestamp;
+
+ public KeyAndValue() {
+
+ }
+
+ public KeyAndValue(int key, V value) {
+ this.key = key;
+ this.value = value;
+ this.setTimestamp(Long.MIN_VALUE);
+ }
+
+
+ public KeyAndValue(int key, V value, Long timestamp) {
+ this.key = key;
+ this.value = value;
+ this.setTimestamp(timestamp);
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public KeyAndValue setValue(V value) {
+ this.value = value;
+ return this;
+ }
+
+ public Integer getKey() {
+ return key;
+ }
+
+ public KeyAndValue setKey(Integer key) {
+ this.key = key;
+ return this;
+ }
+
+ @Override
+ public int compareTo(KeyAndValue> o) {
+ return this.key - o.key;
+ }
+
+ public Long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Long timestamp) {
+ this.timestamp = timestamp;
+ }
}
diff --git a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/PhenoCube.java b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/PhenoCube.java
index dfdf408b7..810cf194a 100644
--- a/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/PhenoCube.java
+++ b/services/pic-sure-hpds/data/src/main/java/edu/harvard/hms/dbmi/avillach/hpds/data/phenotype/PhenoCube.java
@@ -7,231 +7,229 @@
public class PhenoCube> implements Serializable {
- private static final long serialVersionUID = -2584728054717230390L;
- public final String name;
- public final Class vType;
-
- int columnWidth;
-
- V[] lowDimValues;
- boolean isLowDim = false;
-
- private KeyAndValue[] sortedByKey;
-
- private TreeMap> categoryMap;
-
- private transient List> loadingMap = Collections.synchronizedList(new ArrayList<>());
-
- public PhenoCube(String name, Class vType){
- this.vType = vType;
- this.name = name;
- }
-
- public void add(Integer key, V value, Date date) {
- loadingMap.add(new KeyAndValue(key, value, date!=null?date.getTime():null));
- }
-
- public V getValueForKey(Integer key) {
- int idx = Arrays.binarySearch(sortedByKey(), new KeyAndValue(key, null));
- if(idx < 0) return null;
- return sortedByKey()[idx].value;
- }
-
- public Set getKeysForValue(V value) {
-
- if(isStringType()) {
- Set keys = categoryMap.get(value);
- return keys == null ? new TreeSet() : keys;
- } else {
- int minIndex;
- KeyAndValue keyAndValue = new KeyAndValue