JAL-629 implementation of --tempfac options
[jalview.git] / src / jalview / analysis / AlignmentUtils.java
index d04d810..42c4b76 100644 (file)
@@ -29,6 +29,7 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
@@ -36,7 +37,7 @@ import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
-import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.commands.RemoveGapColCommand;
 import jalview.datamodel.AlignedCodon;
 import jalview.datamodel.AlignedCodonFrame;
@@ -44,6 +45,7 @@ import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.GeneLociI;
 import jalview.datamodel.IncompleteCodonException;
@@ -182,10 +184,10 @@ public class AlignmentUtils
       // TODO use Character.toLowerCase to avoid creating String objects?
       char[] upstream = new String(ds
               .getSequence(s.getStart() - 1 - ustream_ds, s.getStart() - 1))
-                      .toLowerCase().toCharArray();
+              .toLowerCase(Locale.ROOT).toCharArray();
       char[] downstream = new String(
-              ds.getSequence(s_end - 1, s_end + dstream_ds)).toLowerCase()
-                      .toCharArray();
+              ds.getSequence(s_end - 1, s_end + dstream_ds))
+              .toLowerCase(Locale.ROOT).toCharArray();
       char[] coreseq = s.getSequence();
       char[] nseq = new char[offset + upstream.length + downstream.length
               + coreseq.length];
