+
+ /**
+ * Answers a (possibly empty) map of any Ontology terms (from the given term
+ * and its parents) which subsume one or more of the target terms. The map key
+ * is an ontology term, and the entry is the list of target terms that are
+ * sub-terms of the key.
+ * <p>
+ * For example if {@code stop_gained} and {@code stop_lost} are known feature
+ * types, then SO term {@ nonsynonymous_variant} is the first common parent of
+ * both terms
+ *
+ * @param givenTerm
+ * the term to search from
+ * @param targetTerms
+ * candidate terms to 'capture' in ontology groupings
+ * @return
+ */
+ public Map<String, List<String>> findSequenceOntologyGroupings(
+ String givenTerm, List<String> targetTerms)
+ {
+ List<String> sortedTypes = new ArrayList<>(targetTerms);
+ Collections.sort(sortedTypes);
+
+ Map<String, List<String>> parents = new HashMap<>();
+
+ /*
+ * method:
+ * walk up featureType and all of its parents
+ * find other feature types which are subsumed by each term
+ * add each distinct aggregation of included feature types to the map
+ */
+ List<String> candidates = new ArrayList<>();
+ SequenceOntologyI so = SequenceOntologyFactory.getInstance();
+ candidates.add(givenTerm);
+ while (!candidates.isEmpty())
+ {
+ String term = candidates.remove(0);
+ List<String> includedFeatures = new ArrayList<>();
+ for (String type : sortedTypes)
+ {
+ if (!type.equals(givenTerm) && so.isA(type, term))
+ {
+ includedFeatures.add(type);
+ }
+ }
+ if (!includedFeatures.isEmpty()
+ && !parents.containsValue(includedFeatures))
+ {
+ parents.put(term, includedFeatures);
+ }
+ candidates.addAll(so.getParents(term));
+ }
+
+ return parents;
+ }