@@ -463,7 +465,8 @@ public class AlignmentUtils
     if (cdnaLength != mappedLength && cdnaLength > 2)
     {
       String lastCodon = String.valueOf(cdnaSeqChars,
-              cdnaLength - CODON_LENGTH, CODON_LENGTH).toUpperCase();
+              cdnaLength - CODON_LENGTH, CODON_LENGTH)
+              .toUpperCase(Locale.ROOT);
       for (String stop : ResidueProperties.STOP_CODONS)
       {
         if (lastCodon.equals(stop))
@@ -480,7 +483,8 @@ public class AlignmentUtils
      */
     int startOffset = 0;
     if (cdnaLength != mappedLength && cdnaLength > 2
-            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH).toUpperCase()
+            && String.valueOf(cdnaSeqChars, 0, CODON_LENGTH)
+                    .toUpperCase(Locale.ROOT)
                     .equals(ResidueProperties.START))
     {
       startOffset += CODON_LENGTH;
@@ -961,12 +965,11 @@ public class AlignmentUtils
             .findMappingsForSequence(cdsSeq, mappings);
     for (AlignedCodonFrame mapping : dnaMappings)
     {
-      List<SequenceToSequenceMapping> foundMap=new ArrayList<>();
-      SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein,foundMap);
+      SequenceI peptide = mapping.findAlignedSequence(cdsSeq, protein);
       if (peptide != null)
       {
         final int peptideLength = peptide.getLength();
-        Mapping map = foundMap.get(0).getMapping();
+        Mapping map = mapping.getMappingBetween(cdsSeq, peptide);
         if (map != null)
         {
           MapList mapList = map.getMap();
@@ -975,14 +978,14 @@ public class AlignmentUtils
             mapList = mapList.getInverse();
           }
           final int cdsLength = cdsDss.getLength();
-          int mappedFromLength = MappingUtils.getLength(mapList
-                  .getFromRanges());
+          int mappedFromLength = MappingUtils
+                  .getLength(mapList.getFromRanges());
           int mappedToLength = MappingUtils
                   .getLength(mapList.getToRanges());
-          boolean addStopCodon = peptide.getDatasetSequence().getEnd()==peptide.getEnd() && ((cdsLength == mappedFromLength
+          boolean addStopCodon = (cdsLength == mappedFromLength
                   * CODON_LENGTH + CODON_LENGTH)
                   || (peptide.getDatasetSequence()
-                          .getLength() == mappedFromLength - 1));
+                          .getLength() == mappedFromLength - 1);
           if (cdsLength != mappedToLength && !addStopCodon)
           {
             System.err.println(String.format(
@@ -1468,7 +1471,8 @@ public class AlignmentUtils
          */
         final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
                 .findAnnotations(seq, dsann.getCalcId(), dsann.label);
-        if (!matchedAlignmentAnnotations.iterator().hasNext())
+        if (matchedAlignmentAnnotations == null
+                || !matchedAlignmentAnnotations.iterator().hasNext())
         {
           result.add(dsann);
           if (labelForCalcId != null)
@@ -1514,7 +1518,7 @@ public class AlignmentUtils
           startRes = selectionGroup.getStartRes();
           endRes = selectionGroup.getEndRes();
         }
-        copyAnn.restrict(startRes, endRes);
+        copyAnn.restrict(startRes, endRes + 0);
 
         /*
          * Add to the sequence (sets copyAnn.datasetSequence), unless the
@@ -1522,6 +1526,12 @@ public class AlignmentUtils
          */
         if (!seq.hasAnnotation(ann))
         {
+          ContactMatrixI cm = seq.getDatasetSequence()
+                  .getContactMatrixFor(ann);
+          if (cm != null)
+          {
+            seq.addContactListFor(copyAnn, cm);
+          }
           seq.addAlignmentAnnotation(copyAnn);
         }
         // adjust for gaps
@@ -1531,6 +1541,7 @@ public class AlignmentUtils
         copyAnn.visible = true;
       }
     }
+
   }
 
   /**
@@ -1570,6 +1581,21 @@ public class AlignmentUtils
     }
   }
 
+  public static AlignmentAnnotation getFirstSequenceAnnotationOfType(
+          AlignmentI al, int graphType)
+  {
+    AlignmentAnnotation[] anns = al.getAlignmentAnnotation();
+    if (anns != null)
+    {
+      for (AlignmentAnnotation aa : anns)
+      {
+        if (aa.sequenceRef != null && aa.graph == graphType)
+          return aa;
+      }
+    }
+    return null;
+  }
+
   /**
    * Returns true if either sequence has a cross-reference to the other
    * 
@@ -1599,11 +1625,12 @@ public class AlignmentUtils
       return false;
     }
     String name = seq2.getName();
-    final DBRefEntry[] xrefs = seq1.getDBRefs();
+    final List<DBRefEntry> xrefs = seq1.getDBRefs();
     if (xrefs != null)
     {
-      for (DBRefEntry xref : xrefs)
+      for (int ix = 0, nx = xrefs.size(); ix < nx; ix++)
       {
+        DBRefEntry xref = xrefs.get(ix);
         String xrefName = xref.getSource() + "|" + xref.getAccessionId();
         // case-insensitive test, consistent with DBRefEntry.equalRef()
         if (xrefName.equalsIgnoreCase(name))
@@ -1649,8 +1676,8 @@ public class AlignmentUtils
       productSeqs = new HashSet<>();
       for (SequenceI seq : products)
       {
-        productSeqs.add(seq.getDatasetSequence() == null ? seq : seq
-                .getDatasetSequence());
+        productSeqs.add(seq.getDatasetSequence() == null ? seq
+                : seq.getDatasetSequence());
       }
     }
 
@@ -1754,7 +1781,7 @@ public class AlignmentUtils
             dataset.addSequence(cdsSeqDss);
             AlignedCodonFrame cdsToProteinMapping = new AlignedCodonFrame();
             cdsToProteinMapping.addMap(cdsSeqDss, proteinProduct,
-                  cdsToProteinMap);
+                    cdsToProteinMap);
 
             /*
              * guard against duplicating the mapping if repeating this action
@@ -1804,22 +1831,24 @@ public class AlignmentUtils
           // need to
           // synthesize an xref.
 
-          for (DBRefEntry primRef : dnaDss.getPrimaryDBRefs())
+          List<DBRefEntry> primrefs = dnaDss.getPrimaryDBRefs();
+          for (int ip = 0, np = primrefs.size(); ip < np; ip++)
           {
+            DBRefEntry primRef = primrefs.get(ip);
             /*
              * create a cross-reference from CDS to the source sequence's
              * primary reference and vice versa
              */
             String source = primRef.getSource();
             String version = primRef.getVersion();
-            DBRefEntry cdsCrossRef = new DBRefEntry(source, source + ":"
-                    + version, primRef.getAccessionId());
-            cdsCrossRef.setMap(new Mapping(dnaDss, new MapList(cdsToDnaMap)));
+            DBRefEntry cdsCrossRef = new DBRefEntry(source,
+                    source + ":" + version, primRef.getAccessionId());
+            cdsCrossRef
+                    .setMap(new Mapping(dnaDss, new MapList(cdsToDnaMap)));
             cdsSeqDss.addDBRef(cdsCrossRef);
 
-            dnaSeq.addDBRef(new DBRefEntry(source, version, cdsSeq
-                    .getName(), new Mapping(cdsSeqDss, dnaToCdsMap)));
-
+            dnaSeq.addDBRef(new DBRefEntry(source, version,
+                    cdsSeq.getName(), new Mapping(cdsSeqDss, dnaToCdsMap)));
             // problem here is that the cross-reference is synthesized -
             // cdsSeq.getName() may be like 'CDS|dnaaccession' or
             // 'CDS|emblcdsacc'
@@ -1828,11 +1857,10 @@ public class AlignmentUtils
             DBRefEntry proteinToCdsRef = new DBRefEntry(source, version,
                     cdsSeq.getName());
             //
-            proteinToCdsRef.setMap(new Mapping(cdsSeqDss, cdsToProteinMap
-                    .getInverse()));
+            proteinToCdsRef.setMap(
+                    new Mapping(cdsSeqDss, cdsToProteinMap.getInverse()));
             proteinProduct.addDBRef(proteinToCdsRef);
           }
-
           /*
            * transfer any features on dna that overlap the CDS
            */
@@ -1842,8 +1870,8 @@ public class AlignmentUtils
       }
     }
 
-    AlignmentI cds = new Alignment(cdsSeqs.toArray(new SequenceI[cdsSeqs
-            .size()]));
+    AlignmentI cds = new Alignment(
+            cdsSeqs.toArray(new SequenceI[cdsSeqs.size()]));
     cds.setDataset(dataset);
 
     return cds;
@@ -2054,8 +2082,9 @@ public class AlignmentUtils
           }
           else
           {
-            Cache.log.error(
-                    "JAL-2154 regression: warning - found (and ignored) a duplicate CDS sequence:" + mtch.toString());
+            Console.error(
+                    "JAL-2154 regression: warning - found (and ignored) a duplicate CDS sequence:"
+                            + mtch.toString());
           }
         }
       }
@@ -2083,13 +2112,15 @@ public class AlignmentUtils
     List<DBRefEntry> direct = new ArrayList<>();
     HashSet<String> directSources = new HashSet<>();
 
-    if (contig.getDBRefs() != null)
+    List<DBRefEntry> refs = contig.getDBRefs();
+    if (refs != null)
     {
-      for (DBRefEntry dbr : contig.getDBRefs())
+      for (int ib = 0, nb = refs.size(); ib < nb; ib++)
       {
-        if (dbr.hasMap() && dbr.getMap().getMap().isTripletMap())
+        DBRefEntry dbr = refs.get(ib);
+        MapList map;
+        if (dbr.hasMap() && (map = dbr.getMap().getMap()).isTripletMap())
         {
-          MapList map = dbr.getMap().getMap();
           // check if map is the CDS mapping
           if (mapping.getMap().equals(map))
           {
@@ -2099,21 +2130,22 @@ public class AlignmentUtils
         }
       }
     }
-    DBRefEntry[] onSource = DBRefUtils.selectRefs(
+    List<DBRefEntry> onSource = DBRefUtils.selectRefs(
             proteinProduct.getDBRefs(),
             directSources.toArray(new String[0]));
     List<DBRefEntry> propagated = new ArrayList<>();
 
     // and generate appropriate mappings
-    for (DBRefEntry cdsref : direct)
+    for (int ic = 0, nc = direct.size(); ic < nc; ic++)
     {
+      DBRefEntry cdsref = direct.get(ic);
+      Mapping m = cdsref.getMap();
       // clone maplist and mapping
       MapList cdsposmap = new MapList(
               Arrays.asList(new int[][]
               { new int[] { cdsSeq.getStart(), cdsSeq.getEnd() } }),
-              cdsref.getMap().getMap().getToRanges(), 3, 1);
-      Mapping cdsmap = new Mapping(cdsref.getMap().getTo(),
-              cdsref.getMap().getMap());
+              m.getMap().getToRanges(), 3, 1);
+      Mapping cdsmap = new Mapping(m.getTo(), m.getMap());
 
       // create dbref
       DBRefEntry newref = new DBRefEntry(cdsref.getSource(),
@@ -2176,9 +2208,9 @@ public class AlignmentUtils
     /*
      * get features, optionally restricted by an ontology term
      */
-    List<SequenceFeature> sfs = select == null ? fromSeq.getFeatures()
-            .getPositionalFeatures() : fromSeq.getFeatures()
-            .getFeaturesByOntology(select);
+    List<SequenceFeature> sfs = select == null
+            ? fromSeq.getFeatures().getPositionalFeatures()
+            : fromSeq.getFeatures().getFeaturesByOntology(select);
 
     int count = 0;
     for (SequenceFeature sf : sfs)
@@ -2323,8 +2355,8 @@ public class AlignmentUtils
   {
     List<int[]> result = new ArrayList<>();
 
-    List<SequenceFeature> sfs = dnaSeq.getFeatures().getFeaturesByOntology(
-            SequenceOntologyI.CDS);
+    List<SequenceFeature> sfs = dnaSeq.getFeatures()
+            .getFeaturesByOntology(SequenceOntologyI.CDS);
     if (sfs.isEmpty())
     {
       return result;
@@ -2336,10 +2368,14 @@ public class AlignmentUtils
       int phase = 0;
       try
       {
-        phase = Integer.parseInt(sf.getPhase());
+        String s = sf.getPhase();
+        if (s != null)
+        {
+          phase = Integer.parseInt(s);
+        }
       } catch (NumberFormatException e)
       {
-        // ignore
+        // leave as zero
       }
       /*
        * phase > 0 on first codon means 5' incomplete - skip to the start
@@ -2392,19 +2428,25 @@ public class AlignmentUtils
     SequenceIdMatcher matcher = new SequenceIdMatcher(seqs);
     if (xrefs != null)
     {
-      for (SequenceI xref : xrefs)
+      // BH 2019.01.25 recoded to remove iterators
+
+      for (int ix = 0, nx = xrefs.length; ix < nx; ix++)
       {
-        DBRefEntry[] dbrefs = xref.getDBRefs();
+        SequenceI xref = xrefs[ix];
+        List<DBRefEntry> dbrefs = xref.getDBRefs();
         if (dbrefs != null)
         {
-          for (DBRefEntry dbref : dbrefs)
+          for (int ir = 0, nir = dbrefs.size(); ir < nir; ir++)
           {
-            if (dbref.getMap() == null || dbref.getMap().getTo() == null
-                    || dbref.getMap().getTo().isProtein() != isProtein)
+            DBRefEntry dbref = dbrefs.get(ir);
+            Mapping map = dbref.getMap();
+            SequenceI mto;
+            if (map == null || (mto = map.getTo()) == null
+                    || mto.isProtein() != isProtein)
             {
               continue;
             }
-            SequenceI mappedTo = dbref.getMap().getTo();
+            SequenceI mappedTo = mto;
             SequenceI match = matcher.findIdMatch(mappedTo);
             if (match == null)
             {
@@ -2505,10 +2547,10 @@ public class AlignmentUtils
    * true; else returns false
    * 
    * @param unaligned
-   *                    - sequences to be aligned based on aligned
+   *          - sequences to be aligned based on aligned
    * @param aligned
-   *                    - 'guide' alignment containing sequences derived from same
-   *                    dataset as unaligned
+   *          - 'guide' alignment containing sequences derived from same dataset
+   *          as unaligned
    * @return
    */
   static boolean alignAsSameSequences(AlignmentI unaligned,
@@ -2544,8 +2586,7 @@ public class AlignmentUtils
       {
         return false;
       }
-      SequenceI alignedSeq = alignedDatasets.get(ds)
-              .get(0);
+      SequenceI alignedSeq = alignedDatasets.get(ds).get(0);
       int startCol = alignedSeq.findIndex(seq.getStart()); // 1..
       leftmost = Math.min(leftmost, startCol);
     }