From 04a4d60a50394d846d0479c442facebe360b5b9c Mon Sep 17 00:00:00 2001 From: gmungoc Date: Fri, 30 Mar 2018 15:56:41 +0100 Subject: [PATCH] Updated with latest from mchmmer branch --- .classpath | 1 + RELEASE | 4 +- benchmarking/README | 4 + .../java/org/jalview/HiddenColumnsBenchmark.java | 225 ++- build.xml | 17 +- examples/testdata/4IM2_missing.pdb | 525 ++++++ examples/testdata/4IM2_missing_noid.pdb | 524 ++++++ examples/testdata/4IM2_nterm.pdb | 139 ++ examples/uniref50.hmm | 466 +++++ help/help.jhm | 3 +- help/helpTOC.xml | 1 + help/html/features/preferences.html | 16 +- help/html/features/splitView.html | 2 +- help/html/menus/alwhmmer.html | 87 + help/html/releases.html | 38 + help/html/whatsNew.html | 20 +- resources/lang/Messages.properties | 68 + src/MCview/PDBChain.java | 50 + src/jalview/analysis/AAFrequency.java | 272 ++- src/jalview/analysis/AlignmentUtils.java | 29 +- src/jalview/analysis/Dna.java | 85 +- src/jalview/analysis/SeqsetUtils.java | 13 +- src/jalview/api/AlignCalcWorkerI.java | 4 +- src/jalview/api/AlignViewportI.java | 42 +- .../api/structures/JalviewStructureDisplayI.java | 7 + src/jalview/appletgui/AlignFrame.java | 30 +- src/jalview/appletgui/AlignViewport.java | 34 +- src/jalview/appletgui/AlignmentPanel.java | 10 +- src/jalview/appletgui/AnnotationLabels.java | 52 +- src/jalview/appletgui/AnnotationPanel.java | 2 +- src/jalview/appletgui/FeatureSettings.java | 18 +- src/jalview/appletgui/IdCanvas.java | 2 +- src/jalview/appletgui/IdwidthAdjuster.java | 27 +- src/jalview/appletgui/OverviewCanvas.java | 1 - src/jalview/appletgui/OverviewPanel.java | 7 +- src/jalview/appletgui/ScalePanel.java | 32 +- src/jalview/appletgui/SeqCanvas.java | 169 +- src/jalview/appletgui/SeqPanel.java | 11 +- src/jalview/bin/Cache.java | 18 +- src/jalview/bin/Jalview.java | 16 +- src/jalview/bin/JalviewLite.java | 24 +- src/jalview/datamodel/Alignment.java | 191 +- src/jalview/datamodel/AlignmentAnnotation.java | 645 ++++--- src/jalview/datamodel/AlignmentI.java | 37 +- src/jalview/datamodel/AlignmentOrder.java | 4 +- src/jalview/datamodel/AnnotatedCollectionI.java | 2 + src/jalview/datamodel/CigarArray.java | 35 +- src/jalview/datamodel/DBRefSource.java | 4 +- src/jalview/datamodel/HMMNode.java | 148 ++ src/jalview/datamodel/HiddenColumns.java | 1943 +++++++------------- src/jalview/datamodel/HiddenColumnsCursor.java | 213 +++ src/jalview/datamodel/HiddenCursorPosition.java | 26 + src/jalview/datamodel/HiddenMarkovModel.java | 612 ++++++ src/jalview/datamodel/RangeElementsIterator.java | 88 + src/jalview/datamodel/RangeIterator.java | 114 ++ src/jalview/datamodel/ResidueCount.java | 35 + src/jalview/datamodel/Sequence.java | 162 +- src/jalview/datamodel/SequenceCollectionI.java | 12 + src/jalview/datamodel/SequenceGroup.java | 298 ++- src/jalview/datamodel/SequenceI.java | 46 +- src/jalview/datamodel/StartRegionIterator.java | 123 ++ src/jalview/datamodel/VisibleColsCollection.java | 6 +- src/jalview/datamodel/VisibleColsIterator.java | 130 -- src/jalview/datamodel/VisibleContigsIterator.java | 96 + src/jalview/ext/ensembl/EnsemblGenomes.java | 11 +- src/jalview/ext/ensembl/EnsemblInfo.java | 6 +- src/jalview/ext/ensembl/EnsemblLookup.java | 89 +- src/jalview/ext/ensembl/EnsemblRestClient.java | 29 +- .../ext/ensembl/EnsemblSequenceFetcher.java | 35 +- src/jalview/ext/jmol/JmolCommands.java | 23 +- .../fts/service/uniprot/UniProtFTSRestClient.java | 16 +- src/jalview/gui/AlignFrame.java | 345 +++- src/jalview/gui/AlignViewport.java | 68 +- src/jalview/gui/AlignmentPanel.java | 49 +- src/jalview/gui/AnnotationLabels.java | 544 +++--- src/jalview/gui/AnnotationPanel.java | 31 +- src/jalview/gui/CalculationChooser.java | 12 +- src/jalview/gui/ColourMenuHelper.java | 3 +- src/jalview/gui/Desktop.java | 7 +- src/jalview/gui/FeatureSettings.java | 9 +- src/jalview/gui/IdCanvas.java | 36 +- src/jalview/gui/IdPanel.java | 5 +- src/jalview/gui/IdwidthAdjuster.java | 20 +- src/jalview/gui/Jalview2XML.java | 9 +- src/jalview/gui/Jalview2XML_V1.java | 2 +- src/jalview/gui/OptsAndParamsPage.java | 100 +- src/jalview/gui/OverviewCanvas.java | 3 +- src/jalview/gui/OverviewPanel.java | 35 +- src/jalview/gui/PairwiseAlignPanel.java | 9 +- src/jalview/gui/PopupMenu.java | 73 +- src/jalview/gui/Preferences.java | 134 +- src/jalview/gui/RotatableCanvas.java | 46 +- src/jalview/gui/ScalePanel.java | 42 +- src/jalview/gui/SeqCanvas.java | 210 +-- src/jalview/gui/SeqPanel.java | 42 +- src/jalview/gui/SplitFrame.java | 5 +- src/jalview/gui/StructureChooser.java | 118 +- src/jalview/gui/StructureViewer.java | 20 +- src/jalview/gui/StructureViewerBase.java | 51 +- src/jalview/gui/VamsasApplication.java | 16 +- src/jalview/gui/WsJobParameters.java | 40 +- src/jalview/hmmer/HMMAlign.java | 349 ++++ src/jalview/hmmer/HMMBuild.java | 362 ++++ src/jalview/hmmer/HMMERParamStore.java | 225 +++ src/jalview/hmmer/HMMERPreset.java | 57 + src/jalview/hmmer/HMMSearch.java | 320 ++++ src/jalview/hmmer/HmmerCommand.java | 280 +++ src/jalview/io/AlignFile.java | 22 +- src/jalview/io/AnnotationFile.java | 2 +- src/jalview/io/FileFormat.java | 16 + src/jalview/io/FileLoader.java | 43 + src/jalview/io/FormatAdapter.java | 6 +- src/jalview/io/HMMFile.java | 717 ++++++++ src/jalview/io/IdentifyFile.java | 5 + src/jalview/io/StockholmFile.java | 413 +++-- src/jalview/jbgui/GAlignFrame.java | 380 +++- src/jalview/jbgui/GPreferences.java | 134 +- src/jalview/renderer/AnnotationRenderer.java | 65 +- src/jalview/renderer/ResidueShaderI.java | 31 +- src/jalview/renderer/ScaleRenderer.java | 71 +- src/jalview/schemes/HmmerColourScheme.java | 196 ++ src/jalview/schemes/HmmerGlobalBackground.java | 60 + src/jalview/schemes/HmmerLocalBackground.java | 97 + src/jalview/schemes/JalviewColourScheme.java | 4 +- src/jalview/schemes/ResidueProperties.java | 62 + src/jalview/structure/StructureMapping.java | 20 +- .../structure/StructureSelectionManager.java | 159 +- .../util/HMMProbabilityDistributionAnalyser.java | 978 ++++++++++ src/jalview/util/MapList.java | 59 +- src/jalview/util/MappingUtils.java | 61 +- .../util/ProbabilityAnalyserKickstarter.java | 221 +++ src/jalview/viewmodel/AlignmentViewport.java | 336 +++- src/jalview/viewmodel/OverviewDimensions.java | 18 +- .../viewmodel/OverviewDimensionsHideHidden.java | 36 +- .../viewmodel/OverviewDimensionsShowHidden.java | 49 +- src/jalview/viewmodel/ViewportRanges.java | 6 +- src/jalview/workers/AlignCalcManager.java | 10 +- src/jalview/workers/ConsensusThread.java | 23 +- src/jalview/workers/InformationThread.java | 311 ++++ src/jalview/ws/DBRefFetcher.java | 4 +- src/jalview/ws/dbsources/Pfam.java | 17 +- src/jalview/ws/dbsources/PfamFull.java | 14 +- src/jalview/ws/dbsources/PfamSeed.java | 13 +- src/jalview/ws/dbsources/Rfam.java | 21 +- src/jalview/ws/dbsources/RfamFull.java | 14 +- src/jalview/ws/dbsources/RfamSeed.java | 13 +- src/jalview/ws/dbsources/Uniprot.java | 10 +- src/jalview/ws/dbsources/Xfam.java | 18 +- src/jalview/ws/jws1/JPredThread.java | 3 +- src/jalview/ws/jws2/MsaWSThread.java | 10 +- src/jalview/ws/params/ValueConstrainI.java | 2 +- src/jalview/ws/params/simple/DoubleParameter.java | 89 + .../ws/params/simple/LogarithmicParameter.java | 101 + src/jalview/ws/params/simple/StringParameter.java | 118 ++ src/jalview/ws/sifts/SiftsClient.java | 170 +- test/jalview/analysis/AAFrequencyTest.java | 111 ++ test/jalview/analysis/AlignmentUtilsTests.java | 183 +- test/jalview/analysis/CrossRefTest.java | 9 +- test/jalview/analysis/DnaTest.java | 27 +- .../scoremodels/FeatureDistanceModelTest.java | 4 +- .../datamodel/AlignmentAnnotationTests.java | 90 +- test/jalview/datamodel/AlignmentTest.java | 165 +- test/jalview/datamodel/AlignmentViewTest.java | 4 +- test/jalview/datamodel/ColumnSelectionTest.java | 37 +- test/jalview/datamodel/HMMNodeTest.java | 42 + .../jalview/datamodel/HiddenColumnsCursorTest.java | 157 ++ test/jalview/datamodel/HiddenColumnsTest.java | 1262 +++++++++---- test/jalview/datamodel/HiddenMarkovModelTest.java | 146 ++ test/jalview/datamodel/HiddenSequencesTest.java | 3 +- ...torTest.java => RangeElementsIteratorTest.java} | 30 +- test/jalview/datamodel/ResidueCountTest.java | 24 + test/jalview/datamodel/SequenceGroupTest.java | 8 +- test/jalview/datamodel/SequenceTest.java | 180 +- .../jalview/datamodel/StartRegionIteratorTest.java | 214 +++ .../datamodel/VisibleContigsIteratorTest.java | 223 +++ test/jalview/ext/ensembl/EnsemblGeneTest.java | 2 + test/jalview/ext/jmol/JmolCommandsTest.java | 4 +- test/jalview/gui/AlignFrameTest.java | 59 +- test/jalview/gui/AlignViewportTest.java | 18 +- test/jalview/gui/AnnotationColumnChooserTest.java | 28 +- test/jalview/gui/PairwiseAlignmentPanelTest.java | 10 +- test/jalview/gui/PopupMenuTest.java | 126 +- test/jalview/gui/SequenceRendererTest.java | 3 +- test/jalview/hmmer/HMMERTest.java | 132 ++ test/jalview/hmmer/testProps.jvprops | 88 + test/jalview/io/AnnotatedPDBFileInputTest.java | 10 +- test/jalview/io/CrossRef2xmlTests.java | 29 +- test/jalview/io/FileFormatsTest.java | 18 +- test/jalview/io/FormatAdapterTest.java | 18 +- test/jalview/io/HMMFileTest.java | 531 ++++++ test/jalview/io/JSONFileTest.java | 22 +- test/jalview/io/Jalview2xmlBase.java | 3 +- test/jalview/io/Jalview2xmlTests.java | 3 +- test/jalview/io/StockholmFileTest.java | 278 ++- test/jalview/io/test_MADE1_hmm.txt | 268 +++ test/jalview/io/test_PKinase_hmm.txt | 806 ++++++++ test/jalview/io/test_fn3_hmm.txt | 285 +++ test/jalview/io/vcf/VCFLoaderTest.java | 2 +- .../renderer/OverviewResColourFinderTest.java | 16 +- test/jalview/renderer/ResidueColourFinderTest.java | 8 +- test/jalview/renderer/ScaleRendererTest.java | 4 +- .../seqfeatures/FeatureColourFinderTest.java | 4 +- test/jalview/schemes/ClustalxColourSchemeTest.java | 2 - .../jalview/schemes/HmmerGlobalBackgroundTest.java | 91 + test/jalview/schemes/HmmerLocalBackgroundTest.java | 78 + test/jalview/schemes/PIDColourSchemeTest.java | 4 +- .../structure/StructureSelectionManagerTest.java | 336 +++- test/jalview/util/Binned.csv | 4 + .../HMMProbabilityDistributionAnalyserTest.java | 119 ++ test/jalview/util/MapListTest.java | 54 - test/jalview/util/MappingUtilsTest.java | 83 +- test/jalview/util/Raw.csv | 4 + .../util/test_Fams_for_probability_analysis | 13 + .../util/test_hmms_for_probability_analysis | 99 + test/jalview/ws/PDBSequenceFetcherTest.java | 83 +- test/jalview/ws/dbsources/PfamFullTest.java | 32 + test/jalview/ws/dbsources/PfamSeedTest.java | 32 + test/jalview/ws/dbsources/RfamFullTest.java | 32 + test/jalview/ws/dbsources/RfamSeedTest.java | 32 + test/jalview/ws/dbsources/XfamFetcherTest.java | 2 +- test/jalview/ws/sifts/SiftsClientTest.java | 196 +- 221 files changed, 19722 insertions(+), 4447 deletions(-) create mode 100644 examples/testdata/4IM2_missing.pdb create mode 100644 examples/testdata/4IM2_missing_noid.pdb create mode 100644 examples/testdata/4IM2_nterm.pdb create mode 100644 examples/uniref50.hmm create mode 100644 help/html/menus/alwhmmer.html create mode 100644 src/jalview/datamodel/HMMNode.java create mode 100644 src/jalview/datamodel/HiddenColumnsCursor.java create mode 100644 src/jalview/datamodel/HiddenCursorPosition.java create mode 100644 src/jalview/datamodel/HiddenMarkovModel.java create mode 100644 src/jalview/datamodel/RangeElementsIterator.java create mode 100644 src/jalview/datamodel/RangeIterator.java create mode 100644 src/jalview/datamodel/StartRegionIterator.java delete mode 100644 src/jalview/datamodel/VisibleColsIterator.java create mode 100644 src/jalview/datamodel/VisibleContigsIterator.java create mode 100644 src/jalview/hmmer/HMMAlign.java create mode 100644 src/jalview/hmmer/HMMBuild.java create mode 100644 src/jalview/hmmer/HMMERParamStore.java create mode 100644 src/jalview/hmmer/HMMERPreset.java create mode 100644 src/jalview/hmmer/HMMSearch.java create mode 100644 src/jalview/hmmer/HmmerCommand.java create mode 100644 src/jalview/io/HMMFile.java create mode 100644 src/jalview/schemes/HmmerColourScheme.java create mode 100644 src/jalview/schemes/HmmerGlobalBackground.java create mode 100644 src/jalview/schemes/HmmerLocalBackground.java create mode 100644 src/jalview/util/HMMProbabilityDistributionAnalyser.java create mode 100644 src/jalview/util/ProbabilityAnalyserKickstarter.java create mode 100644 src/jalview/workers/InformationThread.java create mode 100644 src/jalview/ws/params/simple/DoubleParameter.java create mode 100644 src/jalview/ws/params/simple/LogarithmicParameter.java create mode 100644 src/jalview/ws/params/simple/StringParameter.java create mode 100644 test/jalview/datamodel/HMMNodeTest.java create mode 100644 test/jalview/datamodel/HiddenColumnsCursorTest.java create mode 100644 test/jalview/datamodel/HiddenMarkovModelTest.java rename test/jalview/datamodel/{VisibleColsIteratorTest.java => RangeElementsIteratorTest.java} (84%) create mode 100644 test/jalview/datamodel/StartRegionIteratorTest.java create mode 100644 test/jalview/datamodel/VisibleContigsIteratorTest.java create mode 100644 test/jalview/hmmer/HMMERTest.java create mode 100644 test/jalview/hmmer/testProps.jvprops create mode 100644 test/jalview/io/HMMFileTest.java create mode 100644 test/jalview/io/test_MADE1_hmm.txt create mode 100644 test/jalview/io/test_PKinase_hmm.txt create mode 100644 test/jalview/io/test_fn3_hmm.txt create mode 100644 test/jalview/schemes/HmmerGlobalBackgroundTest.java create mode 100644 test/jalview/schemes/HmmerLocalBackgroundTest.java create mode 100644 test/jalview/util/Binned.csv create mode 100644 test/jalview/util/HMMProbabilityDistributionAnalyserTest.java create mode 100644 test/jalview/util/Raw.csv create mode 100644 test/jalview/util/test_Fams_for_probability_analysis create mode 100644 test/jalview/util/test_hmms_for_probability_analysis create mode 100644 test/jalview/ws/dbsources/PfamFullTest.java create mode 100644 test/jalview/ws/dbsources/PfamSeedTest.java create mode 100644 test/jalview/ws/dbsources/RfamFullTest.java create mode 100644 test/jalview/ws/dbsources/RfamSeedTest.java diff --git a/.classpath b/.classpath index c85feaf..896611c 100644 --- a/.classpath +++ b/.classpath @@ -69,5 +69,6 @@ + diff --git a/RELEASE b/RELEASE index eb9d7cd..5ad87c8 100644 --- a/RELEASE +++ b/RELEASE @@ -1,2 +1,2 @@ -jalview.release=releases/Release_2_10_3_Branch -jalview.version=2.10.3b1 +jalview.release=releases/Release_2_10_4_Branch +jalview.version=2.10.4 diff --git a/benchmarking/README b/benchmarking/README index ccf53c1..d1ec146 100644 --- a/benchmarking/README +++ b/benchmarking/README @@ -27,6 +27,9 @@ to install the jalview.jar file in the local maven repository. The pom.xml in th To get JSON output instead use: java -jar target/benchmarks.jar -rf json + To run a specific benchmark file use: + java -jar target/benchmarks.jar + JSON output can be viewed quickly by drag-dropping on http://jmh.morethan.io/ To get help use the standard -h option: @@ -38,3 +41,4 @@ to install the jalview.jar file in the local maven repository. The pom.xml in th 6. If you make changes to the Jalview code everything will need to be refreshed, by performing steps 3-5 again. + diff --git a/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java b/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java index d3c67d7..07b76f9 100644 --- a/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java +++ b/benchmarking/src/main/java/org/jalview/HiddenColumnsBenchmark.java @@ -47,128 +47,111 @@ import jalview.datamodel.HiddenColumns; @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) @Fork(1) public class HiddenColumnsBenchmark -{ - /* - * State with multiple hidden columns and a start position set - */ - @State(Scope.Thread) - public static class HiddenColsAndStartState - { - @Param({ "300", "10000", "100000" }) - public int maxcols; - - @Param({ "1", "50", "90" }) - public int startpcnt; // position as percentage of maxcols - - @Param({ "1", "15", "100" }) - public int hide; - - HiddenColumns h = new HiddenColumns(); - - Random rand = new Random(); - - public int hiddenColumn; - - public int visibleColumn; - - @Setup - public void setup() +{ + /* + * State with multiple hidden columns and a start position set + */ + @State(Scope.Thread) + public static class HiddenColsAndStartState + { + @Param({"100", "1000", "10000", "100000", "1000000"}) + public int maxcols; + + @Param({"1", "50", "90"}) + public int startpcnt; // position as percentage of maxcols + + @Param({"1","15","100"}) + public int hide; + + HiddenColumns h = new HiddenColumns(); + Random rand = new Random(); + + public int hiddenColumn; + public int visibleColumn; + + @Setup + public void setup() + { + rand.setSeed(1234); + int lastcol = 0; + while (lastcol < maxcols) + { + int count = rand.nextInt(100); + lastcol += count; + h.hideColumns(lastcol, lastcol+hide); + lastcol+=hide; + } + + // make sure column at start is hidden + hiddenColumn = (int)(maxcols * startpcnt/100.0); + h.hideColumns(hiddenColumn, hiddenColumn); + + // and column after start is visible + ColumnSelection sel = new ColumnSelection(); + h.revealHiddenColumns(hiddenColumn+hide, sel); + visibleColumn = hiddenColumn+hide; + + System.out.println("Maxcols: " + maxcols + " HiddenCol: " + hiddenColumn + " Hide: " + hide); + System.out.println("Number of hidden columns: " + h.getSize()); + } + } + + /* Convention: functions in alphabetical order */ + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate) + { + return tstate.h.visibleToAbsoluteColumn(tstate.visibleColumn); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public int benchFindColumnPosition(HiddenColsAndStartState tstate) + { + return tstate.h.absoluteToVisibleColumn(tstate.visibleColumn); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public int benchGetSize(HiddenColsAndStartState tstate) { - rand.setSeed(1234); - int lastcol = 0; - while (lastcol < maxcols) - { - int count = rand.nextInt(100); - lastcol += count; - h.hideColumns(lastcol, lastcol + hide); - lastcol += hide; - } - - // make sure column at start is hidden - hiddenColumn = (int) (maxcols * startpcnt / 100.0); - h.hideColumns(hiddenColumn, hiddenColumn); - - // and column after start is visible - ColumnSelection sel = new ColumnSelection(); - h.revealHiddenColumns(hiddenColumn + hide, sel); - visibleColumn = hiddenColumn + hide; - - System.out.println("Maxcols: " + maxcols + " HiddenCol: " - + hiddenColumn + " Hide: " + hide); - System.out.println("Number of hidden columns: " + h.getSize()); + return tstate.h.getSize(); } - } - - /* Convention: functions in alphabetical order */ - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate) - { - return tstate.h.adjustForHiddenColumns(tstate.visibleColumn); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public int benchFindColumnPosition(HiddenColsAndStartState tstate) - { - return tstate.h.findColumnPosition(tstate.visibleColumn); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public List benchFindHiddenRegionPositions( - HiddenColsAndStartState tstate) - { - return tstate.h.findHiddenRegionPositions(); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public ArrayList benchGetHiddenColumnsCopy( - HiddenColsAndStartState tstate) - { - return tstate.h.getHiddenColumnsCopy(); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public int benchGetSize(HiddenColsAndStartState tstate) - { - return tstate.h.getSize(); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public HiddenColumns benchHideCols(HiddenColsAndStartState tstate) - { - tstate.h.hideColumns(tstate.visibleColumn, tstate.visibleColumn + 2000); - return tstate.h; - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public boolean benchIsVisible(HiddenColsAndStartState tstate) - { - return tstate.h.isVisible(tstate.hiddenColumn); - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public HiddenColumns benchReveal(HiddenColsAndStartState tstate) - { - ColumnSelection sel = new ColumnSelection(); - tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel); - return tstate.h; - } - - @Benchmark - @BenchmarkMode({ Mode.Throughput }) - public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate) - { - ColumnSelection sel = new ColumnSelection(); - tstate.h.revealAllHiddenColumns(sel); - return tstate.h; - } + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public HiddenColumns benchHideCols(HiddenColsAndStartState tstate) + { + tstate.h.hideColumns(tstate.visibleColumn, + tstate.visibleColumn+2000); + return tstate.h; + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public boolean benchIsVisible(HiddenColsAndStartState tstate) + { + return tstate.h.isVisible(tstate.hiddenColumn); + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public HiddenColumns benchReveal(HiddenColsAndStartState tstate) + { + ColumnSelection sel = new ColumnSelection(); + tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel); + return tstate.h; + } + + @Benchmark + @BenchmarkMode({Mode.Throughput}) + public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate) + { + ColumnSelection sel = new ColumnSelection(); + tstate.h.revealAllHiddenColumns(sel); + return tstate.h; + } + + } \ No newline at end of file diff --git a/build.xml b/build.xml index 89c3d24..d636a42 100755 --- a/build.xml +++ b/build.xml @@ -17,7 +17,9 @@ * You should have received a copy of the GNU General Public License along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. --> - + @@ -96,6 +98,10 @@ + + + + @@ -298,6 +304,8 @@ + + @@ -431,13 +439,14 @@ - + - + + @@ -580,7 +589,6 @@ - @@ -598,7 +606,6 @@ - diff --git a/examples/testdata/4IM2_missing.pdb b/examples/testdata/4IM2_missing.pdb new file mode 100644 index 0000000..35f94b2 --- /dev/null +++ b/examples/testdata/4IM2_missing.pdb @@ -0,0 +1,525 @@ +HEADER TRANSFERASE/TRANSFERASE INHIBITOR 01-JAN-13 4IM2 +TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file) +ATOM 3510 N LEU A 468 76.337 90.332 -7.628 1.00168.53 N +ANISOU 3510 N LEU A 468 19760 15191 29082 5189 1248 -1702 N +ATOM 3511 CA LEU A 468 75.576 90.788 -6.476 1.00181.60 C +ANISOU 3511 CA LEU A 468 21073 16927 30998 5158 1421 -2051 C +ATOM 3512 C LEU A 468 76.285 91.971 -5.836 1.00196.57 C +ANISOU 3512 C LEU A 468 23029 18636 33021 5053 1667 -2229 C +ATOM 3513 O LEU A 468 75.727 93.067 -5.733 1.00197.97 O +ANISOU 3513 O LEU A 468 23115 18581 33523 5166 1662 -2304 O +ATOM 3514 CB LEU A 468 75.409 89.671 -5.449 1.00173.72 C +ANISOU 3514 CB LEU A 468 19829 16340 29836 4981 1593 -2304 C +ATOM 3515 CG LEU A 468 74.099 88.882 -5.420 1.00170.58 C +ANISOU 3515 CG LEU A 468 19142 16142 29529 5074 1449 -2345 C +ATOM 3516 CD1 LEU A 468 74.023 87.940 -6.581 1.00167.98 C +ANISOU 3516 CD1 LEU A 468 18951 15858 29015 5180 1156 -2025 C +ATOM 3517 CD2 LEU A 468 73.988 88.096 -4.145 1.00165.16 C +ANISOU 3517 CD2 LEU A 468 18217 15818 28720 4865 1706 -2656 C +ATOM 3518 N ASP A 469 77.529 91.753 -5.429 1.00208.80 N +ANISOU 3518 N ASP A 469 24731 20282 34322 4836 1875 -2296 N +ATOM 3519 CA ASP A 469 78.267 92.785 -4.720 1.00223.11 C +ANISOU 3519 CA ASP A 469 26577 21960 36233 4701 2123 -2500 C +ATOM 3520 C ASP A 469 78.653 93.973 -5.599 1.00231.96 C +ANISOU 3520 C ASP A 469 27954 22654 37525 4817 2037 -2283 C +ATOM 3521 O ASP A 469 78.718 95.100 -5.118 1.00235.71 O +ANISOU 3521 O ASP A 469 28377 22940 38242 4798 2175 -2449 O +ATOM 3522 CB ASP A 469 79.506 92.197 -4.057 1.00224.50 C +ANISOU 3522 CB ASP A 469 26841 22370 36089 4433 2350 -2633 C +ATOM 3523 CG ASP A 469 79.748 92.767 -2.679 1.00229.51 C +ANISOU 3523 CG ASP A 469 27303 23107 36794 4254 2637 -3018 C +ATOM 3524 OD1 ASP A 469 79.958 93.992 -2.564 1.00232.36 O +ANISOU 3524 OD1 ASP A 469 27695 23203 37387 4262 2718 -3093 O +ATOM 3525 OD2 ASP A 469 79.751 91.979 -1.709 1.00229.48 O +ANISOU 3525 OD2 ASP A 469 27145 23450 36598 4098 2779 -3242 O +ATOM 3526 N PHE A 470 78.904 93.735 -6.882 1.00233.88 N +ANISOU 3526 N PHE A 470 28481 22742 37641 4931 1813 -1912 N +ATOM 3527 CA PHE A 470 79.292 94.831 -7.766 1.00237.73 C +ANISOU 3527 CA PHE A 470 29252 22819 38256 5033 1733 -1677 C +ATOM 3528 C PHE A 470 78.103 95.470 -8.467 1.00232.15 C +ANISOU 3528 C PHE A 470 28512 21868 37828 5322 1470 -1512 C +ATOM 3529 O PHE A 470 78.021 96.691 -8.532 1.00230.69 O +ANISOU 3529 O PHE A 470 28371 21372 37909 5402 1493 -1517 O +ATOM 3530 CB PHE A 470 80.344 94.379 -8.784 1.00242.99 C +ANISOU 3530 CB PHE A 470 30297 23410 38616 4976 1661 -1357 C +ATOM 3531 CG PHE A 470 80.663 95.388 -9.839 1.00251.53 C +ANISOU 3531 CG PHE A 470 31709 24074 39788 5089 1550 -1064 C +ATOM 3532 CD1 PHE A 470 81.658 96.315 -9.620 1.00252.90 C +ANISOU 3532 CD1 PHE A 470 32021 24036 40032 4942 1771 -1133 C +ATOM 3533 CD2 PHE A 470 80.005 95.389 -11.059 1.00255.02 C +ANISOU 3533 CD2 PHE A 470 32335 24339 40221 5330 1225 -715 C +ATOM 3534 CE1 PHE A 470 81.981 97.242 -10.575 1.00254.75 C +ANISOU 3534 CE1 PHE A 470 32569 23879 40344 5028 1688 -862 C +ATOM 3535 CE2 PHE A 470 80.321 96.320 -12.027 1.00256.76 C +ANISOU 3535 CE2 PHE A 470 32894 24173 40491 5427 1126 -433 C +ATOM 3536 CZ PHE A 470 81.313 97.248 -11.784 1.00256.57 C +ANISOU 3536 CZ PHE A 470 33006 23929 40550 5272 1365 -504 C +ATOM 3537 N CYS A 471 77.190 94.665 -8.997 1.00176.88 N +ANISOU 3537 N CYS A 471 20955 21812 24441 2225 -3821 -3711 N +ATOM 3538 CA CYS A 471 76.124 95.233 -9.815 1.00176.41 C +ANISOU 3538 CA CYS A 471 20820 21906 24301 2124 -3576 -3614 C +ATOM 3539 C CYS A 471 74.868 95.631 -9.050 1.00176.82 C +ANISOU 3539 C CYS A 471 21026 22206 23952 2247 -3588 -3734 C +ATOM 3540 O CYS A 471 74.632 96.811 -8.854 1.00178.66 O +ANISOU 3540 O CYS A 471 21175 22393 24314 2353 -3749 -3873 O +ATOM 3541 CB CYS A 471 75.805 94.346 -11.019 1.00173.95 C +ANISOU 3541 CB CYS A 471 20521 21694 23877 1925 -3217 -3359 C +ATOM 3542 SG CYS A 471 76.954 94.571 -12.398 1.00273.04 S +ANISOU 3542 SG CYS A 471 32850 33934 36957 1863 -3075 -3146 S +ATOM 3543 N ILE A 472 74.068 94.670 -8.603 1.00173.50 N +ANISOU 3543 N ILE A 472 20813 22023 23085 2253 -3402 -3662 N +ATOM 3544 CA ILE A 472 72.771 95.033 -8.022 1.00171.09 C +ANISOU 3544 CA ILE A 472 20616 21936 22453 2374 -3307 -3694 C +ATOM 3545 C ILE A 472 72.832 96.022 -6.874 1.00177.82 C +ANISOU 3545 C ILE A 472 21591 22750 23222 2698 -3611 -3931 C +ATOM 3546 O ILE A 472 71.992 96.914 -6.776 1.00182.92 O +ANISOU 3546 O ILE A 472 22220 23491 23792 2778 -3598 -3985 O +ATOM 3547 CB ILE A 472 71.979 93.843 -7.518 1.00159.41 C +ANISOU 3547 CB ILE A 472 19318 20653 20599 2393 -3038 -3546 C +ATOM 3548 CG1 ILE A 472 70.708 93.667 -8.341 1.00147.27 C +ANISOU 3548 CG1 ILE A 472 17653 19253 19051 2196 -2745 -3384 C +ATOM 3549 CG2 ILE A 472 71.526 94.090 -6.105 1.00155.95 C +ANISOU 3549 CG2 ILE A 472 19129 20312 19812 2752 -3085 -3637 C +ATOM 3550 CD1 ILE A 472 70.927 92.915 -9.606 1.00135.92 C +ANISOU 3550 CD1 ILE A 472 16097 17752 17794 1929 -2643 -3254 C +ATOM 3551 N ARG A 473 73.812 95.865 -5.996 1.00180.33 N +ANISOU 3551 N ARG A 473 22055 22917 23544 2920 -3920 -4092 N +ATOM 3552 CA ARG A 473 73.860 96.762 -4.877 1.00189.65 C +ANISOU 3552 CA ARG A 473 23415 24034 24610 3307 -4283 -4357 C +ATOM 3553 C ARG A 473 74.328 98.021 -5.558 1.00185.98 C +ANISOU 3553 C ARG A 473 22628 23344 24692 3195 -4530 -4477 C +ATOM 3554 O ARG A 473 73.519 98.885 -5.866 1.00181.76 O +ANISOU 3554 O ARG A 473 22002 22904 24153 3165 -4446 -4474 O +ATOM 3555 CB ARG A 473 74.803 96.287 -3.768 1.00205.24 C +ANISOU 3555 CB ARG A 473 25661 25862 26460 3635 -4629 -4545 C +ATOM 3556 CG ARG A 473 74.468 96.921 -2.433 1.00220.50 C +ANISOU 3556 CG ARG A 473 27955 27814 28011 4171 -4923 -4787 C +ATOM 3557 CD ARG A 473 75.337 96.433 -1.295 1.00232.58 C +ANISOU 3557 CD ARG A 473 29837 29192 29341 4591 -5300 -5003 C +ATOM 3558 NE ARG A 473 76.763 96.602 -1.549 1.00237.46 N +ANISOU 3558 NE ARG A 473 30220 29440 30564 4489 -5773 -5205 N +ATOM 3559 CZ ARG A 473 77.716 95.991 -0.861 1.00240.32 C +ANISOU 3559 CZ ARG A 473 30786 29623 30903 4725 -6098 -5371 C +ATOM 3560 NH1 ARG A 473 77.388 95.172 0.115 1.00241.12 N +ANISOU 3560 NH1 ARG A 473 31370 29900 30344 5100 -5978 -5355 N +ATOM 3561 NH2 ARG A 473 78.988 96.195 -1.159 1.00241.54 N +ANISOU 3561 NH2 ARG A 473 30651 29398 31724 4605 -6518 -5533 N +ATOM 3562 N ASN A 474 75.608 98.073 -5.901 1.00188.74 N +ANISOU 3562 N ASN A 474 22768 23381 25563 3107 -4772 -4534 N +ATOM 3563 CA ASN A 474 76.168 99.264 -6.526 1.00188.61 C +ANISOU 3563 CA ASN A 474 22395 23075 26194 3026 -4977 -4605 C +ATOM 3564 C ASN A 474 75.420 99.892 -7.729 1.00173.98 C +ANISOU 3564 C ASN A 474 20312 21326 24467 2781 -4623 -4414 C +ATOM 3565 O ASN A 474 75.482 101.107 -7.891 1.00176.08 O +ANISOU 3565 O ASN A 474 20374 21426 25104 2827 -4803 -4518 O +ATOM 3566 CB ASN A 474 77.650 99.066 -6.857 1.00199.45 C +ANISOU 3566 CB ASN A 474 23514 24060 28207 2939 -5170 -4595 C +ATOM 3567 CG ASN A 474 78.504 98.809 -5.625 1.00210.23 C +ANISOU 3567 CG ASN A 474 25062 25219 29597 3243 -5689 -4883 C +ATOM 3568 OD1 ASN A 474 78.174 99.240 -4.527 1.00215.26 O +ANISOU 3568 OD1 ASN A 474 25969 25891 29928 3596 -6043 -5160 O +ATOM 3569 ND2 ASN A 474 79.613 98.103 -5.810 1.00212.07 N +ANISOU 3569 ND2 ASN A 474 25176 25222 30179 3148 -5748 -4822 N +ATOM 3570 N ILE A 475 74.722 99.114 -8.562 1.00161.86 N +ANISOU 3570 N ILE A 475 18813 20033 22652 2556 -4165 -4158 N +ATOM 3571 CA ILE A 475 74.022 99.727 -9.709 1.00154.84 C +ANISOU 3571 CA ILE A 475 17755 19216 21861 2390 -3885 -4015 C +ATOM 3572 C ILE A 475 72.785 100.520 -9.312 1.00159.27 C +ANISOU 3572 C ILE A 475 18401 19995 22121 2490 -3891 -4125 C +ATOM 3573 O ILE A 475 72.662 101.687 -9.663 1.00162.60 O +ANISOU 3573 O ILE A 475 18651 20327 22804 2505 -3962 -4186 O +ATOM 3574 CB ILE A 475 73.600 98.727 -10.818 1.00214.93 C +ANISOU 3574 CB ILE A 475 25397 26975 29293 2173 -3475 -3753 C +ATOM 3575 CG1 ILE A 475 74.808 98.227 -11.613 1.00218.74 C +ANISOU 3575 CG1 ILE A 475 25753 27211 30145 2083 -3390 -3585 C +ATOM 3576 CG2 ILE A 475 72.618 99.379 -11.789 1.00210.37 C +ANISOU 3576 CG2 ILE A 475 24743 26509 28681 2097 -3256 -3677 C +ATOM 3577 CD1 ILE A 475 74.446 97.201 -12.664 1.00218.15 C +ANISOU 3577 CD1 ILE A 475 25777 27260 29850 1946 -3056 -3359 C +ATOM 3578 N GLU A 476 71.856 99.893 -8.600 1.00156.45 N +ANISOU 3578 N GLU A 476 18293 19907 21245 2571 -3778 -4120 N +ATOM 3579 CA GLU A 476 70.623 100.594 -8.252 1.00142.72 C +ANISOU 3579 CA GLU A 476 16627 18370 19231 2677 -3720 -4176 C +ATOM 3580 C GLU A 476 70.845 101.560 -7.094 1.00144.41 C +ANISOU 3580 C GLU A 476 16959 18500 19412 3012 -4114 -4440 C +ATOM 3581 O GLU A 476 70.012 102.417 -6.811 1.00142.58 O +ANISOU 3581 O GLU A 476 16768 18380 19024 3141 -4136 -4517 O +ATOM 3582 CB GLU A 476 69.486 99.616 -7.958 1.00128.68 C +ANISOU 3582 CB GLU A 476 15020 16860 17012 2665 -3395 -4018 C +ATOM 3583 CG GLU A 476 69.562 98.905 -6.628 1.00128.73 C +ANISOU 3583 CG GLU A 476 15321 16930 16662 2941 -3433 -4041 C +ATOM 3584 CD GLU A 476 68.465 97.866 -6.484 1.00133.35 C +ANISOU 3584 CD GLU A 476 15992 17719 16955 2900 -3026 -3806 C +ATOM 3585 OE1 GLU A 476 68.285 97.061 -7.422 1.00132.30 O +ANISOU 3585 OE1 GLU A 476 15710 17598 16962 2603 -2816 -3643 O +ATOM 3586 OE2 GLU A 476 67.768 97.860 -5.448 1.00136.37 O +ANISOU 3586 OE2 GLU A 476 16588 18223 17003 3196 -2912 -3773 O +ATOM 3587 N LYS A 477 71.990 101.424 -6.439 1.00148.46 N +ANISOU 3587 N LYS A 477 17534 18788 20087 3179 -4467 -4596 N +ATOM 3588 CA LYS A 477 72.399 102.365 -5.405 1.00154.25 C +ANISOU 3588 CA LYS A 477 18378 19348 20882 3544 -4976 -4907 C +ATOM 3589 C LYS A 477 72.634 103.732 -5.994 1.00159.76 C +ANISOU 3589 C LYS A 477 18754 19833 22117 3467 -5183 -5014 C +ATOM 3590 O LYS A 477 72.568 104.742 -5.292 1.00158.01 O +ANISOU 3590 O LYS A 477 18598 19516 21921 3749 -5568 -5266 O +ATOM 3591 CB LYS A 477 73.667 101.883 -4.706 1.00154.03 C +ANISOU 3591 CB LYS A 477 18446 19057 21022 3730 -5372 -5076 C +ATOM 3592 CG LYS A 477 73.367 100.787 -3.750 1.00149.76 C +ANISOU 3592 CG LYS A 477 18324 18717 19861 3975 -5258 -5042 C +ATOM 3593 CD LYS A 477 74.437 100.554 -2.740 1.00143.39 C +ANISOU 3593 CD LYS A 477 17737 17664 19082 4327 -5762 -5306 C +ATOM 3594 CE LYS A 477 73.739 100.087 -1.488 1.00145.72 C +ANISOU 3594 CE LYS A 477 18569 18186 18613 4805 -5697 -5337 C +ATOM 3595 NZ LYS A 477 74.661 99.556 -0.469 1.00149.42 N +ANISOU 3595 NZ LYS A 477 19366 18470 18936 5206 -6108 -5561 N +ATOM 3596 N THR A 478 72.908 103.757 -7.293 1.00166.45 N +ANISOU 3596 N THR A 478 19271 20589 23384 3124 -4918 -4810 N +ATOM 3597 CA THR A 478 73.186 105.012 -7.968 1.00170.99 C +ANISOU 3597 CA THR A 478 19509 20929 24531 3052 -5023 -4844 C +ATOM 3598 C THR A 478 71.905 105.733 -8.391 1.00172.33 C +ANISOU 3598 C THR A 478 19686 21358 24435 2999 -4780 -4796 C +ATOM 3599 O THR A 478 71.021 105.170 -9.046 1.00163.10 O +ANISOU 3599 O THR A 478 18581 20461 22928 2823 -4356 -4594 O +ATOM 3600 CB THR A 478 74.217 104.856 -9.128 1.00146.93 C +ANISOU 3600 CB THR A 478 16115 17589 22125 2815 -4843 -4626 C +ATOM 3601 OG1 THR A 478 74.873 106.106 -9.369 1.00147.15 O +ANISOU 3601 OG1 THR A 478 15790 17239 22881 2857 -5085 -4705 O +ATOM 3602 CG2 THR A 478 73.562 104.391 -10.425 1.00144.32 C +ANISOU 3602 CG2 THR A 478 15764 17473 21597 2570 -4282 -4318 C +ATOM 3603 N VAL A 479 71.809 106.979 -7.944 1.00177.73 N +ANISOU 3603 N VAL A 479 20309 21929 25291 3181 -5110 -5014 N +ATOM 3604 CA VAL A 479 70.674 107.838 -8.218 1.00175.65 C +ANISOU 3604 CA VAL A 479 20044 21875 24819 3171 -4959 -5013 C +ATOM 3605 C VAL A 479 71.176 109.077 -8.939 1.00177.67 C +ANISOU 3605 C VAL A 479 19928 21830 25749 3101 -5069 -5035 C +ATOM 3606 O VAL A 479 72.353 109.417 -8.840 1.00179.02 O +ANISOU 3606 O VAL A 479 19865 21600 26555 3150 -5387 -5121 O +ATOM 3607 CB VAL A 479 69.983 108.266 -6.909 1.00168.37 C +ANISOU 3607 CB VAL A 479 19442 21113 23418 3524 -5243 -5249 C +ATOM 3608 CG1 VAL A 479 69.008 109.403 -7.169 1.00162.23 C +ANISOU 3608 CG1 VAL A 479 18603 20470 22565 3531 -5176 -5285 C +ATOM 3609 CG2 VAL A 479 69.288 107.080 -6.256 1.00163.89 C +ANISOU 3609 CG2 VAL A 479 19236 20856 22180 3624 -4991 -5142 C +ATOM 3610 N MET A 486 57.931 103.433 -6.150 1.00 92.00 N +ANISOU 3610 N MET A 486 10154 13425 11375 3371 -1523 -3283 N +ATOM 3611 CA MET A 486 56.824 104.104 -5.482 1.00110.61 C +ANISOU 3611 CA MET A 486 12558 15882 13585 3644 -1287 -3161 C +ATOM 3612 C MET A 486 56.182 105.150 -6.389 1.00111.38 C +ANISOU 3612 C MET A 486 12428 16016 13877 3424 -1416 -3308 C +ATOM 3613 O MET A 486 56.000 106.305 -6.002 1.00120.35 O +ANISOU 3613 O MET A 486 13691 17243 14794 3639 -1526 -3430 O +ATOM 3614 CB MET A 486 57.288 104.743 -4.170 1.00120.60 C +ANISOU 3614 CB MET A 486 14253 17221 14347 4174 -1395 -3243 C +ATOM 3615 CG MET A 486 58.405 105.768 -4.316 1.00126.87 C +ANISOU 3615 CG MET A 486 15171 17987 15047 4196 -1944 -3629 C +ATOM 3616 SD MET A 486 58.150 107.169 -3.210 1.00146.78 S +ANISOU 3616 SD MET A 486 18044 20597 17128 4757 -2124 -3782 S +ATOM 3617 CE MET A 486 58.003 106.326 -1.640 1.00102.35 C +ANISOU 3617 CE MET A 486 12883 15002 11003 5391 -1797 -3524 C +ATOM 3618 N GLY A 496 57.154 99.412 -2.065 1.00157.62 N +ANISOU 3618 N GLY A 496 19150 21656 19083 4616 82 -2024 N +ATOM 3619 CA GLY A 496 57.031 99.217 -3.498 1.00158.07 C +ANISOU 3619 CA GLY A 496 18749 21636 19677 3991 -116 -2141 C +ATOM 3620 C GLY A 496 57.664 97.914 -3.942 1.00163.71 C +ANISOU 3620 C GLY A 496 19349 22235 20619 3709 -140 -2093 C +ATOM 3621 O GLY A 496 58.040 97.090 -3.111 1.00167.17 O +ANISOU 3621 O GLY A 496 20009 22652 20858 3970 79 -1915 O +ATOM 3622 N GLU A 497 57.778 97.722 -5.254 1.00166.67 N +ANISOU 3622 N GLU A 497 19413 22530 21383 3222 -403 -2250 N +ATOM 3623 CA GLU A 497 58.431 96.534 -5.792 1.00170.73 C +ANISOU 3623 CA GLU A 497 19840 22933 22098 2955 -485 -2239 C +ATOM 3624 C GLU A 497 59.931 96.621 -5.556 1.00172.64 C +ANISOU 3624 C GLU A 497 20403 23228 21965 3043 -809 -2472 C +ATOM 3625 O GLU A 497 60.589 95.609 -5.311 1.00173.01 O +ANISOU 3625 O GLU A 497 20547 23223 21965 3047 -764 -2395 O +ATOM 3626 CB GLU A 497 58.173 96.394 -7.290 1.00169.62 C +ANISOU 3626 CB GLU A 497 19361 22681 22408 2505 -727 -2374 C +ATOM 3627 CG GLU A 497 56.882 97.012 -7.777 1.00173.11 C +ANISOU 3627 CG GLU A 497 19518 23086 23171 2413 -663 -2350 C +ATOM 3628 CD GLU A 497 56.703 96.840 -9.270 1.00173.61 C +ANISOU 3628 CD GLU A 497 19329 23013 23621 2054 -974 -2531 C +ATOM 3629 OE1 GLU A 497 57.597 96.241 -9.908 1.00170.78 O +ANISOU 3629 OE1 GLU A 497 19040 22600 23250 1901 -1202 -2647 O +ATOM 3630 OE2 GLU A 497 55.672 97.300 -9.805 1.00174.73 O +ANISOU 3630 OE2 GLU A 497 19233 23093 24064 1967 -999 -2559 O +ATOM 3631 N ILE A 498 60.466 97.836 -5.652 1.00171.44 N +ANISOU 3631 N ILE A 498 20381 23149 21608 3107 -1147 -2757 N +ATOM 3632 CA ILE A 498 61.883 98.078 -5.403 1.00167.93 C +ANISOU 3632 CA ILE A 498 20186 22695 20926 3210 -1503 -2995 C +ATOM 3633 C ILE A 498 62.251 97.620 -4.004 1.00173.82 C +ANISOU 3633 C ILE A 498 21298 23465 21280 3659 -1379 -2903 C +ATOM 3634 O ILE A 498 63.315 97.034 -3.789 1.00168.12 O +ANISOU 3634 O ILE A 498 20732 22684 20462 3692 -1544 -2980 O +ATOM 3635 CB ILE A 498 62.227 99.564 -5.520 1.00165.53 C +ANISOU 3635 CB ILE A 498 19934 22420 20540 3287 -1855 -3283 C +ATOM 3636 CG1 ILE A 498 61.848 100.100 -6.901 1.00171.37 C +ANISOU 3636 CG1 ILE A 498 20360 23137 21618 2911 -1947 -3365 C +ATOM 3637 CG2 ILE A 498 63.706 99.798 -5.239 1.00153.61 C +ANISOU 3637 CG2 ILE A 498 18613 20820 18931 3398 -2256 -3525 C +ATOM 3638 CD1 ILE A 498 61.891 101.605 -6.996 1.00174.73 C +ANISOU 3638 CD1 ILE A 498 20793 23594 22004 2996 -2195 -3587 C +ATOM 3639 N SER A 499 61.362 97.890 -3.054 1.00187.32 N +ANISOU 3639 N SER A 499 23169 25252 22753 4049 -1074 -2727 N +ATOM 3640 CA SER A 499 61.558 97.444 -1.683 1.00198.47 C +ANISOU 3640 CA SER A 499 24999 26682 23729 4594 -880 -2593 C +ATOM 3641 C SER A 499 61.611 95.926 -1.651 1.00206.95 C +ANISOU 3641 C SER A 499 26003 27687 24943 4481 -548 -2315 C +ATOM 3642 O SER A 499 62.302 95.334 -0.823 1.00211.11 O +ANISOU 3642 O SER A 499 26867 28195 25151 4806 -533 -2293 O +ATOM 3643 CB SER A 499 60.435 97.952 -0.780 1.00200.16 C +ANISOU 3643 CB SER A 499 25385 26976 23690 5064 -498 -2368 C +ATOM 3644 OG SER A 499 60.635 97.541 0.556 1.00203.12 O +ANISOU 3644 OG SER A 499 26244 27359 23574 5697 -286 -2224 O +ATOM 3645 N ASP A 500 60.877 95.300 -2.564 1.00209.43 N +ANISOU 3645 N ASP A 500 25883 27938 25751 4040 -320 -2123 N +ATOM 3646 CA ASP A 500 60.862 93.851 -2.655 1.00212.36 C +ANISOU 3646 CA ASP A 500 26120 28207 26361 3883 -39 -1865 C +ATOM 3647 C ASP A 500 62.097 93.307 -3.366 1.00203.21 C +ANISOU 3647 C ASP A 500 24946 26999 25265 3557 -426 -2093 C +ATOM 3648 O ASP A 500 62.511 92.195 -3.092 1.00204.96 O +ANISOU 3648 O ASP A 500 25238 27165 25472 3573 -286 -1954 O +ATOM 3649 CB ASP A 500 59.580 93.355 -3.335 1.00221.23 C +ANISOU 3649 CB ASP A 500 26765 29217 28075 3573 287 -1593 C +ATOM 3650 CG ASP A 500 58.346 93.583 -2.486 1.00233.55 C +ANISOU 3650 CG ASP A 500 28310 30773 29657 3938 816 -1243 C +ATOM 3651 OD1 ASP A 500 58.502 93.807 -1.272 1.00239.09 O +ANISOU 3651 OD1 ASP A 500 29432 31558 29852 4492 1029 -1137 O +ATOM 3652 OD2 ASP A 500 57.226 93.532 -3.034 1.00237.24 O +ANISOU 3652 OD2 ASP A 500 28355 31128 30656 3709 1011 -1072 O +ATOM 3653 N ILE A 501 62.692 94.094 -4.258 1.00192.67 N +ANISOU 3653 N ILE A 501 23525 25673 24008 3292 -875 -2413 N +ATOM 3654 CA ILE A 501 63.864 93.633 -5.007 1.00181.71 C +ANISOU 3654 CA ILE A 501 22108 24215 22719 3006 -1195 -2587 C +ATOM 3655 C ILE A 501 65.165 93.699 -4.196 1.00170.68 C +ANISOU 3655 C ILE A 501 21064 22814 20972 3287 -1450 -2764 C +ATOM 3656 O ILE A 501 65.940 92.735 -4.173 1.00164.70 O +ANISOU 3656 O ILE A 501 20376 21999 20202 3222 -1476 -2736 O +ATOM 3657 CB ILE A 501 64.023 94.385 -6.353 1.00138.03 C +ANISOU 3657 CB ILE A 501 16341 18649 17453 2657 -1507 -2802 C +ATOM 3658 CG1 ILE A 501 63.385 93.589 -7.491 1.00130.33 C +ANISOU 3658 CG1 ILE A 501 15061 17587 16872 2296 -1411 -2683 C +ATOM 3659 CG2 ILE A 501 65.491 94.642 -6.682 1.00137.98 C +ANISOU 3659 CG2 ILE A 501 16437 18581 17410 2596 -1883 -3037 C +ATOM 3660 CD1 ILE A 501 61.877 93.516 -7.426 1.00127.50 C +ANISOU 3660 CD1 ILE A 501 14480 17217 16748 2292 -1111 -2482 C +ATOM 3661 N HIS A 502 65.396 94.829 -3.532 1.00164.00 N +ANISOU 3661 N HIS A 502 20439 22007 19869 3613 -1676 -2964 N +ATOM 3662 CA HIS A 502 66.603 95.022 -2.737 1.00157.69 C +ANISOU 3662 CA HIS A 502 19968 21147 18800 3931 -2029 -3195 C +ATOM 3663 C HIS A 502 66.627 94.018 -1.594 1.00162.64 C +ANISOU 3663 C HIS A 502 20933 21795 19069 4322 -1761 -3012 C +ATOM 3664 O HIS A 502 67.677 93.496 -1.229 1.00164.35 O +ANISOU 3664 O HIS A 502 21348 21935 19163 4433 -1971 -3125 O +ATOM 3665 CB HIS A 502 66.654 96.452 -2.195 1.00150.83 C +ANISOU 3665 CB HIS A 502 19272 20282 17755 4264 -2351 -3452 C +ATOM 3666 CG HIS A 502 67.989 97.117 -2.348 1.00143.78 C +ANISOU 3666 CG HIS A 502 18387 19223 17019 4248 -2929 -3804 C +ATOM 3667 ND1 HIS A 502 68.672 97.155 -3.544 1.00137.00 N +ANISOU 3667 ND1 HIS A 502 17193 18253 16609 3785 -3096 -3872 N +ATOM 3668 CD2 HIS A 502 68.759 97.787 -1.457 1.00140.15 C +ANISOU 3668 CD2 HIS A 502 18217 18647 16387 4674 -3387 -4099 C +ATOM 3669 CE1 HIS A 502 69.807 97.814 -3.383 1.00131.33 C +ANISOU 3669 CE1 HIS A 502 16503 17343 16055 3893 -3583 -4155 C +ATOM 3670 NE2 HIS A 502 69.883 98.208 -2.125 1.00130.34 N +ANISOU 3670 NE2 HIS A 502 16741 17200 15583 4416 -3815 -4326 N +ATOM 3671 N THR A 503 65.450 93.751 -1.039 1.00163.37 N +ANISOU 3671 N THR A 503 21080 21971 19022 4552 -1268 -2705 N +ATOM 3672 CA THR A 503 65.295 92.771 0.033 1.00163.31 C +ANISOU 3672 CA THR A 503 21384 21972 18696 4974 -872 -2437 C +ATOM 3673 C THR A 503 65.393 91.327 -0.475 1.00151.49 C +ANISOU 3673 C THR A 503 19659 20415 17484 4610 -614 -2206 C +ATOM 3674 O THR A 503 65.955 90.464 0.198 1.00146.11 O +ANISOU 3674 O THR A 503 19247 19705 16563 4853 -520 -2130 O +ATOM 3675 CB THR A 503 63.956 92.972 0.783 1.00170.09 C +ANISOU 3675 CB THR A 503 22342 22899 19387 5379 -334 -2106 C +ATOM 3676 OG1 THR A 503 64.026 94.162 1.576 1.00176.61 O +ANISOU 3676 OG1 THR A 503 23551 23775 19778 5902 -585 -2325 O +ATOM 3677 CG2 THR A 503 63.645 91.790 1.693 1.00171.53 C +ANISOU 3677 CG2 THR A 503 22747 23054 19374 5760 235 -1707 C +ATOM 3678 N LYS A 504 64.865 91.071 -1.669 1.00141.41 N +ANISOU 3678 N LYS A 504 17911 19106 16711 4058 -541 -2117 N +ATOM 3679 CA LYS A 504 64.918 89.730 -2.251 1.00138.96 C +ANISOU 3679 CA LYS A 504 17368 18711 16719 3706 -369 -1930 C +ATOM 3680 C LYS A 504 66.335 89.382 -2.646 1.00142.04 C +ANISOU 3680 C LYS A 504 17848 19062 17058 3520 -779 -2178 C +ATOM 3681 O LYS A 504 66.762 88.230 -2.559 1.00134.46 O +ANISOU 3681 O LYS A 504 16927 18053 16108 3463 -666 -2057 O +ATOM 3682 CB LYS A 504 64.010 89.614 -3.477 1.00129.82 C +ANISOU 3682 CB LYS A 504 15721 17488 16116 3223 -303 -1839 C +ATOM 3683 CG LYS A 504 62.585 89.222 -3.164 1.00130.75 C +ANISOU 3683 CG LYS A 504 15616 17544 16518 3307 225 -1458 C +ATOM 3684 N LEU A 505 67.053 90.395 -3.100 1.00138.41 N +ANISOU 3684 N LEU A 505 17394 18602 16593 3427 -1237 -2505 N +ATOM 3685 CA LEU A 505 68.435 90.224 -3.458 1.00120.29 C +ANISOU 3685 CA LEU A 505 15154 16230 14322 3285 -1619 -2726 C +ATOM 3686 C LEU A 505 69.260 89.889 -2.223 1.00124.70 C +ANISOU 3686 C LEU A 505 16126 16770 14484 3724 -1710 -2800 C +ATOM 3687 O LEU A 505 70.166 89.052 -2.259 1.00124.02 O +ANISOU 3687 O LEU A 505 16106 16619 14396 3643 -1808 -2823 O +ATOM 3688 CB LEU A 505 68.966 91.499 -4.066 1.00109.42 C +ANISOU 3688 CB LEU A 505 13673 14807 13094 3171 -2036 -3016 C +ATOM 3689 CG LEU A 505 70.386 91.097 -4.404 1.00128.61 C +ANISOU 3689 CG LEU A 505 16120 17111 15635 3034 -2336 -3157 C +ATOM 3690 CD1 LEU A 505 70.509 91.048 -5.920 1.00141.22 C +ANISOU 3690 CD1 LEU A 505 17393 18648 17616 2580 -2370 -3131 C +ATOM 3691 CD2 LEU A 505 71.441 91.946 -3.655 1.00114.58 C +ANISOU 3691 CD2 LEU A 505 14554 15224 13758 3350 -2784 -3462 C +ATOM 3692 N LEU A 506 68.951 90.579 -1.132 1.00130.40 N +ANISOU 3692 N LEU A 506 17159 17539 14847 4233 -1705 -2854 N +ATOM 3693 CA LEU A 506 69.612 90.336 0.139 1.00131.63 C +ANISOU 3693 CA LEU A 506 17798 17665 14549 4786 -1814 -2947 C +ATOM 3694 C LEU A 506 69.501 88.865 0.507 1.00144.65 C +ANISOU 3694 C LEU A 506 19548 19330 16080 4841 -1380 -2638 C +ATOM 3695 O LEU A 506 70.448 88.287 1.024 1.00156.36 O +ANISOU 3695 O LEU A 506 21304 20754 17351 5038 -1550 -2741 O +ATOM 3696 CB LEU A 506 69.008 91.206 1.240 1.00120.17 C +ANISOU 3696 CB LEU A 506 16713 16270 12675 5409 -1772 -2980 C +ATOM 3697 N ARG A 507 68.351 88.260 0.214 1.00146.01 N +ANISOU 3697 N ARG A 507 19470 19552 16453 4658 -839 -2263 N +ATOM 3698 CA ARG A 507 68.159 86.831 0.443 1.00152.26 C +ANISOU 3698 CA ARG A 507 20261 20320 17271 4649 -394 -1930 C +ATOM 3699 C ARG A 507 69.164 86.004 -0.360 1.00145.14 C +ANISOU 3699 C ARG A 507 19199 19352 16597 4200 -653 -2042 C +ATOM 3700 O ARG A 507 69.471 84.873 0.007 1.00142.95 O +ANISOU 3700 O ARG A 507 19044 19045 16224 4273 -450 -1882 O +ATOM 3701 CB ARG A 507 66.724 86.401 0.111 1.00161.16 C +ANISOU 3701 CB ARG A 507 21023 21434 18777 4463 165 -1523 C +ATOM 3702 CG ARG A 507 65.661 86.975 1.046 1.00177.63 C +ANISOU 3702 CG ARG A 507 23283 23565 20645 4978 585 -1290 C +ATOM 3703 CD ARG A 507 64.263 86.468 0.696 1.00187.68 C +ANISOU 3703 CD ARG A 507 24111 24757 22442 4769 1148 -857 C +ATOM 3704 NE ARG A 507 63.229 87.082 1.527 1.00198.88 N +ANISOU 3704 NE ARG A 507 25661 26202 23704 5259 1588 -600 N +ATOM 3705 CZ ARG A 507 61.923 86.883 1.368 1.00205.71 C +ANISOU 3705 CZ ARG A 507 26137 26967 25058 5169 2095 -210 C +ATOM 3706 NH1 ARG A 507 61.484 86.084 0.406 1.00207.33 N +ANISOU 3706 NH1 ARG A 507 25797 27020 25959 4610 2159 -75 N +ATOM 3707 NH2 ARG A 507 61.055 87.485 2.171 1.00208.11 N +ANISOU 3707 NH2 ARG A 507 26596 27293 25185 5668 2517 41 N +ATOM 3708 N LEU A 508 69.681 86.579 -1.445 1.00134.19 N +ANISOU 3708 N LEU A 508 17555 17933 15496 3776 -1072 -2294 N +ATOM 3709 CA LEU A 508 70.654 85.888 -2.287 1.00125.06 C +ANISOU 3709 CA LEU A 508 16259 16704 14555 3385 -1304 -2382 C +ATOM 3710 C LEU A 508 72.070 85.983 -1.730 1.00133.75 C +ANISOU 3710 C LEU A 508 17660 17739 15419 3609 -1705 -2655 C +ATOM 3711 O LEU A 508 72.775 84.975 -1.650 1.00132.42 O +ANISOU 3711 O LEU A 508 17581 17530 15202 3562 -1700 -2615 O +ATOM 3712 CB LEU A 508 70.606 86.404 -3.726 1.00112.64 C +ANISOU 3712 CB LEU A 508 14312 15095 13392 2907 -1513 -2482 C +ATOM 3713 CG LEU A 508 69.271 86.186 -4.436 1.00113.17 C +ANISOU 3713 CG LEU A 508 14056 15174 13769 2653 -1215 -2260 C +ATOM 3714 CD1 LEU A 508 69.459 86.184 -5.945 1.00106.22 C +ANISOU 3714 CD1 LEU A 508 12898 14225 13237 2216 -1432 -2343 C +ATOM 3715 CD2 LEU A 508 68.613 84.894 -3.968 1.00117.32 C +ANISOU 3715 CD2 LEU A 508 14560 15678 14341 2703 -779 -1932 C +ATOM 3716 N SER A 509 72.491 87.188 -1.355 1.00130.72 N +ANISOU 3716 N SER A 509 17414 17317 14936 3856 -2085 -2944 N +ATOM 3717 CA SER A 509 73.767 87.347 -0.663 1.00136.66 C +ANISOU 3717 CA SER A 509 18457 17948 15519 4156 -2531 -3236 C +ATOM 3718 C SER A 509 73.698 86.583 0.646 1.00143.40 C +ANISOU 3718 C SER A 509 19773 18845 15866 4687 -2319 -3138 C +ATOM 3719 O SER A 509 74.680 85.977 1.082 1.00138.35 O +ANISOU 3719 O SER A 509 19358 18121 15090 4839 -2521 -3256 O +ATOM 3720 CB SER A 509 74.089 88.820 -0.410 1.00130.15 C +ANISOU 3720 CB SER A 509 17685 17028 14738 4382 -3008 -3572 C +ATOM 3721 OG SER A 509 74.991 89.319 -1.384 1.00125.27 O +ANISOU 3721 OG SER A 509 16739 16248 14609 4003 -3376 -3749 O +ATOM 3722 N SER A 510 72.520 86.615 1.263 1.00144.65 N +ANISOU 3722 N SER A 510 20078 19123 15761 4999 -1878 -2899 N +ATOM 3723 CA SER A 510 72.236 85.777 2.417 1.00148.97 C +ANISOU 3723 CA SER A 510 21044 19713 15846 5526 -1487 -2677 C +ATOM 3724 C SER A 510 72.424 84.315 2.046 1.00145.48 C +ANISOU 3724 C SER A 510 20455 19266 15554 5204 -1182 -2426 C +ATOM 3725 O SER A 510 73.001 83.552 2.811 1.00140.49 O +ANISOU 3725 O SER A 510 20177 18606 14598 5539 -1145 -2415 O +ATOM 3726 CB SER A 510 70.807 85.999 2.911 1.00149.05 C +ANISOU 3726 CB SER A 510 21111 19824 15699 5832 -930 -2348 C +ATOM 3727 OG SER A 510 70.346 84.882 3.643 1.00147.27 O +ANISOU 3727 OG SER A 510 21097 19617 15240 6154 -337 -1962 O +ATOM 3728 N SER A 511 71.946 83.946 0.858 1.00139.39 N +ANISOU 3728 N SER A 511 19184 18508 15269 4583 -1004 -2249 N +ATOM 3729 CA SER A 511 72.011 82.573 0.365 1.00129.68 C +ANISOU 3729 CA SER A 511 17763 17254 14255 4236 -745 -2013 C +ATOM 3730 C SER A 511 73.437 82.171 0.006 1.00129.30 C +ANISOU 3730 C SER A 511 17762 17135 14232 4035 -1175 -2258 C +ATOM 3731 O SER A 511 73.792 80.991 0.047 1.00109.17 O +ANISOU 3731 O SER A 511 15254 14565 11659 3957 -1019 -2119 O +ATOM 3732 CB SER A 511 71.108 82.416 -0.862 1.00125.40 C +ANISOU 3732 CB SER A 511 16701 16703 14243 3684 -564 -1828 C +ATOM 3733 OG SER A 511 71.167 81.106 -1.394 1.00137.08 O +ANISOU 3733 OG SER A 511 17990 18125 15969 3359 -392 -1635 O +ATOM 3734 N GLN A 512 74.247 83.164 -0.347 1.00131.12 N +ANISOU 3734 N GLN A 512 17958 17304 14560 3957 -1699 -2603 N +ATOM 3735 CA GLN A 512 75.621 82.941 -0.774 1.00120.52 C +ANISOU 3735 CA GLN A 512 16587 15845 13361 3755 -2110 -2821 C +ATOM 3736 C GLN A 512 76.508 82.796 0.431 1.00123.24 C +ANISOU 3736 C GLN A 512 17385 16120 13322 4264 -2359 -3023 C +ATOM 3737 O GLN A 512 77.569 82.174 0.385 1.00128.94 O +ANISOU 3737 O GLN A 512 18162 16749 14081 4188 -2573 -3124 O +ATOM 3738 CB GLN A 512 76.096 84.150 -1.546 1.00118.44 C +ANISOU 3738 CB GLN A 512 16077 15483 13440 3537 -2531 -3073 C +ATOM 3739 CG GLN A 512 76.798 83.822 -2.807 1.00125.91 C +ANISOU 3739 CG GLN A 512 16711 16343 14787 3048 -2644 -3057 C +ATOM 3740 CD GLN A 512 76.915 85.020 -3.690 1.00137.22 C +ANISOU 3740 CD GLN A 512 17859 17690 16589 2843 -2877 -3186 C +ATOM 3741 OE1 GLN A 512 77.456 86.052 -3.281 1.00153.03 O +ANISOU 3741 OE1 GLN A 512 19904 19568 18672 3053 -3245 -3442 O +ATOM 3742 NE2 GLN A 512 76.353 84.922 -4.897 1.00128.62 N +ANISOU 3742 NE2 GLN A 512 16487 16643 15739 2470 -2678 -3017 N +ATOM 3743 N GLY A 513 76.073 83.422 1.510 1.00128.93 N +ANISOU 3743 N GLY A 513 18453 16869 13665 4826 -2362 -3100 N +ATOM 3744 CA GLY A 513 76.767 83.309 2.761 1.00135.31 C +ANISOU 3744 CA GLY A 513 19790 17602 14021 5449 -2610 -3308 C +ATOM 3745 C GLY A 513 76.597 81.908 3.295 1.00133.10 C +ANISOU 3745 C GLY A 513 19748 17398 13425 5620 -2132 -3010 C +ATOM 3746 O GLY A 513 77.464 81.407 3.988 1.00135.48 O +ANISOU 3746 O GLY A 513 20407 17622 13448 5952 -2344 -3163 O +ATOM 3747 N THR A 514 75.478 81.270 2.971 1.00130.00 N +ANISOU 3747 N THR A 514 19139 17128 13128 5402 -1499 -2584 N +ATOM 3748 CA THR A 514 75.252 79.899 3.409 1.00136.05 C +ANISOU 3748 CA THR A 514 20053 17932 13707 5525 -990 -2248 C +ATOM 3749 C THR A 514 76.125 78.980 2.571 1.00136.91 C +ANISOU 3749 C THR A 514 19914 17993 14111 4991 -1151 -2279 C +ATOM 3750 O THR A 514 76.451 77.859 2.971 1.00136.85 O +ANISOU 3750 O THR A 514 20093 17981 13923 5102 -944 -2139 O +ATOM 3751 CB THR A 514 73.784 79.475 3.234 1.00141.83 C +ANISOU 3751 CB THR A 514 20522 18734 14631 5408 -287 -1768 C +ATOM 3752 OG1 THR A 514 73.591 78.921 1.927 1.00142.93 O +ANISOU 3752 OG1 THR A 514 20113 18858 15336 4676 -233 -1640 O +ATOM 3753 CG2 THR A 514 72.861 80.659 3.413 1.00145.09 C +ANISOU 3753 CG2 THR A 514 20916 19192 15018 5620 -214 -1761 C +ATOM 3754 N ILE A 515 76.491 79.473 1.394 1.00129.08 N +ANISOU 3754 N ILE A 515 18518 16960 13565 4442 -1494 -2442 N +ATOM 3755 CA ILE A 515 77.327 78.735 0.468 1.00119.39 C +ANISOU 3755 CA ILE A 515 17053 15677 12633 3951 -1657 -2465 C +ATOM 3756 C ILE A 515 78.787 78.796 0.895 1.00127.05 C +ANISOU 3756 C ILE A 515 18275 16524 13475 4143 -2161 -2798 C +ATOM 3757 O ILE A 515 79.482 77.778 0.906 1.00128.44 O +ANISOU 3757 O ILE A 515 18530 16671 13600 4065 -2153 -2760 O +ATOM 3758 CB ILE A 515 77.220 79.308 -0.945 1.00110.42 C +ANISOU 3758 CB ILE A 515 15452 14516 11987 3401 -1815 -2500 C +ATOM 3759 CG1 ILE A 515 75.801 79.150 -1.481 1.00109.39 C +ANISOU 3759 CG1 ILE A 515 15038 14466 12060 3177 -1388 -2203 C +ATOM 3760 CG2 ILE A 515 78.168 78.587 -1.861 1.00112.80 C +ANISOU 3760 CG2 ILE A 515 15581 14743 12533 2997 -1979 -2516 C +ATOM 3761 CD1 ILE A 515 75.570 79.879 -2.780 1.00110.01 C +ANISOU 3761 CD1 ILE A 515 14740 14519 12538 2759 -1561 -2268 C +ATOM 3762 N GLU A 516 79.240 79.996 1.247 1.00122.76 N +ANISOU 3762 N GLU A 516 17837 15878 12927 4400 -2627 -3132 N +ATOM 3763 CA GLU A 516 80.636 80.218 1.589 1.00124.18 C +ANISOU 3763 CA GLU A 516 18172 15860 13149 4571 -3208 -3493 C +ATOM 3764 C GLU A 516 81.099 79.274 2.681 1.00126.09 C +ANISOU 3764 C GLU A 516 18894 16095 12918 5029 -3183 -3522 C +ATOM 3765 O GLU A 516 82.117 78.595 2.539 1.00116.84 O +ANISOU 3765 O GLU A 516 17721 14825 11848 4893 -3381 -3605 O +ATOM 3766 CB GLU A 516 80.863 81.656 2.046 1.00135.21 C +ANISOU 3766 CB GLU A 516 19658 17112 14603 4907 -3722 -3854 C +ATOM 3767 CG GLU A 516 82.315 82.045 1.962 1.00146.41 C +ANISOU 3767 CG GLU A 516 20992 18238 16400 4885 -4381 -4215 C +ATOM 3768 CD GLU A 516 82.865 81.775 0.582 1.00151.28 C +ANISOU 3768 CD GLU A 516 21100 18789 17590 4220 -4329 -4073 C +ATOM 3769 OE1 GLU A 516 82.373 82.413 -0.367 1.00146.52 O +ANISOU 3769 OE1 GLU A 516 20133 18221 17316 3867 -4198 -3957 O +ATOM 3770 OE2 GLU A 516 83.763 80.917 0.441 1.00154.24 O +ANISOU 3770 OE2 GLU A 516 21471 19078 18055 4089 -4397 -4065 O +END diff --git a/examples/testdata/4IM2_missing_noid.pdb b/examples/testdata/4IM2_missing_noid.pdb new file mode 100644 index 0000000..5a5ef94 --- /dev/null +++ b/examples/testdata/4IM2_missing_noid.pdb @@ -0,0 +1,524 @@ +TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file) +ATOM 3510 N LEU A 468 76.337 90.332 -7.628 1.00168.53 N +ANISOU 3510 N LEU A 468 19760 15191 29082 5189 1248 -1702 N +ATOM 3511 CA LEU A 468 75.576 90.788 -6.476 1.00181.60 C +ANISOU 3511 CA LEU A 468 21073 16927 30998 5158 1421 -2051 C +ATOM 3512 C LEU A 468 76.285 91.971 -5.836 1.00196.57 C +ANISOU 3512 C LEU A 468 23029 18636 33021 5053 1667 -2229 C +ATOM 3513 O LEU A 468 75.727 93.067 -5.733 1.00197.97 O +ANISOU 3513 O LEU A 468 23115 18581 33523 5166 1662 -2304 O +ATOM 3514 CB LEU A 468 75.409 89.671 -5.449 1.00173.72 C +ANISOU 3514 CB LEU A 468 19829 16340 29836 4981 1593 -2304 C +ATOM 3515 CG LEU A 468 74.099 88.882 -5.420 1.00170.58 C +ANISOU 3515 CG LEU A 468 19142 16142 29529 5074 1449 -2345 C +ATOM 3516 CD1 LEU A 468 74.023 87.940 -6.581 1.00167.98 C +ANISOU 3516 CD1 LEU A 468 18951 15858 29015 5180 1156 -2025 C +ATOM 3517 CD2 LEU A 468 73.988 88.096 -4.145 1.00165.16 C +ANISOU 3517 CD2 LEU A 468 18217 15818 28720 4865 1706 -2656 C +ATOM 3518 N ASP A 469 77.529 91.753 -5.429 1.00208.80 N +ANISOU 3518 N ASP A 469 24731 20282 34322 4836 1875 -2296 N +ATOM 3519 CA ASP A 469 78.267 92.785 -4.720 1.00223.11 C +ANISOU 3519 CA ASP A 469 26577 21960 36233 4701 2123 -2500 C +ATOM 3520 C ASP A 469 78.653 93.973 -5.599 1.00231.96 C +ANISOU 3520 C ASP A 469 27954 22654 37525 4817 2037 -2283 C +ATOM 3521 O ASP A 469 78.718 95.100 -5.118 1.00235.71 O +ANISOU 3521 O ASP A 469 28377 22940 38242 4798 2175 -2449 O +ATOM 3522 CB ASP A 469 79.506 92.197 -4.057 1.00224.50 C +ANISOU 3522 CB ASP A 469 26841 22370 36089 4433 2350 -2633 C +ATOM 3523 CG ASP A 469 79.748 92.767 -2.679 1.00229.51 C +ANISOU 3523 CG ASP A 469 27303 23107 36794 4254 2637 -3018 C +ATOM 3524 OD1 ASP A 469 79.958 93.992 -2.564 1.00232.36 O +ANISOU 3524 OD1 ASP A 469 27695 23203 37387 4262 2718 -3093 O +ATOM 3525 OD2 ASP A 469 79.751 91.979 -1.709 1.00229.48 O +ANISOU 3525 OD2 ASP A 469 27145 23450 36598 4098 2779 -3242 O +ATOM 3526 N PHE A 470 78.904 93.735 -6.882 1.00233.88 N +ANISOU 3526 N PHE A 470 28481 22742 37641 4931 1813 -1912 N +ATOM 3527 CA PHE A 470 79.292 94.831 -7.766 1.00237.73 C +ANISOU 3527 CA PHE A 470 29252 22819 38256 5033 1733 -1677 C +ATOM 3528 C PHE A 470 78.103 95.470 -8.467 1.00232.15 C +ANISOU 3528 C PHE A 470 28512 21868 37828 5322 1470 -1512 C +ATOM 3529 O PHE A 470 78.021 96.691 -8.532 1.00230.69 O +ANISOU 3529 O PHE A 470 28371 21372 37909 5402 1493 -1517 O +ATOM 3530 CB PHE A 470 80.344 94.379 -8.784 1.00242.99 C +ANISOU 3530 CB PHE A 470 30297 23410 38616 4976 1661 -1357 C +ATOM 3531 CG PHE A 470 80.663 95.388 -9.839 1.00251.53 C +ANISOU 3531 CG PHE A 470 31709 24074 39788 5089 1550 -1064 C +ATOM 3532 CD1 PHE A 470 81.658 96.315 -9.620 1.00252.90 C +ANISOU 3532 CD1 PHE A 470 32021 24036 40032 4942 1771 -1133 C +ATOM 3533 CD2 PHE A 470 80.005 95.389 -11.059 1.00255.02 C +ANISOU 3533 CD2 PHE A 470 32335 24339 40221 5330 1225 -715 C +ATOM 3534 CE1 PHE A 470 81.981 97.242 -10.575 1.00254.75 C +ANISOU 3534 CE1 PHE A 470 32569 23879 40344 5028 1688 -862 C +ATOM 3535 CE2 PHE A 470 80.321 96.320 -12.027 1.00256.76 C +ANISOU 3535 CE2 PHE A 470 32894 24173 40491 5427 1126 -433 C +ATOM 3536 CZ PHE A 470 81.313 97.248 -11.784 1.00256.57 C +ANISOU 3536 CZ PHE A 470 33006 23929 40550 5272 1365 -504 C +ATOM 3537 N CYS A 471 77.190 94.665 -8.997 1.00176.88 N +ANISOU 3537 N CYS A 471 20955 21812 24441 2225 -3821 -3711 N +ATOM 3538 CA CYS A 471 76.124 95.233 -9.815 1.00176.41 C +ANISOU 3538 CA CYS A 471 20820 21906 24301 2124 -3576 -3614 C +ATOM 3539 C CYS A 471 74.868 95.631 -9.050 1.00176.82 C +ANISOU 3539 C CYS A 471 21026 22206 23952 2247 -3588 -3734 C +ATOM 3540 O CYS A 471 74.632 96.811 -8.854 1.00178.66 O +ANISOU 3540 O CYS A 471 21175 22393 24314 2353 -3749 -3873 O +ATOM 3541 CB CYS A 471 75.805 94.346 -11.019 1.00173.95 C +ANISOU 3541 CB CYS A 471 20521 21694 23877 1925 -3217 -3359 C +ATOM 3542 SG CYS A 471 76.954 94.571 -12.398 1.00273.04 S +ANISOU 3542 SG CYS A 471 32850 33934 36957 1863 -3075 -3146 S +ATOM 3543 N ILE A 472 74.068 94.670 -8.603 1.00173.50 N +ANISOU 3543 N ILE A 472 20813 22023 23085 2253 -3402 -3662 N +ATOM 3544 CA ILE A 472 72.771 95.033 -8.022 1.00171.09 C +ANISOU 3544 CA ILE A 472 20616 21936 22453 2374 -3307 -3694 C +ATOM 3545 C ILE A 472 72.832 96.022 -6.874 1.00177.82 C +ANISOU 3545 C ILE A 472 21591 22750 23222 2698 -3611 -3931 C +ATOM 3546 O ILE A 472 71.992 96.914 -6.776 1.00182.92 O +ANISOU 3546 O ILE A 472 22220 23491 23792 2778 -3598 -3985 O +ATOM 3547 CB ILE A 472 71.979 93.843 -7.518 1.00159.41 C +ANISOU 3547 CB ILE A 472 19318 20653 20599 2393 -3038 -3546 C +ATOM 3548 CG1 ILE A 472 70.708 93.667 -8.341 1.00147.27 C +ANISOU 3548 CG1 ILE A 472 17653 19253 19051 2196 -2745 -3384 C +ATOM 3549 CG2 ILE A 472 71.526 94.090 -6.105 1.00155.95 C +ANISOU 3549 CG2 ILE A 472 19129 20312 19812 2752 -3085 -3637 C +ATOM 3550 CD1 ILE A 472 70.927 92.915 -9.606 1.00135.92 C +ANISOU 3550 CD1 ILE A 472 16097 17752 17794 1929 -2643 -3254 C +ATOM 3551 N ARG A 473 73.812 95.865 -5.996 1.00180.33 N +ANISOU 3551 N ARG A 473 22055 22917 23544 2920 -3920 -4092 N +ATOM 3552 CA ARG A 473 73.860 96.762 -4.877 1.00189.65 C +ANISOU 3552 CA ARG A 473 23415 24034 24610 3307 -4283 -4357 C +ATOM 3553 C ARG A 473 74.328 98.021 -5.558 1.00185.98 C +ANISOU 3553 C ARG A 473 22628 23344 24692 3195 -4530 -4477 C +ATOM 3554 O ARG A 473 73.519 98.885 -5.866 1.00181.76 O +ANISOU 3554 O ARG A 473 22002 22904 24153 3165 -4446 -4474 O +ATOM 3555 CB ARG A 473 74.803 96.287 -3.768 1.00205.24 C +ANISOU 3555 CB ARG A 473 25661 25862 26460 3635 -4629 -4545 C +ATOM 3556 CG ARG A 473 74.468 96.921 -2.433 1.00220.50 C +ANISOU 3556 CG ARG A 473 27955 27814 28011 4171 -4923 -4787 C +ATOM 3557 CD ARG A 473 75.337 96.433 -1.295 1.00232.58 C +ANISOU 3557 CD ARG A 473 29837 29192 29341 4591 -5300 -5003 C +ATOM 3558 NE ARG A 473 76.763 96.602 -1.549 1.00237.46 N +ANISOU 3558 NE ARG A 473 30220 29440 30564 4489 -5773 -5205 N +ATOM 3559 CZ ARG A 473 77.716 95.991 -0.861 1.00240.32 C +ANISOU 3559 CZ ARG A 473 30786 29623 30903 4725 -6098 -5371 C +ATOM 3560 NH1 ARG A 473 77.388 95.172 0.115 1.00241.12 N +ANISOU 3560 NH1 ARG A 473 31370 29900 30344 5100 -5978 -5355 N +ATOM 3561 NH2 ARG A 473 78.988 96.195 -1.159 1.00241.54 N +ANISOU 3561 NH2 ARG A 473 30651 29398 31724 4605 -6518 -5533 N +ATOM 3562 N ASN A 474 75.608 98.073 -5.901 1.00188.74 N +ANISOU 3562 N ASN A 474 22768 23381 25563 3107 -4772 -4534 N +ATOM 3563 CA ASN A 474 76.168 99.264 -6.526 1.00188.61 C +ANISOU 3563 CA ASN A 474 22395 23075 26194 3026 -4977 -4605 C +ATOM 3564 C ASN A 474 75.420 99.892 -7.729 1.00173.98 C +ANISOU 3564 C ASN A 474 20312 21326 24467 2781 -4623 -4414 C +ATOM 3565 O ASN A 474 75.482 101.107 -7.891 1.00176.08 O +ANISOU 3565 O ASN A 474 20374 21426 25104 2827 -4803 -4518 O +ATOM 3566 CB ASN A 474 77.650 99.066 -6.857 1.00199.45 C +ANISOU 3566 CB ASN A 474 23514 24060 28207 2939 -5170 -4595 C +ATOM 3567 CG ASN A 474 78.504 98.809 -5.625 1.00210.23 C +ANISOU 3567 CG ASN A 474 25062 25219 29597 3243 -5689 -4883 C +ATOM 3568 OD1 ASN A 474 78.174 99.240 -4.527 1.00215.26 O +ANISOU 3568 OD1 ASN A 474 25969 25891 29928 3596 -6043 -5160 O +ATOM 3569 ND2 ASN A 474 79.613 98.103 -5.810 1.00212.07 N +ANISOU 3569 ND2 ASN A 474 25176 25222 30179 3148 -5748 -4822 N +ATOM 3570 N ILE A 475 74.722 99.114 -8.562 1.00161.86 N +ANISOU 3570 N ILE A 475 18813 20033 22652 2556 -4165 -4158 N +ATOM 3571 CA ILE A 475 74.022 99.727 -9.709 1.00154.84 C +ANISOU 3571 CA ILE A 475 17755 19216 21861 2390 -3885 -4015 C +ATOM 3572 C ILE A 475 72.785 100.520 -9.312 1.00159.27 C +ANISOU 3572 C ILE A 475 18401 19995 22121 2490 -3891 -4125 C +ATOM 3573 O ILE A 475 72.662 101.687 -9.663 1.00162.60 O +ANISOU 3573 O ILE A 475 18651 20327 22804 2505 -3962 -4186 O +ATOM 3574 CB ILE A 475 73.600 98.727 -10.818 1.00214.93 C +ANISOU 3574 CB ILE A 475 25397 26975 29293 2173 -3475 -3753 C +ATOM 3575 CG1 ILE A 475 74.808 98.227 -11.613 1.00218.74 C +ANISOU 3575 CG1 ILE A 475 25753 27211 30145 2083 -3390 -3585 C +ATOM 3576 CG2 ILE A 475 72.618 99.379 -11.789 1.00210.37 C +ANISOU 3576 CG2 ILE A 475 24743 26509 28681 2097 -3256 -3677 C +ATOM 3577 CD1 ILE A 475 74.446 97.201 -12.664 1.00218.15 C +ANISOU 3577 CD1 ILE A 475 25777 27260 29850 1946 -3056 -3359 C +ATOM 3578 N GLU A 476 71.856 99.893 -8.600 1.00156.45 N +ANISOU 3578 N GLU A 476 18293 19907 21245 2571 -3778 -4120 N +ATOM 3579 CA GLU A 476 70.623 100.594 -8.252 1.00142.72 C +ANISOU 3579 CA GLU A 476 16627 18370 19231 2677 -3720 -4176 C +ATOM 3580 C GLU A 476 70.845 101.560 -7.094 1.00144.41 C +ANISOU 3580 C GLU A 476 16959 18500 19412 3012 -4114 -4440 C +ATOM 3581 O GLU A 476 70.012 102.417 -6.811 1.00142.58 O +ANISOU 3581 O GLU A 476 16768 18380 19024 3141 -4136 -4517 O +ATOM 3582 CB GLU A 476 69.486 99.616 -7.958 1.00128.68 C +ANISOU 3582 CB GLU A 476 15020 16860 17012 2665 -3395 -4018 C +ATOM 3583 CG GLU A 476 69.562 98.905 -6.628 1.00128.73 C +ANISOU 3583 CG GLU A 476 15321 16930 16662 2941 -3433 -4041 C +ATOM 3584 CD GLU A 476 68.465 97.866 -6.484 1.00133.35 C +ANISOU 3584 CD GLU A 476 15992 17719 16955 2900 -3026 -3806 C +ATOM 3585 OE1 GLU A 476 68.285 97.061 -7.422 1.00132.30 O +ANISOU 3585 OE1 GLU A 476 15710 17598 16962 2603 -2816 -3643 O +ATOM 3586 OE2 GLU A 476 67.768 97.860 -5.448 1.00136.37 O +ANISOU 3586 OE2 GLU A 476 16588 18223 17003 3196 -2912 -3773 O +ATOM 3587 N LYS A 477 71.990 101.424 -6.439 1.00148.46 N +ANISOU 3587 N LYS A 477 17534 18788 20087 3179 -4467 -4596 N +ATOM 3588 CA LYS A 477 72.399 102.365 -5.405 1.00154.25 C +ANISOU 3588 CA LYS A 477 18378 19348 20882 3544 -4976 -4907 C +ATOM 3589 C LYS A 477 72.634 103.732 -5.994 1.00159.76 C +ANISOU 3589 C LYS A 477 18754 19833 22117 3467 -5183 -5014 C +ATOM 3590 O LYS A 477 72.568 104.742 -5.292 1.00158.01 O +ANISOU 3590 O LYS A 477 18598 19516 21921 3749 -5568 -5266 O +ATOM 3591 CB LYS A 477 73.667 101.883 -4.706 1.00154.03 C +ANISOU 3591 CB LYS A 477 18446 19057 21022 3730 -5372 -5076 C +ATOM 3592 CG LYS A 477 73.367 100.787 -3.750 1.00149.76 C +ANISOU 3592 CG LYS A 477 18324 18717 19861 3975 -5258 -5042 C +ATOM 3593 CD LYS A 477 74.437 100.554 -2.740 1.00143.39 C +ANISOU 3593 CD LYS A 477 17737 17664 19082 4327 -5762 -5306 C +ATOM 3594 CE LYS A 477 73.739 100.087 -1.488 1.00145.72 C +ANISOU 3594 CE LYS A 477 18569 18186 18613 4805 -5697 -5337 C +ATOM 3595 NZ LYS A 477 74.661 99.556 -0.469 1.00149.42 N +ANISOU 3595 NZ LYS A 477 19366 18470 18936 5206 -6108 -5561 N +ATOM 3596 N THR A 478 72.908 103.757 -7.293 1.00166.45 N +ANISOU 3596 N THR A 478 19271 20589 23384 3124 -4918 -4810 N +ATOM 3597 CA THR A 478 73.186 105.012 -7.968 1.00170.99 C +ANISOU 3597 CA THR A 478 19509 20929 24531 3052 -5023 -4844 C +ATOM 3598 C THR A 478 71.905 105.733 -8.391 1.00172.33 C +ANISOU 3598 C THR A 478 19686 21358 24435 2999 -4780 -4796 C +ATOM 3599 O THR A 478 71.021 105.170 -9.046 1.00163.10 O +ANISOU 3599 O THR A 478 18581 20461 22928 2823 -4356 -4594 O +ATOM 3600 CB THR A 478 74.217 104.856 -9.128 1.00146.93 C +ANISOU 3600 CB THR A 478 16115 17589 22125 2815 -4843 -4626 C +ATOM 3601 OG1 THR A 478 74.873 106.106 -9.369 1.00147.15 O +ANISOU 3601 OG1 THR A 478 15790 17239 22881 2857 -5085 -4705 O +ATOM 3602 CG2 THR A 478 73.562 104.391 -10.425 1.00144.32 C +ANISOU 3602 CG2 THR A 478 15764 17473 21597 2570 -4282 -4318 C +ATOM 3603 N VAL A 479 71.809 106.979 -7.944 1.00177.73 N +ANISOU 3603 N VAL A 479 20309 21929 25291 3181 -5110 -5014 N +ATOM 3604 CA VAL A 479 70.674 107.838 -8.218 1.00175.65 C +ANISOU 3604 CA VAL A 479 20044 21875 24819 3171 -4959 -5013 C +ATOM 3605 C VAL A 479 71.176 109.077 -8.939 1.00177.67 C +ANISOU 3605 C VAL A 479 19928 21830 25749 3101 -5069 -5035 C +ATOM 3606 O VAL A 479 72.353 109.417 -8.840 1.00179.02 O +ANISOU 3606 O VAL A 479 19865 21600 26555 3150 -5387 -5121 O +ATOM 3607 CB VAL A 479 69.983 108.266 -6.909 1.00168.37 C +ANISOU 3607 CB VAL A 479 19442 21113 23418 3524 -5243 -5249 C +ATOM 3608 CG1 VAL A 479 69.008 109.403 -7.169 1.00162.23 C +ANISOU 3608 CG1 VAL A 479 18603 20470 22565 3531 -5176 -5285 C +ATOM 3609 CG2 VAL A 479 69.288 107.080 -6.256 1.00163.89 C +ANISOU 3609 CG2 VAL A 479 19236 20856 22180 3624 -4991 -5142 C +ATOM 3610 N MET A 486 57.931 103.433 -6.150 1.00 92.00 N +ANISOU 3610 N MET A 486 10154 13425 11375 3371 -1523 -3283 N +ATOM 3611 CA MET A 486 56.824 104.104 -5.482 1.00110.61 C +ANISOU 3611 CA MET A 486 12558 15882 13585 3644 -1287 -3161 C +ATOM 3612 C MET A 486 56.182 105.150 -6.389 1.00111.38 C +ANISOU 3612 C MET A 486 12428 16016 13877 3424 -1416 -3308 C +ATOM 3613 O MET A 486 56.000 106.305 -6.002 1.00120.35 O +ANISOU 3613 O MET A 486 13691 17243 14794 3639 -1526 -3430 O +ATOM 3614 CB MET A 486 57.288 104.743 -4.170 1.00120.60 C +ANISOU 3614 CB MET A 486 14253 17221 14347 4174 -1395 -3243 C +ATOM 3615 CG MET A 486 58.405 105.768 -4.316 1.00126.87 C +ANISOU 3615 CG MET A 486 15171 17987 15047 4196 -1944 -3629 C +ATOM 3616 SD MET A 486 58.150 107.169 -3.210 1.00146.78 S +ANISOU 3616 SD MET A 486 18044 20597 17128 4757 -2124 -3782 S +ATOM 3617 CE MET A 486 58.003 106.326 -1.640 1.00102.35 C +ANISOU 3617 CE MET A 486 12883 15002 11003 5391 -1797 -3524 C +ATOM 3618 N GLY A 496 57.154 99.412 -2.065 1.00157.62 N +ANISOU 3618 N GLY A 496 19150 21656 19083 4616 82 -2024 N +ATOM 3619 CA GLY A 496 57.031 99.217 -3.498 1.00158.07 C +ANISOU 3619 CA GLY A 496 18749 21636 19677 3991 -116 -2141 C +ATOM 3620 C GLY A 496 57.664 97.914 -3.942 1.00163.71 C +ANISOU 3620 C GLY A 496 19349 22235 20619 3709 -140 -2093 C +ATOM 3621 O GLY A 496 58.040 97.090 -3.111 1.00167.17 O +ANISOU 3621 O GLY A 496 20009 22652 20858 3970 79 -1915 O +ATOM 3622 N GLU A 497 57.778 97.722 -5.254 1.00166.67 N +ANISOU 3622 N GLU A 497 19413 22530 21383 3222 -403 -2250 N +ATOM 3623 CA GLU A 497 58.431 96.534 -5.792 1.00170.73 C +ANISOU 3623 CA GLU A 497 19840 22933 22098 2955 -485 -2239 C +ATOM 3624 C GLU A 497 59.931 96.621 -5.556 1.00172.64 C +ANISOU 3624 C GLU A 497 20403 23228 21965 3043 -809 -2472 C +ATOM 3625 O GLU A 497 60.589 95.609 -5.311 1.00173.01 O +ANISOU 3625 O GLU A 497 20547 23223 21965 3047 -764 -2395 O +ATOM 3626 CB GLU A 497 58.173 96.394 -7.290 1.00169.62 C +ANISOU 3626 CB GLU A 497 19361 22681 22408 2505 -727 -2374 C +ATOM 3627 CG GLU A 497 56.882 97.012 -7.777 1.00173.11 C +ANISOU 3627 CG GLU A 497 19518 23086 23171 2413 -663 -2350 C +ATOM 3628 CD GLU A 497 56.703 96.840 -9.270 1.00173.61 C +ANISOU 3628 CD GLU A 497 19329 23013 23621 2054 -974 -2531 C +ATOM 3629 OE1 GLU A 497 57.597 96.241 -9.908 1.00170.78 O +ANISOU 3629 OE1 GLU A 497 19040 22600 23250 1901 -1202 -2647 O +ATOM 3630 OE2 GLU A 497 55.672 97.300 -9.805 1.00174.73 O +ANISOU 3630 OE2 GLU A 497 19233 23093 24064 1967 -999 -2559 O +ATOM 3631 N ILE A 498 60.466 97.836 -5.652 1.00171.44 N +ANISOU 3631 N ILE A 498 20381 23149 21608 3107 -1147 -2757 N +ATOM 3632 CA ILE A 498 61.883 98.078 -5.403 1.00167.93 C +ANISOU 3632 CA ILE A 498 20186 22695 20926 3210 -1503 -2995 C +ATOM 3633 C ILE A 498 62.251 97.620 -4.004 1.00173.82 C +ANISOU 3633 C ILE A 498 21298 23465 21280 3659 -1379 -2903 C +ATOM 3634 O ILE A 498 63.315 97.034 -3.789 1.00168.12 O +ANISOU 3634 O ILE A 498 20732 22684 20462 3692 -1544 -2980 O +ATOM 3635 CB ILE A 498 62.227 99.564 -5.520 1.00165.53 C +ANISOU 3635 CB ILE A 498 19934 22420 20540 3287 -1855 -3283 C +ATOM 3636 CG1 ILE A 498 61.848 100.100 -6.901 1.00171.37 C +ANISOU 3636 CG1 ILE A 498 20360 23137 21618 2911 -1947 -3365 C +ATOM 3637 CG2 ILE A 498 63.706 99.798 -5.239 1.00153.61 C +ANISOU 3637 CG2 ILE A 498 18613 20820 18931 3398 -2256 -3525 C +ATOM 3638 CD1 ILE A 498 61.891 101.605 -6.996 1.00174.73 C +ANISOU 3638 CD1 ILE A 498 20793 23594 22004 2996 -2195 -3587 C +ATOM 3639 N SER A 499 61.362 97.890 -3.054 1.00187.32 N +ANISOU 3639 N SER A 499 23169 25252 22753 4049 -1074 -2727 N +ATOM 3640 CA SER A 499 61.558 97.444 -1.683 1.00198.47 C +ANISOU 3640 CA SER A 499 24999 26682 23729 4594 -880 -2593 C +ATOM 3641 C SER A 499 61.611 95.926 -1.651 1.00206.95 C +ANISOU 3641 C SER A 499 26003 27687 24943 4481 -548 -2315 C +ATOM 3642 O SER A 499 62.302 95.334 -0.823 1.00211.11 O +ANISOU 3642 O SER A 499 26867 28195 25151 4806 -533 -2293 O +ATOM 3643 CB SER A 499 60.435 97.952 -0.780 1.00200.16 C +ANISOU 3643 CB SER A 499 25385 26976 23690 5064 -498 -2368 C +ATOM 3644 OG SER A 499 60.635 97.541 0.556 1.00203.12 O +ANISOU 3644 OG SER A 499 26244 27359 23574 5697 -286 -2224 O +ATOM 3645 N ASP A 500 60.877 95.300 -2.564 1.00209.43 N +ANISOU 3645 N ASP A 500 25883 27938 25751 4040 -320 -2123 N +ATOM 3646 CA ASP A 500 60.862 93.851 -2.655 1.00212.36 C +ANISOU 3646 CA ASP A 500 26120 28207 26361 3883 -39 -1865 C +ATOM 3647 C ASP A 500 62.097 93.307 -3.366 1.00203.21 C +ANISOU 3647 C ASP A 500 24946 26999 25265 3557 -426 -2093 C +ATOM 3648 O ASP A 500 62.511 92.195 -3.092 1.00204.96 O +ANISOU 3648 O ASP A 500 25238 27165 25472 3573 -286 -1954 O +ATOM 3649 CB ASP A 500 59.580 93.355 -3.335 1.00221.23 C +ANISOU 3649 CB ASP A 500 26765 29217 28075 3573 287 -1593 C +ATOM 3650 CG ASP A 500 58.346 93.583 -2.486 1.00233.55 C +ANISOU 3650 CG ASP A 500 28310 30773 29657 3938 816 -1243 C +ATOM 3651 OD1 ASP A 500 58.502 93.807 -1.272 1.00239.09 O +ANISOU 3651 OD1 ASP A 500 29432 31558 29852 4492 1029 -1137 O +ATOM 3652 OD2 ASP A 500 57.226 93.532 -3.034 1.00237.24 O +ANISOU 3652 OD2 ASP A 500 28355 31128 30656 3709 1011 -1072 O +ATOM 3653 N ILE A 501 62.692 94.094 -4.258 1.00192.67 N +ANISOU 3653 N ILE A 501 23525 25673 24008 3292 -875 -2413 N +ATOM 3654 CA ILE A 501 63.864 93.633 -5.007 1.00181.71 C +ANISOU 3654 CA ILE A 501 22108 24215 22719 3006 -1195 -2587 C +ATOM 3655 C ILE A 501 65.165 93.699 -4.196 1.00170.68 C +ANISOU 3655 C ILE A 501 21064 22814 20972 3287 -1450 -2764 C +ATOM 3656 O ILE A 501 65.940 92.735 -4.173 1.00164.70 O +ANISOU 3656 O ILE A 501 20376 21999 20202 3222 -1476 -2736 O +ATOM 3657 CB ILE A 501 64.023 94.385 -6.353 1.00138.03 C +ANISOU 3657 CB ILE A 501 16341 18649 17453 2657 -1507 -2802 C +ATOM 3658 CG1 ILE A 501 63.385 93.589 -7.491 1.00130.33 C +ANISOU 3658 CG1 ILE A 501 15061 17587 16872 2296 -1411 -2683 C +ATOM 3659 CG2 ILE A 501 65.491 94.642 -6.682 1.00137.98 C +ANISOU 3659 CG2 ILE A 501 16437 18581 17410 2596 -1883 -3037 C +ATOM 3660 CD1 ILE A 501 61.877 93.516 -7.426 1.00127.50 C +ANISOU 3660 CD1 ILE A 501 14480 17217 16748 2292 -1111 -2482 C +ATOM 3661 N HIS A 502 65.396 94.829 -3.532 1.00164.00 N +ANISOU 3661 N HIS A 502 20439 22007 19869 3613 -1676 -2964 N +ATOM 3662 CA HIS A 502 66.603 95.022 -2.737 1.00157.69 C +ANISOU 3662 CA HIS A 502 19968 21147 18800 3931 -2029 -3195 C +ATOM 3663 C HIS A 502 66.627 94.018 -1.594 1.00162.64 C +ANISOU 3663 C HIS A 502 20933 21795 19069 4322 -1761 -3012 C +ATOM 3664 O HIS A 502 67.677 93.496 -1.229 1.00164.35 O +ANISOU 3664 O HIS A 502 21348 21935 19163 4433 -1971 -3125 O +ATOM 3665 CB HIS A 502 66.654 96.452 -2.195 1.00150.83 C +ANISOU 3665 CB HIS A 502 19272 20282 17755 4264 -2351 -3452 C +ATOM 3666 CG HIS A 502 67.989 97.117 -2.348 1.00143.78 C +ANISOU 3666 CG HIS A 502 18387 19223 17019 4248 -2929 -3804 C +ATOM 3667 ND1 HIS A 502 68.672 97.155 -3.544 1.00137.00 N +ANISOU 3667 ND1 HIS A 502 17193 18253 16609 3785 -3096 -3872 N +ATOM 3668 CD2 HIS A 502 68.759 97.787 -1.457 1.00140.15 C +ANISOU 3668 CD2 HIS A 502 18217 18647 16387 4674 -3387 -4099 C +ATOM 3669 CE1 HIS A 502 69.807 97.814 -3.383 1.00131.33 C +ANISOU 3669 CE1 HIS A 502 16503 17343 16055 3893 -3583 -4155 C +ATOM 3670 NE2 HIS A 502 69.883 98.208 -2.125 1.00130.34 N +ANISOU 3670 NE2 HIS A 502 16741 17200 15583 4416 -3815 -4326 N +ATOM 3671 N THR A 503 65.450 93.751 -1.039 1.00163.37 N +ANISOU 3671 N THR A 503 21080 21971 19022 4552 -1268 -2705 N +ATOM 3672 CA THR A 503 65.295 92.771 0.033 1.00163.31 C +ANISOU 3672 CA THR A 503 21384 21972 18696 4974 -872 -2437 C +ATOM 3673 C THR A 503 65.393 91.327 -0.475 1.00151.49 C +ANISOU 3673 C THR A 503 19659 20415 17484 4610 -614 -2206 C +ATOM 3674 O THR A 503 65.955 90.464 0.198 1.00146.11 O +ANISOU 3674 O THR A 503 19247 19705 16563 4853 -520 -2130 O +ATOM 3675 CB THR A 503 63.956 92.972 0.783 1.00170.09 C +ANISOU 3675 CB THR A 503 22342 22899 19387 5379 -334 -2106 C +ATOM 3676 OG1 THR A 503 64.026 94.162 1.576 1.00176.61 O +ANISOU 3676 OG1 THR A 503 23551 23775 19778 5902 -585 -2325 O +ATOM 3677 CG2 THR A 503 63.645 91.790 1.693 1.00171.53 C +ANISOU 3677 CG2 THR A 503 22747 23054 19374 5760 235 -1707 C +ATOM 3678 N LYS A 504 64.865 91.071 -1.669 1.00141.41 N +ANISOU 3678 N LYS A 504 17911 19106 16711 4058 -541 -2117 N +ATOM 3679 CA LYS A 504 64.918 89.730 -2.251 1.00138.96 C +ANISOU 3679 CA LYS A 504 17368 18711 16719 3706 -369 -1930 C +ATOM 3680 C LYS A 504 66.335 89.382 -2.646 1.00142.04 C +ANISOU 3680 C LYS A 504 17848 19062 17058 3520 -779 -2178 C +ATOM 3681 O LYS A 504 66.762 88.230 -2.559 1.00134.46 O +ANISOU 3681 O LYS A 504 16927 18053 16108 3463 -666 -2057 O +ATOM 3682 CB LYS A 504 64.010 89.614 -3.477 1.00129.82 C +ANISOU 3682 CB LYS A 504 15721 17488 16116 3223 -303 -1839 C +ATOM 3683 CG LYS A 504 62.585 89.222 -3.164 1.00130.75 C +ANISOU 3683 CG LYS A 504 15616 17544 16518 3307 225 -1458 C +ATOM 3684 N LEU A 505 67.053 90.395 -3.100 1.00138.41 N +ANISOU 3684 N LEU A 505 17394 18602 16593 3427 -1237 -2505 N +ATOM 3685 CA LEU A 505 68.435 90.224 -3.458 1.00120.29 C +ANISOU 3685 CA LEU A 505 15154 16230 14322 3285 -1619 -2726 C +ATOM 3686 C LEU A 505 69.260 89.889 -2.223 1.00124.70 C +ANISOU 3686 C LEU A 505 16126 16770 14484 3724 -1710 -2800 C +ATOM 3687 O LEU A 505 70.166 89.052 -2.259 1.00124.02 O +ANISOU 3687 O LEU A 505 16106 16619 14396 3643 -1808 -2823 O +ATOM 3688 CB LEU A 505 68.966 91.499 -4.066 1.00109.42 C +ANISOU 3688 CB LEU A 505 13673 14807 13094 3171 -2036 -3016 C +ATOM 3689 CG LEU A 505 70.386 91.097 -4.404 1.00128.61 C +ANISOU 3689 CG LEU A 505 16120 17111 15635 3034 -2336 -3157 C +ATOM 3690 CD1 LEU A 505 70.509 91.048 -5.920 1.00141.22 C +ANISOU 3690 CD1 LEU A 505 17393 18648 17616 2580 -2370 -3131 C +ATOM 3691 CD2 LEU A 505 71.441 91.946 -3.655 1.00114.58 C +ANISOU 3691 CD2 LEU A 505 14554 15224 13758 3350 -2784 -3462 C +ATOM 3692 N LEU A 506 68.951 90.579 -1.132 1.00130.40 N +ANISOU 3692 N LEU A 506 17159 17539 14847 4233 -1705 -2854 N +ATOM 3693 CA LEU A 506 69.612 90.336 0.139 1.00131.63 C +ANISOU 3693 CA LEU A 506 17798 17665 14549 4786 -1814 -2947 C +ATOM 3694 C LEU A 506 69.501 88.865 0.507 1.00144.65 C +ANISOU 3694 C LEU A 506 19548 19330 16080 4841 -1380 -2638 C +ATOM 3695 O LEU A 506 70.448 88.287 1.024 1.00156.36 O +ANISOU 3695 O LEU A 506 21304 20754 17351 5038 -1550 -2741 O +ATOM 3696 CB LEU A 506 69.008 91.206 1.240 1.00120.17 C +ANISOU 3696 CB LEU A 506 16713 16270 12675 5409 -1772 -2980 C +ATOM 3697 N ARG A 507 68.351 88.260 0.214 1.00146.01 N +ANISOU 3697 N ARG A 507 19470 19552 16453 4658 -839 -2263 N +ATOM 3698 CA ARG A 507 68.159 86.831 0.443 1.00152.26 C +ANISOU 3698 CA ARG A 507 20261 20320 17271 4649 -394 -1930 C +ATOM 3699 C ARG A 507 69.164 86.004 -0.360 1.00145.14 C +ANISOU 3699 C ARG A 507 19199 19352 16597 4200 -653 -2042 C +ATOM 3700 O ARG A 507 69.471 84.873 0.007 1.00142.95 O +ANISOU 3700 O ARG A 507 19044 19045 16224 4273 -450 -1882 O +ATOM 3701 CB ARG A 507 66.724 86.401 0.111 1.00161.16 C +ANISOU 3701 CB ARG A 507 21023 21434 18777 4463 165 -1523 C +ATOM 3702 CG ARG A 507 65.661 86.975 1.046 1.00177.63 C +ANISOU 3702 CG ARG A 507 23283 23565 20645 4978 585 -1290 C +ATOM 3703 CD ARG A 507 64.263 86.468 0.696 1.00187.68 C +ANISOU 3703 CD ARG A 507 24111 24757 22442 4769 1148 -857 C +ATOM 3704 NE ARG A 507 63.229 87.082 1.527 1.00198.88 N +ANISOU 3704 NE ARG A 507 25661 26202 23704 5259 1588 -600 N +ATOM 3705 CZ ARG A 507 61.923 86.883 1.368 1.00205.71 C +ANISOU 3705 CZ ARG A 507 26137 26967 25058 5169 2095 -210 C +ATOM 3706 NH1 ARG A 507 61.484 86.084 0.406 1.00207.33 N +ANISOU 3706 NH1 ARG A 507 25797 27020 25959 4610 2159 -75 N +ATOM 3707 NH2 ARG A 507 61.055 87.485 2.171 1.00208.11 N +ANISOU 3707 NH2 ARG A 507 26596 27293 25185 5668 2517 41 N +ATOM 3708 N LEU A 508 69.681 86.579 -1.445 1.00134.19 N +ANISOU 3708 N LEU A 508 17555 17933 15496 3776 -1072 -2294 N +ATOM 3709 CA LEU A 508 70.654 85.888 -2.287 1.00125.06 C +ANISOU 3709 CA LEU A 508 16259 16704 14555 3385 -1304 -2382 C +ATOM 3710 C LEU A 508 72.070 85.983 -1.730 1.00133.75 C +ANISOU 3710 C LEU A 508 17660 17739 15419 3609 -1705 -2655 C +ATOM 3711 O LEU A 508 72.775 84.975 -1.650 1.00132.42 O +ANISOU 3711 O LEU A 508 17581 17530 15202 3562 -1700 -2615 O +ATOM 3712 CB LEU A 508 70.606 86.404 -3.726 1.00112.64 C +ANISOU 3712 CB LEU A 508 14312 15095 13392 2907 -1513 -2482 C +ATOM 3713 CG LEU A 508 69.271 86.186 -4.436 1.00113.17 C +ANISOU 3713 CG LEU A 508 14056 15174 13769 2653 -1215 -2260 C +ATOM 3714 CD1 LEU A 508 69.459 86.184 -5.945 1.00106.22 C +ANISOU 3714 CD1 LEU A 508 12898 14225 13237 2216 -1432 -2343 C +ATOM 3715 CD2 LEU A 508 68.613 84.894 -3.968 1.00117.32 C +ANISOU 3715 CD2 LEU A 508 14560 15678 14341 2703 -779 -1932 C +ATOM 3716 N SER A 509 72.491 87.188 -1.355 1.00130.72 N +ANISOU 3716 N SER A 509 17414 17317 14936 3856 -2085 -2944 N +ATOM 3717 CA SER A 509 73.767 87.347 -0.663 1.00136.66 C +ANISOU 3717 CA SER A 509 18457 17948 15519 4156 -2531 -3236 C +ATOM 3718 C SER A 509 73.698 86.583 0.646 1.00143.40 C +ANISOU 3718 C SER A 509 19773 18845 15866 4687 -2319 -3138 C +ATOM 3719 O SER A 509 74.680 85.977 1.082 1.00138.35 O +ANISOU 3719 O SER A 509 19358 18121 15090 4839 -2521 -3256 O +ATOM 3720 CB SER A 509 74.089 88.820 -0.410 1.00130.15 C +ANISOU 3720 CB SER A 509 17685 17028 14738 4382 -3008 -3572 C +ATOM 3721 OG SER A 509 74.991 89.319 -1.384 1.00125.27 O +ANISOU 3721 OG SER A 509 16739 16248 14609 4003 -3376 -3749 O +ATOM 3722 N SER A 510 72.520 86.615 1.263 1.00144.65 N +ANISOU 3722 N SER A 510 20078 19123 15761 4999 -1878 -2899 N +ATOM 3723 CA SER A 510 72.236 85.777 2.417 1.00148.97 C +ANISOU 3723 CA SER A 510 21044 19713 15846 5526 -1487 -2677 C +ATOM 3724 C SER A 510 72.424 84.315 2.046 1.00145.48 C +ANISOU 3724 C SER A 510 20455 19266 15554 5204 -1182 -2426 C +ATOM 3725 O SER A 510 73.001 83.552 2.811 1.00140.49 O +ANISOU 3725 O SER A 510 20177 18606 14598 5539 -1145 -2415 O +ATOM 3726 CB SER A 510 70.807 85.999 2.911 1.00149.05 C +ANISOU 3726 CB SER A 510 21111 19824 15699 5832 -930 -2348 C +ATOM 3727 OG SER A 510 70.346 84.882 3.643 1.00147.27 O +ANISOU 3727 OG SER A 510 21097 19617 15240 6154 -337 -1962 O +ATOM 3728 N SER A 511 71.946 83.946 0.858 1.00139.39 N +ANISOU 3728 N SER A 511 19184 18508 15269 4583 -1004 -2249 N +ATOM 3729 CA SER A 511 72.011 82.573 0.365 1.00129.68 C +ANISOU 3729 CA SER A 511 17763 17254 14255 4236 -745 -2013 C +ATOM 3730 C SER A 511 73.437 82.171 0.006 1.00129.30 C +ANISOU 3730 C SER A 511 17762 17135 14232 4035 -1175 -2258 C +ATOM 3731 O SER A 511 73.792 80.991 0.047 1.00109.17 O +ANISOU 3731 O SER A 511 15254 14565 11659 3957 -1019 -2119 O +ATOM 3732 CB SER A 511 71.108 82.416 -0.862 1.00125.40 C +ANISOU 3732 CB SER A 511 16701 16703 14243 3684 -564 -1828 C +ATOM 3733 OG SER A 511 71.167 81.106 -1.394 1.00137.08 O +ANISOU 3733 OG SER A 511 17990 18125 15969 3359 -392 -1635 O +ATOM 3734 N GLN A 512 74.247 83.164 -0.347 1.00131.12 N +ANISOU 3734 N GLN A 512 17958 17304 14560 3957 -1699 -2603 N +ATOM 3735 CA GLN A 512 75.621 82.941 -0.774 1.00120.52 C +ANISOU 3735 CA GLN A 512 16587 15845 13361 3755 -2110 -2821 C +ATOM 3736 C GLN A 512 76.508 82.796 0.431 1.00123.24 C +ANISOU 3736 C GLN A 512 17385 16120 13322 4264 -2359 -3023 C +ATOM 3737 O GLN A 512 77.569 82.174 0.385 1.00128.94 O +ANISOU 3737 O GLN A 512 18162 16749 14081 4188 -2573 -3124 O +ATOM 3738 CB GLN A 512 76.096 84.150 -1.546 1.00118.44 C +ANISOU 3738 CB GLN A 512 16077 15483 13440 3537 -2531 -3073 C +ATOM 3739 CG GLN A 512 76.798 83.822 -2.807 1.00125.91 C +ANISOU 3739 CG GLN A 512 16711 16343 14787 3048 -2644 -3057 C +ATOM 3740 CD GLN A 512 76.915 85.020 -3.690 1.00137.22 C +ANISOU 3740 CD GLN A 512 17859 17690 16589 2843 -2877 -3186 C +ATOM 3741 OE1 GLN A 512 77.456 86.052 -3.281 1.00153.03 O +ANISOU 3741 OE1 GLN A 512 19904 19568 18672 3053 -3245 -3442 O +ATOM 3742 NE2 GLN A 512 76.353 84.922 -4.897 1.00128.62 N +ANISOU 3742 NE2 GLN A 512 16487 16643 15739 2470 -2678 -3017 N +ATOM 3743 N GLY A 513 76.073 83.422 1.510 1.00128.93 N +ANISOU 3743 N GLY A 513 18453 16869 13665 4826 -2362 -3100 N +ATOM 3744 CA GLY A 513 76.767 83.309 2.761 1.00135.31 C +ANISOU 3744 CA GLY A 513 19790 17602 14021 5449 -2610 -3308 C +ATOM 3745 C GLY A 513 76.597 81.908 3.295 1.00133.10 C +ANISOU 3745 C GLY A 513 19748 17398 13425 5620 -2132 -3010 C +ATOM 3746 O GLY A 513 77.464 81.407 3.988 1.00135.48 O +ANISOU 3746 O GLY A 513 20407 17622 13448 5952 -2344 -3163 O +ATOM 3747 N THR A 514 75.478 81.270 2.971 1.00130.00 N +ANISOU 3747 N THR A 514 19139 17128 13128 5402 -1499 -2584 N +ATOM 3748 CA THR A 514 75.252 79.899 3.409 1.00136.05 C +ANISOU 3748 CA THR A 514 20053 17932 13707 5525 -990 -2248 C +ATOM 3749 C THR A 514 76.125 78.980 2.571 1.00136.91 C +ANISOU 3749 C THR A 514 19914 17993 14111 4991 -1151 -2279 C +ATOM 3750 O THR A 514 76.451 77.859 2.971 1.00136.85 O +ANISOU 3750 O THR A 514 20093 17981 13923 5102 -944 -2139 O +ATOM 3751 CB THR A 514 73.784 79.475 3.234 1.00141.83 C +ANISOU 3751 CB THR A 514 20522 18734 14631 5408 -287 -1768 C +ATOM 3752 OG1 THR A 514 73.591 78.921 1.927 1.00142.93 O +ANISOU 3752 OG1 THR A 514 20113 18858 15336 4676 -233 -1640 O +ATOM 3753 CG2 THR A 514 72.861 80.659 3.413 1.00145.09 C +ANISOU 3753 CG2 THR A 514 20916 19192 15018 5620 -214 -1761 C +ATOM 3754 N ILE A 515 76.491 79.473 1.394 1.00129.08 N +ANISOU 3754 N ILE A 515 18518 16960 13565 4442 -1494 -2442 N +ATOM 3755 CA ILE A 515 77.327 78.735 0.468 1.00119.39 C +ANISOU 3755 CA ILE A 515 17053 15677 12633 3951 -1657 -2465 C +ATOM 3756 C ILE A 515 78.787 78.796 0.895 1.00127.05 C +ANISOU 3756 C ILE A 515 18275 16524 13475 4143 -2161 -2798 C +ATOM 3757 O ILE A 515 79.482 77.778 0.906 1.00128.44 O +ANISOU 3757 O ILE A 515 18530 16671 13600 4065 -2153 -2760 O +ATOM 3758 CB ILE A 515 77.220 79.308 -0.945 1.00110.42 C +ANISOU 3758 CB ILE A 515 15452 14516 11987 3401 -1815 -2500 C +ATOM 3759 CG1 ILE A 515 75.801 79.150 -1.481 1.00109.39 C +ANISOU 3759 CG1 ILE A 515 15038 14466 12060 3177 -1388 -2203 C +ATOM 3760 CG2 ILE A 515 78.168 78.587 -1.861 1.00112.80 C +ANISOU 3760 CG2 ILE A 515 15581 14743 12533 2997 -1979 -2516 C +ATOM 3761 CD1 ILE A 515 75.570 79.879 -2.780 1.00110.01 C +ANISOU 3761 CD1 ILE A 515 14740 14519 12538 2759 -1561 -2268 C +ATOM 3762 N GLU A 516 79.240 79.996 1.247 1.00122.76 N +ANISOU 3762 N GLU A 516 17837 15878 12927 4400 -2627 -3132 N +ATOM 3763 CA GLU A 516 80.636 80.218 1.589 1.00124.18 C +ANISOU 3763 CA GLU A 516 18172 15860 13149 4571 -3208 -3493 C +ATOM 3764 C GLU A 516 81.099 79.274 2.681 1.00126.09 C +ANISOU 3764 C GLU A 516 18894 16095 12918 5029 -3183 -3522 C +ATOM 3765 O GLU A 516 82.117 78.595 2.539 1.00116.84 O +ANISOU 3765 O GLU A 516 17721 14825 11848 4893 -3381 -3605 O +ATOM 3766 CB GLU A 516 80.863 81.656 2.046 1.00135.21 C +ANISOU 3766 CB GLU A 516 19658 17112 14603 4907 -3722 -3854 C +ATOM 3767 CG GLU A 516 82.315 82.045 1.962 1.00146.41 C +ANISOU 3767 CG GLU A 516 20992 18238 16400 4885 -4381 -4215 C +ATOM 3768 CD GLU A 516 82.865 81.775 0.582 1.00151.28 C +ANISOU 3768 CD GLU A 516 21100 18789 17590 4220 -4329 -4073 C +ATOM 3769 OE1 GLU A 516 82.373 82.413 -0.367 1.00146.52 O +ANISOU 3769 OE1 GLU A 516 20133 18221 17316 3867 -4198 -3957 O +ATOM 3770 OE2 GLU A 516 83.763 80.917 0.441 1.00154.24 O +ANISOU 3770 OE2 GLU A 516 21471 19078 18055 4089 -4397 -4065 O +END diff --git a/examples/testdata/4IM2_nterm.pdb b/examples/testdata/4IM2_nterm.pdb new file mode 100644 index 0000000..48f7803 --- /dev/null +++ b/examples/testdata/4IM2_nterm.pdb @@ -0,0 +1,139 @@ +HEADER TRANSFERASE/TRANSFERASE INHIBITOR 01-JAN-13 4IM2 +TITLE STRUCTURE OF TANK-BINDING KINASE 1 (Truncated test file) +DBREF 4IM2 A 1 657 UNP Q9UHD2 TBK1_HUMAN 1 657 +SEQADV 4IM2 GLY A -5 UNP Q9UHD2 EXPRESSION TAG +SEQADV 4IM2 SER A -4 UNP Q9UHD2 EXPRESSION TAG +SEQADV 4IM2 GLY A -3 UNP Q9UHD2 EXPRESSION TAG +SEQADV 4IM2 SER A -2 UNP Q9UHD2 EXPRESSION TAG +SEQADV 4IM2 GLY A -1 UNP Q9UHD2 EXPRESSION TAG +SEQADV 4IM2 SER A 0 UNP Q9UHD2 EXPRESSION TAG +SEQRES 1 A 663 GLY SER GLY SER GLY SER MET GLN SER THR SER ASN HIS +ATOM 1 N GLY A -1 126.784 4.226 -23.353 1.00158.13 N +ANISOU 1 N GLY A -1 19370 17517 23197 6628 1162 2075 N +ATOM 2 CA GLY A -1 125.521 4.306 -24.062 1.00150.94 C +ANISOU 2 CA GLY A -1 18746 16231 22374 6153 1277 1996 C +ATOM 3 C GLY A -1 125.742 4.361 -25.557 1.00146.29 C +ANISOU 3 C GLY A -1 18187 15453 21943 5900 1405 1498 C +ATOM 4 O GLY A -1 126.691 4.980 -26.029 1.00150.85 O +ANISOU 4 O GLY A -1 18536 16366 22413 5906 1385 1160 O +ATOM 5 N SER A 0 124.869 3.710 -26.313 1.00137.36 N +ANISOU 5 N SER A 0 17328 13796 21068 5675 1550 1432 N +ATOM 6 CA SER A 0 125.052 3.672 -27.755 1.00139.44 C +ANISOU 6 CA SER A 0 17634 13884 21461 5464 1674 953 C +ATOM 7 C SER A 0 123.846 4.104 -28.574 1.00137.43 C +ANISOU 7 C SER A 0 17591 13478 21149 4975 1714 755 C +ATOM 8 O SER A 0 122.737 4.275 -28.071 1.00128.25 O +ANISOU 8 O SER A 0 16566 12244 19921 4780 1667 988 O +ATOM 9 CB SER A 0 125.578 2.312 -28.214 1.00155.09 C +ANISOU 9 CB SER A 0 19671 15395 23862 5752 1827 887 C +ATOM 10 OG SER A 0 126.993 2.281 -28.131 1.00164.59 O +ANISOU 10 OG SER A 0 20608 16866 25062 6113 1802 781 O +ATOM 11 N MET A 1 124.096 4.270 -29.861 1.00134.87 N +ANISOU 11 N MET A 1 17283 13123 20839 4799 1805 311 N +ATOM 12 CA MET A 1 123.214 5.039 -30.698 1.00125.22 C +ANISOU 12 CA MET A 1 16193 11958 19428 4369 1804 70 C +ATOM 13 C MET A 1 122.885 4.351 -32.006 1.00124.69 C +ANISOU 13 C MET A 1 16293 11510 19572 4225 1942 -293 C +ATOM 14 O MET A 1 123.723 3.686 -32.606 1.00129.61 O +ANISOU 14 O MET A 1 16868 11984 20394 4414 2057 -519 O +ATOM 15 CB MET A 1 123.867 6.392 -30.970 1.00122.51 C +ANISOU 15 CB MET A 1 15675 12140 18732 4254 1762 -132 C +ATOM 16 CG MET A 1 125.074 6.368 -31.866 1.00120.74 C +ANISOU 16 CG MET A 1 15318 12013 18544 4369 1884 -495 C +ATOM 17 SD MET A 1 125.834 7.982 -31.850 1.00196.33 S +ANISOU 17 SD MET A 1 24655 22193 27747 4246 1861 -642 S +ATOM 18 CE MET A 1 126.785 7.896 -30.345 1.00132.53 C +ANISOU 18 CE MET A 1 16264 14397 19693 4639 1728 -355 C +ATOM 19 N GLN A 2 121.643 4.496 -32.440 1.00123.78 N +ANISOU 19 N GLN A 2 16363 11253 19416 3898 1925 -369 N +ATOM 20 CA GLN A 2 121.313 4.161 -33.809 1.00128.51 C +ANISOU 20 CA GLN A 2 17093 11643 20094 3714 2020 -799 C +ATOM 21 C GLN A 2 121.639 5.396 -34.617 1.00121.06 C +ANISOU 21 C GLN A 2 16105 11138 18752 3541 2004 -1065 C +ATOM 22 O GLN A 2 121.959 6.442 -34.059 1.00107.32 O +ANISOU 22 O GLN A 2 14247 9790 16739 3528 1928 -906 O +ATOM 23 CB GLN A 2 119.832 3.845 -33.965 1.00136.11 C +ANISOU 23 CB GLN A 2 18240 12314 21161 3439 1994 -809 C +ATOM 24 CG GLN A 2 119.171 3.277 -32.740 1.00148.45 C +ANISOU 24 CG GLN A 2 19841 13613 22949 3500 1973 -376 C +ATOM 25 CD GLN A 2 117.773 2.799 -33.042 1.00158.28 C +ANISOU 25 CD GLN A 2 21243 14511 24385 3221 1993 -473 C +ATOM 26 OE1 GLN A 2 116.827 3.097 -32.313 1.00163.28 O +ANISOU 26 OE1 GLN A 2 21915 15160 24966 3070 1921 -211 O +ATOM 27 NE2 GLN A 2 117.631 2.057 -34.134 1.00155.02 N +ANISOU 27 NE2 GLN A 2 20902 13797 24200 3144 2095 -885 N +ATOM 28 N SER A 3 121.547 5.280 -35.931 1.00124.66 N +ANISOU 28 N SER A 3 16661 11530 19175 3410 2090 -1474 N +ATOM 29 CA SER A 3 121.742 6.432 -36.781 1.00120.35 C +ANISOU 29 CA SER A 3 16121 11369 18236 3242 2107 -1703 C +ATOM 30 C SER A 3 121.190 6.186 -38.161 1.00125.27 C +ANISOU 30 C SER A 3 16914 11882 18801 3073 2165 -2108 C +ATOM 31 O SER A 3 120.746 5.090 -38.489 1.00135.86 O +ANISOU 31 O SER A 3 18337 12848 20436 3082 2197 -2268 O +ATOM 32 CB SER A 3 123.217 6.751 -36.923 1.00116.70 C +ANISOU 32 CB SER A 3 15475 11153 17711 3435 2220 -1807 C +ATOM 33 OG SER A 3 123.770 5.974 -37.974 1.00112.78 O +ANISOU 33 OG SER A 3 15005 10478 17367 3528 2375 -2175 O +ATOM 34 N THR A 4 121.244 7.232 -38.972 1.00116.48 N +ANISOU 34 N THR A 4 15849 11109 17301 2928 2191 -2281 N +ATOM 35 CA THR A 4 120.978 7.130 -40.394 1.00113.12 C +ANISOU 35 CA THR A 4 15568 10691 16723 2823 2262 -2692 C +ATOM 36 C THR A 4 122.118 7.839 -41.119 1.00116.32 C +ANISOU 36 C THR A 4 15918 11410 16867 2884 2432 -2867 C +ATOM 37 O THR A 4 123.106 8.236 -40.495 1.00117.17 O +ANISOU 37 O THR A 4 15851 11671 16998 3007 2493 -2706 O +ATOM 38 CB THR A 4 119.615 7.756 -40.775 1.00106.20 C +ANISOU 38 CB THR A 4 14854 9927 15568 2568 2121 -2713 C +ATOM 39 OG1 THR A 4 119.774 9.154 -41.043 1.00107.14 O +ANISOU 39 OG1 THR A 4 15001 10451 15258 2480 2138 -2644 O +ATOM 40 CG2 THR A 4 118.597 7.567 -39.657 1.00 99.42 C +ANISOU 40 CG2 THR A 4 13990 8889 14896 2483 1956 -2396 C +ATOM 41 N SER A 5 121.981 7.982 -42.432 1.00116.70 N +ANISOU 41 N SER A 5 16106 11564 16670 2803 2517 -3210 N +ATOM 42 CA SER A 5 122.975 8.671 -43.247 1.00122.60 C +ANISOU 42 CA SER A 5 16837 12604 17144 2839 2721 -3385 C +ATOM 43 C SER A 5 123.317 10.064 -42.713 1.00128.43 C +ANISOU 43 C SER A 5 17501 13666 17630 2768 2748 -3105 C +ATOM 44 O SER A 5 124.481 10.467 -42.712 1.00133.01 O +ANISOU 44 O SER A 5 17934 14410 18193 2852 2925 -3133 O +ATOM 45 CB SER A 5 122.473 8.779 -44.687 1.00127.34 C +ANISOU 45 CB SER A 5 17646 13318 17418 2741 2774 -3729 C +ATOM 46 OG SER A 5 121.108 9.163 -44.712 1.00135.31 O +ANISOU 46 OG SER A 5 18807 14370 18235 2568 2576 -3643 O +ATOM 47 N ASN A 6 122.303 10.783 -42.240 1.00122.78 N +ANISOU 47 N ASN A 6 16868 13033 16750 2608 2581 -2859 N +ATOM 48 CA ASN A 6 122.460 12.194 -41.897 1.00114.44 C +ANISOU 48 CA ASN A 6 15777 12275 15429 2507 2620 -2639 C +ATOM 49 C ASN A 6 122.348 12.537 -40.412 1.00108.55 C +ANISOU 49 C ASN A 6 14870 11544 14832 2498 2474 -2282 C +ATOM 50 O ASN A 6 122.712 13.640 -40.004 1.00110.16 O +ANISOU 50 O ASN A 6 14983 11984 14890 2435 2531 -2135 O +ATOM 51 CB ASN A 6 121.461 13.034 -42.695 1.00113.00 C +ANISOU 51 CB ASN A 6 15832 12254 14850 2339 2583 -2658 C +ATOM 52 CG ASN A 6 121.646 12.886 -44.191 1.00118.14 C +ANISOU 52 CG ASN A 6 16648 12982 15257 2366 2743 -2999 C +ATOM 53 OD1 ASN A 6 122.765 12.952 -44.698 1.00122.16 O +ANISOU 53 OD1 ASN A 6 17097 13580 15737 2449 2985 -3154 O +ATOM 54 ND2 ASN A 6 120.546 12.672 -44.905 1.00118.96 N +ANISOU 54 ND2 ASN A 6 16946 13074 15179 2302 2609 -3139 N +ATOM 55 N HIS A 7 121.845 11.605 -39.608 1.00100.48 N +ANISOU 55 N HIS A 7 13810 10269 14098 2560 2305 -2149 N +ATOM 56 CA HIS A 7 121.657 11.871 -38.183 1.00 91.49 C +ANISOU 56 CA HIS A 7 12535 9160 13066 2569 2162 -1799 C +ATOM 57 C HIS A 7 122.134 10.725 -37.300 1.00 97.74 C +ANISOU 57 C HIS A 7 13180 9725 14232 2793 2117 -1685 C +ATOM 58 O HIS A 7 122.456 9.647 -37.791 1.00101.23 O +ANISOU 58 O HIS A 7 13643 9923 14898 2924 2188 -1876 O +ATOM 59 CB HIS A 7 120.189 12.175 -37.884 1.00 86.30 C +ANISOU 59 CB HIS A 7 12021 8464 12306 2383 1977 -1628 C +ATOM 60 CG HIS A 7 119.634 13.303 -38.694 1.00101.46 C +ANISOU 60 CG HIS A 7 14094 10603 13853 2201 2000 -1699 C +ATOM 61 ND1 HIS A 7 119.265 13.157 -40.015 1.00 99.83 N +ANISOU 61 ND1 HIS A 7 14076 10384 13472 2153 2049 -1976 N +ATOM 62 CD2 HIS A 7 119.401 14.600 -38.379 1.00 89.60 C +ANISOU 62 CD2 HIS A 7 12588 9342 12114 2078 1988 -1527 C +ATOM 63 CE1 HIS A 7 118.823 14.314 -40.476 1.00 97.86 C +ANISOU 63 CE1 HIS A 7 13944 10363 12875 2029 2062 -1939 C +ATOM 64 NE2 HIS A 7 118.896 15.206 -39.503 1.00 93.14 N +ANISOU 64 NE2 HIS A 7 13235 9899 12253 1975 2035 -1667 N +END diff --git a/examples/uniref50.hmm b/examples/uniref50.hmm new file mode 100644 index 0000000..b07ec14 --- /dev/null +++ b/examples/uniref50.hmm @@ -0,0 +1,466 @@ +HMMER3/f [3.1b2 | February 2015] +NAME uniref50 +LENG 148 +ALPH amino + RF no +MM no +CONS yes +CS no +MAP yes +DATE Mon Jun 12 14:32:05 2017 +NSEQ 15 +EFFN 0.648193 +CKSUM 2563184735 +STATS LOCAL MSV -10.0682 0.70956 +STATS LOCAL VITERBI -10.7870 0.70956 +STATS LOCAL FORWARD -4.6837 0.70956 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 2.40816 3.71583 2.80837 2.63551 3.47092 2.77036 3.85028 2.88279 2.80267 2.53589 3.68425 3.22102 3.34428 3.14560 3.11474 2.53177 2.75990 2.58070 5.00144 3.51101 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.10433 3.97705 2.52157 0.61958 0.77255 0.00000 * + 1 2.99317 4.53706 4.08224 3.67789 3.22093 3.85692 4.40592 2.39958 3.44433 1.81088 1.32037 3.95163 4.31759 3.82413 3.64608 3.34553 3.29902 2.40928 5.06591 3.83044 1 m - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 2 0.97044 4.20710 3.49350 3.28598 4.08269 3.03087 4.30444 3.21278 3.30302 3.09300 4.12129 3.42792 3.77296 3.64134 3.55157 2.55705 2.83652 2.86187 5.50678 4.31039 2 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.11955 3.90315 2.38048 0.61958 0.77255 0.55549 0.85282 + 3 1.74035 4.09199 3.34495 3.00819 4.05288 2.91638 4.05509 3.33461 3.01251 3.11462 3.97728 3.20348 3.62940 3.32849 3.32799 1.99191 1.99086 2.89563 5.42641 4.20726 3 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03323 3.81683 4.53917 0.61958 0.77255 0.62561 0.76558 + 4 2.37663 4.18625 3.55838 3.17855 3.75132 3.18264 4.13666 2.64341 3.07328 2.62344 3.69712 3.39774 3.83139 3.44405 3.35689 2.61052 1.64486 2.15973 5.30034 4.05468 4 t - - - + 2.68617 4.42230 2.77525 2.73129 3.46359 2.40511 3.72500 3.29359 2.67746 2.69350 4.24695 2.90352 2.73719 3.18152 2.89806 2.37885 2.77501 2.98524 4.58482 3.61508 + 0.33937 1.47682 2.82312 0.71438 0.67236 0.50642 0.92294 + 5 1.78828 4.31568 3.18846 2.75366 3.97645 3.11838 3.84000 3.34055 2.67250 3.02453 3.87541 3.10729 3.71676 3.06391 2.67828 2.15246 2.50645 2.96422 5.30410 4.05011 9 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03188 3.85742 4.57976 0.61958 0.77255 0.59400 0.80322 + 6 2.60146 4.34120 4.20318 3.64233 3.23200 4.03946 4.38229 1.91078 3.53317 1.46276 2.80385 3.95250 4.35454 3.78680 3.77614 3.34686 3.12310 1.90138 5.05979 3.90282 10 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03188 3.85742 4.57976 0.61958 0.77255 0.59400 0.80322 + 7 2.51618 4.38929 3.20785 2.68482 3.53842 3.39630 3.71025 2.97988 2.63127 2.66315 3.23915 3.11866 3.35060 2.98059 3.01133 2.11689 2.77574 2.72369 4.95633 3.10650 11 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03188 3.85742 4.57976 0.61958 0.77255 0.59400 0.80322 + 8 1.83112 4.12334 3.20156 2.95461 4.23963 1.79514 4.09699 3.64646 3.07597 3.33878 4.16582 3.16397 3.61350 3.35846 3.40724 1.96001 2.64648 3.10558 5.57497 4.34818 12 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.07518 3.85742 2.97012 0.61958 0.77255 0.59400 0.80322 + 9 2.02467 4.19921 3.47207 3.00878 3.03795 3.27081 3.95597 2.70270 2.96218 2.55248 3.54468 3.31239 3.83177 3.27950 3.28895 2.63385 2.09090 2.46488 5.06606 3.80489 13 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03327 3.81551 4.53786 0.61958 0.77255 0.56041 0.84624 + 10 2.25155 4.19461 3.85704 3.29295 2.92371 3.72128 4.04839 2.07964 3.20853 2.08962 2.71310 3.60847 4.09120 3.47607 3.47945 3.00735 2.74040 2.14097 4.86082 3.65928 14 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03170 3.86316 4.58551 0.61958 0.77255 0.53107 0.88667 + 11 2.97746 4.34766 4.53309 3.96552 2.78843 4.21079 4.53997 1.80103 3.85948 1.59494 2.57669 4.20401 4.48099 4.02954 4.02513 3.53069 3.20806 1.63119 5.03312 3.89134 15 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 12 2.01604 4.15364 3.23013 2.99255 4.26101 2.66741 4.12859 3.66796 3.09383 3.37186 4.20680 3.19709 3.64453 3.39377 3.41395 1.27425 2.68165 3.13093 5.59931 4.36607 16 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 13 2.41396 4.26265 3.40226 2.93569 3.72492 3.24366 3.92462 2.93397 2.83929 2.73560 3.16052 3.25846 3.81309 3.20648 3.16819 2.37913 1.73294 2.65776 5.16309 3.91530 17 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 14 2.06589 4.14828 3.30608 3.02868 4.20053 2.92394 4.12227 3.52677 3.06750 3.27902 4.13704 3.22373 3.65849 3.38850 3.37961 1.31011 2.40891 3.04032 5.55736 4.32788 18 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 15 2.74009 4.29274 3.92243 3.42912 1.74599 3.72053 3.90473 2.32427 3.32349 2.18956 3.31553 3.65797 4.14118 3.57919 3.55745 2.71376 3.01017 2.38146 4.46330 2.97696 19 f - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 16 2.76094 4.39380 4.31945 3.75589 3.18422 4.12530 4.45889 2.01307 3.63847 1.30728 2.59228 4.05575 4.41925 3.86957 3.85970 3.43754 3.19324 1.94550 5.06650 3.93230 20 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 17 2.70295 4.73637 3.16526 2.68917 4.18427 3.37581 3.71759 3.61851 2.27125 3.18722 4.06871 3.11427 2.39752 2.89725 1.66361 2.77186 2.98335 3.28411 5.34221 4.10051 21 r - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.07762 3.90315 2.90945 0.61958 0.77255 0.55549 0.85282 + 18 2.49055 4.81399 3.14505 2.59164 4.19520 3.44406 3.60132 3.55142 1.92611 3.12799 3.98038 3.04037 3.86298 2.75679 1.83484 2.76119 2.76042 3.23493 5.31169 4.06564 22 r - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.06501 3.85742 3.17445 0.61958 0.77255 0.59400 0.80322 + 19 2.43450 4.81939 2.81703 2.39298 4.15804 3.33308 3.59871 3.56807 2.06609 3.14527 3.97247 2.89702 3.36070 2.29211 2.66793 2.54254 2.87166 3.22778 5.35034 4.03520 23 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03294 3.82535 4.54770 0.61958 0.77255 0.61916 0.77305 + 20 2.61608 4.67386 2.79167 2.51004 4.07010 3.23635 3.73836 3.55025 2.48903 3.13320 4.04098 2.97430 2.02723 2.34075 2.83811 2.68076 2.93097 3.21608 5.34739 4.03735 24 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03294 3.82535 4.54770 0.61958 0.77255 0.51069 0.91649 + 21 1.83080 4.22890 3.60014 3.08598 3.61014 3.38577 4.01761 2.55536 3.00939 2.52819 3.20189 3.39791 3.91288 3.33215 3.33591 2.72706 2.41446 2.12040 5.12303 3.89826 25 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 22 2.43845 4.29437 3.39983 3.04145 3.80350 3.19872 4.06195 2.96220 2.98493 2.76612 3.80233 3.32666 1.71751 3.35496 3.29387 2.63325 2.83846 2.21304 5.28839 4.02321 26 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 23 2.55648 4.28453 3.47615 2.92649 3.45346 3.51308 3.86072 2.37030 2.85167 2.40896 2.93550 3.31525 2.97437 3.17776 3.19434 2.79032 2.33896 2.42929 4.94762 3.71651 27 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 24 2.23005 4.31546 3.25841 2.77512 3.78441 3.22479 3.82985 3.12652 2.73582 2.83244 3.03171 3.14960 3.26067 3.07830 3.10838 1.85715 2.73859 2.81468 5.16957 3.91289 28 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 25 2.72216 3.51794 4.14734 3.58168 3.26953 3.85722 4.23682 2.10046 3.47012 1.71220 2.91412 3.83361 4.22096 3.71804 3.68973 3.16541 2.79579 1.71693 4.93656 3.75086 29 l - - - + 2.68606 4.42227 2.77522 2.73126 3.46337 2.40515 3.72497 3.29356 2.67743 2.69357 4.24692 2.90349 2.73742 3.18149 2.89784 2.37889 2.77522 2.98521 4.58479 3.61506 + 0.31572 1.55442 2.82310 0.27619 1.42159 0.55549 0.85282 + 26 2.06718 4.47388 3.00085 2.59301 4.03403 3.18938 3.75234 3.40130 2.21691 3.06406 3.90876 3.01767 3.74194 2.94856 2.91976 2.09488 2.60568 3.04014 5.32541 4.04568 31 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03205 3.85226 4.57460 0.61958 0.77255 0.52495 0.89548 + 27 2.09937 4.25808 3.35967 2.86682 3.65405 3.28224 3.85971 2.93650 2.81278 2.15397 3.59474 3.22143 3.43624 3.14697 3.16235 2.43009 2.43628 2.66078 5.07593 3.83686 32 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 28 2.56380 4.32380 3.45039 2.92280 3.52453 3.48960 3.88793 2.33272 2.83649 2.29194 3.45598 3.31192 2.56007 3.18425 3.18050 2.78603 2.52825 2.43071 5.02605 3.78340 33 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 29 2.52137 4.41862 3.18708 2.64701 3.24265 3.41116 3.70401 2.99879 2.50849 2.54033 3.56040 3.09794 3.19241 2.94883 3.00442 2.32271 2.53579 2.73855 5.01724 3.74765 34 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 30 2.00013 4.58033 2.94855 2.53646 4.07584 3.24271 3.72285 3.46598 2.50253 3.10366 3.94143 2.28591 3.76727 2.90505 2.65085 2.58556 2.61842 3.10852 5.34830 4.05040 35 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 31 2.38233 4.27978 3.41241 2.86526 3.23400 3.48475 3.81694 2.67786 2.81404 2.37039 3.42629 2.84230 3.90072 3.13098 3.17039 2.75440 2.50322 2.16090 4.92926 3.68461 36 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 32 2.57741 4.71210 2.95136 2.48036 4.10354 2.51445 3.64563 3.50876 2.11219 3.10615 3.93363 2.96219 3.79067 2.80786 2.54902 2.50592 2.51289 3.16566 5.32824 4.02677 37 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 33 2.48649 4.79372 2.91636 2.20828 4.05411 3.38774 3.59403 3.46081 2.32653 3.05709 3.87988 2.78811 3.79502 2.48988 2.50461 2.63652 2.83744 2.71303 5.28703 3.96685 38 e - - - + 2.68619 4.42226 2.77520 2.73124 3.46338 2.40514 3.72495 3.29355 2.67742 2.69356 4.24691 2.90348 2.73732 3.18147 2.89802 2.37888 2.77520 2.98519 4.58478 3.61504 + 0.07101 2.83445 4.62550 0.63888 0.75053 0.55549 0.85282 + 34 1.61247 4.12982 3.30077 3.01153 4.23531 2.30721 4.11812 3.64225 3.09602 3.33089 4.15414 3.20546 3.63382 3.37908 3.42786 1.71494 2.65404 3.10635 5.57312 4.35188 41 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 35 2.72153 4.23229 3.98871 3.42694 2.97156 3.37228 4.12428 2.11066 3.32720 1.56866 3.14804 3.72158 4.17041 3.58506 3.57523 3.10753 2.96236 2.01957 4.85619 3.63474 42 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 36 2.59948 4.33296 4.13320 3.58598 1.90470 3.92561 4.14661 2.31847 3.46961 1.74381 2.73954 3.84829 4.26638 3.69996 3.68809 3.23462 3.08833 2.27549 4.71854 3.39100 43 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 37 2.58931 4.58161 2.85848 2.66250 4.27569 1.35942 3.92193 3.72667 2.37699 3.36968 4.25453 3.08080 3.80217 3.15095 3.05968 2.68693 2.97358 3.32002 5.50315 4.25822 44 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 38 2.65443 4.41996 3.43781 2.92526 3.49579 3.52457 3.83449 2.83057 2.64507 1.65492 3.47551 3.30970 3.36731 3.12885 2.65176 2.85231 2.91346 2.65496 4.98654 3.73087 45 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 39 2.72350 4.79628 3.09209 2.60253 4.10688 3.43694 3.64699 3.48037 1.53491 2.80300 3.97997 3.05455 3.87955 2.81812 2.48623 2.53142 2.96661 3.17965 5.30004 4.01932 46 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 40 1.82674 4.13179 3.37396 3.04098 4.15468 2.93287 4.10316 3.48191 3.05943 3.22685 4.07364 3.23234 3.65478 3.36800 3.38156 1.54612 2.23418 3.00585 5.51189 4.29184 47 s - - - + 2.68618 4.42225 2.77520 2.73124 3.46354 2.40513 3.72495 3.29354 2.67741 2.69355 4.24690 2.90347 2.73740 3.18147 2.89801 2.37887 2.77520 2.98508 4.58477 3.61503 + 0.07101 2.83445 4.62550 0.49418 0.94179 0.55549 0.85282 + 41 1.87334 4.14690 3.25058 2.97809 4.26468 2.12605 4.11046 3.68104 3.08263 3.36184 4.18261 3.18779 3.63442 3.36584 3.42015 1.58161 2.66271 3.13490 5.59481 4.36766 49 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.11955 3.90315 2.38048 0.61958 0.77255 0.55549 0.85282 + 42 2.21070 4.25592 3.22113 2.77420 3.85340 3.11965 3.84389 3.18555 2.74438 2.69874 3.77079 3.12117 3.16635 3.08826 3.10948 2.13243 2.17697 2.83916 5.22265 3.97074 50 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03323 3.81683 4.53917 0.61958 0.77255 0.62561 0.76558 + 43 2.34367 4.62113 3.10732 2.54725 3.88271 3.41056 3.61301 3.25335 2.12788 2.89080 3.32993 3.01581 3.81452 2.79680 2.35592 2.55841 2.82420 2.96607 5.15612 3.88260 51 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.07842 3.81683 2.92953 0.61958 0.77255 0.50642 0.92294 + 44 2.82371 4.84862 3.20218 2.72371 4.21308 3.44211 3.65714 3.71157 2.07944 3.25434 4.14899 2.84303 3.91564 2.83614 1.36807 2.87376 3.07618 3.38687 5.31229 4.06004 52 r - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.12129 3.86316 2.37274 0.61958 0.77255 0.58934 0.80899 + 45 2.50307 4.57358 2.77436 2.48515 4.13002 2.10145 3.72113 3.58708 2.48196 3.19739 4.04544 2.56817 3.72971 2.91621 2.54565 2.57756 2.84032 3.19983 5.38083 4.07634 53 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03462 3.77648 4.49883 0.61958 0.77255 0.55399 0.85485 + 46 2.68547 4.96255 2.09111 2.21584 4.36925 1.97687 3.70446 3.84410 2.62382 3.41713 4.25934 2.75900 3.76266 2.58919 3.12019 2.66938 2.98839 3.45462 5.60805 4.21173 54 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03205 3.85226 4.57460 0.61958 0.77255 0.52495 0.89548 + 47 2.70472 4.70735 3.22145 2.64799 3.96742 3.15410 3.63371 3.33902 2.12091 2.43520 3.82970 3.09240 3.88741 2.81708 1.91192 2.78290 2.92703 3.06076 5.19463 3.94224 55 r - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 48 2.39251 4.23853 3.75245 3.18839 3.35715 3.69117 4.01036 2.17738 3.07061 2.00722 3.28706 3.53429 4.07078 3.39072 3.07752 2.97399 2.89120 1.85844 4.92824 3.71532 56 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 49 2.56050 4.39105 3.34411 2.78319 3.60155 3.46480 3.77128 2.83822 2.62742 2.58594 3.21262 3.20237 3.88486 3.03059 2.56448 2.73642 2.19035 2.37832 5.02624 3.77891 57 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 50 1.37812 2.80072 3.83498 3.42070 3.87397 2.99921 4.24161 2.96530 3.32256 2.89459 3.81917 3.44880 3.71764 3.60422 3.56604 2.43360 2.40411 2.61888 5.33835 4.15246 58 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.55549 0.85282 + 51 2.74532 4.50724 3.42983 2.95244 3.42568 3.60626 3.88910 2.77026 2.70375 2.22807 1.95486 3.35569 4.02547 2.58121 2.99178 2.94186 2.99694 2.66631 5.01046 3.74777 59 m - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03044 3.90315 4.62550 0.61958 0.77255 0.44450 1.02483 + 52 0.87297 4.24657 3.57075 3.36786 4.15839 3.06811 4.37727 3.29971 3.38685 3.17640 4.19749 3.49040 3.81731 3.71861 3.62959 2.59634 2.88098 2.93600 5.57511 4.38724 60 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 53 1.96298 4.17134 3.43460 3.07855 4.14627 2.98936 4.12481 3.46945 3.08161 3.21642 4.06614 3.27556 3.70074 3.39215 3.40515 1.84467 1.63498 3.01250 5.50977 4.28998 61 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 54 3.40066 4.84720 3.99369 3.74344 2.30278 3.95279 3.67128 3.39553 3.59798 2.82228 4.05988 3.85394 4.42456 3.87882 3.75994 3.52665 3.68805 3.27113 3.95029 0.80817 62 y - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 55 2.86663 5.06853 2.87640 2.51952 4.45748 3.43879 3.66568 3.89866 1.33937 3.41664 4.27179 2.44223 3.91577 2.81805 2.46217 2.85914 3.10555 3.54515 5.50478 4.21799 63 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 56 2.89101 4.40561 4.26922 3.93641 3.62800 3.83108 4.72052 2.04974 3.80577 2.29743 3.57810 4.10920 4.38636 4.15841 4.00806 3.34183 3.25039 0.90272 5.42983 4.16757 64 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 57 2.78989 4.87427 3.10728 2.66228 4.33471 3.44160 3.70636 3.64306 1.30828 3.25641 4.14609 3.10047 3.92071 2.86764 2.46119 2.83588 2.59339 3.32217 5.44317 4.19498 65 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 58 3.28295 4.64373 4.65267 4.15432 2.12281 4.39226 4.40565 2.30868 4.01063 0.99404 2.96208 4.34589 4.63887 4.13687 4.14117 3.75853 3.51440 2.42033 4.68321 3.26182 66 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 59 3.08248 4.42168 4.72065 4.23378 3.50231 4.37831 4.95293 1.13074 4.10572 1.99571 3.31982 4.46032 4.70821 4.37869 4.30619 3.77127 3.35421 1.44848 5.47660 4.27063 67 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 60 2.47137 4.31634 3.52340 3.28135 4.06362 3.15188 4.29038 3.20358 3.22639 3.06334 4.10788 3.47324 3.86421 3.61618 3.47946 2.67390 1.00625 2.88730 5.49222 4.28053 68 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 61 2.89484 4.63395 3.51346 3.36817 4.35306 3.31558 4.43642 3.92611 3.43456 3.54133 4.59617 3.66397 0.65427 3.82016 3.66760 3.06578 3.34480 3.55944 5.51022 4.47541 69 P - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 62 2.83547 5.32344 1.90710 1.42799 4.63051 3.24198 3.71244 4.09996 2.65068 3.63347 4.46321 2.71732 3.81726 2.86723 3.20067 2.75440 2.81778 3.69487 5.81218 4.35094 70 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 63 2.79923 4.56350 3.49435 3.40744 4.54632 0.58454 4.52062 4.17205 3.60289 3.81287 4.79002 3.65874 3.95796 3.91884 3.82676 2.97427 3.28861 3.68020 5.61312 4.65200 71 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 64 2.69344 5.03834 2.59685 1.78499 4.35492 3.31996 3.63904 3.79867 2.33359 3.34661 4.15382 2.64678 2.71516 2.78054 2.89199 2.67010 2.77928 3.42501 5.53498 4.15652 72 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 65 2.70271 4.40317 3.56325 3.00957 3.45446 3.68235 3.94694 2.18180 2.88182 2.21283 3.37093 3.41883 4.05792 2.33611 3.21378 2.95204 2.94041 2.01647 5.02429 3.78732 73 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 66 3.04481 5.17464 2.53544 0.88540 4.53437 3.34332 3.94029 4.00914 2.83416 3.60986 4.58016 2.99593 3.95313 3.15433 3.25317 3.01711 3.35013 3.68253 5.68627 4.40959 74 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 67 3.05681 4.44153 4.54138 3.99838 1.97987 4.22221 4.40129 2.17878 3.87522 1.45215 3.02589 4.20160 4.50632 4.03401 4.02978 3.55251 3.29207 1.80812 4.80289 3.46847 75 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 68 2.82984 5.35567 1.99168 1.57663 4.64578 3.25717 3.68509 4.14274 2.58330 3.63869 4.45307 2.71724 3.81329 2.22362 3.11653 2.74299 3.09347 3.72626 5.79564 4.33600 76 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 69 2.50977 1.62448 4.23724 3.80750 3.60189 3.40590 4.45756 2.35254 3.63764 2.45765 3.57920 3.82230 4.04603 3.92585 3.81907 2.84633 2.91668 1.82275 5.24689 4.01880 77 c - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 70 2.77571 5.11398 2.10801 2.05696 4.45701 3.25620 3.72899 3.91339 2.64389 3.48166 4.32027 2.78446 1.86353 2.89484 3.15510 2.73789 3.05806 3.53410 5.67671 4.27030 78 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 71 2.91274 5.42662 1.24765 1.93231 4.73792 3.20738 3.76458 4.24169 2.78531 3.76893 4.62568 2.68636 3.83308 2.93581 3.37349 2.60161 3.20907 3.82383 5.94007 4.44265 79 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 72 2.93000 5.34144 1.08347 2.15883 4.66482 3.19912 3.82811 4.25255 2.88821 3.80850 4.69751 2.51974 3.85217 3.02158 3.46889 2.84580 3.25390 3.83179 5.90365 4.41772 80 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 73 2.89101 4.40561 4.26922 3.93641 3.62800 3.83108 4.72052 2.04974 3.80577 2.29743 3.57810 4.10920 4.38636 4.15841 4.00806 3.34183 3.25039 0.90272 5.42983 4.16757 81 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 74 3.40066 4.84720 3.99369 3.74344 2.30278 3.95279 3.67128 3.39553 3.59798 2.82228 4.05988 3.85394 4.42456 3.87882 3.75994 3.52665 3.68805 3.27113 3.95029 0.80817 82 y - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 75 3.08173 4.41570 4.73343 4.24332 3.51344 4.38931 4.96241 1.16063 4.11994 2.00857 3.32756 4.46929 4.71466 4.39012 4.32070 3.78014 3.35186 1.39369 5.48545 4.28088 83 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 76 3.27378 4.70553 4.35708 3.99825 3.17780 4.11433 4.62122 2.38848 3.76496 0.75643 3.16963 4.26355 4.53226 4.10824 3.92358 3.69863 3.56359 2.45281 5.09417 3.84135 84 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 77 3.10426 5.24570 0.77891 2.40498 4.63731 3.29196 4.02650 4.24977 3.13093 3.83985 4.82107 2.96628 3.95224 3.26642 3.66070 3.05541 3.44536 3.87811 5.78539 4.49402 85 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 78 2.10165 4.63153 3.04360 2.53313 3.37849 3.42468 3.14974 3.24484 2.48640 2.87927 3.73924 3.02051 3.83549 2.34761 2.89722 2.67591 2.83487 2.96227 5.11406 3.77860 86 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 79 0.87297 4.24657 3.57075 3.36786 4.15839 3.06811 4.37727 3.29971 3.38685 3.17640 4.19749 3.49040 3.81731 3.71861 3.62959 2.59634 2.88098 2.93600 5.57511 4.38724 87 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 80 3.04481 5.17464 2.53544 0.88540 4.53437 3.34332 3.94029 4.00914 2.83416 3.60986 4.58016 2.99593 3.95313 3.15433 3.25317 3.01711 3.35013 3.68253 5.68627 4.40959 88 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 81 3.04481 5.17464 2.53544 0.88540 4.53437 3.34332 3.94029 4.00914 2.83416 3.60986 4.58016 2.99593 3.95313 3.15433 3.25317 3.01711 3.35013 3.68253 5.68627 4.40959 89 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 82 2.02804 4.79412 2.56696 2.04470 4.09359 3.33689 3.67081 3.44631 2.51465 3.10781 3.94410 2.90500 3.80252 2.83547 2.98166 2.64658 2.87169 2.76307 5.37415 4.03168 90 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 83 2.79923 4.56350 3.49435 3.40744 4.54632 0.58454 4.52062 4.17205 3.60289 3.81287 4.79002 3.65874 3.95796 3.91884 3.82676 2.97427 3.28861 3.68020 5.61312 4.65200 91 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 84 2.73428 4.33692 3.73213 3.19478 3.16177 3.72868 2.92126 1.73180 3.00305 2.10225 3.32627 3.53324 4.10443 3.37488 3.27326 3.02489 2.97120 2.37844 4.75364 3.40581 92 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 85 2.98626 5.46880 1.08491 1.97249 4.77077 3.21550 3.81546 4.28421 2.87189 3.82944 4.72170 2.71026 3.86087 3.00007 3.46540 2.87647 3.29141 3.87860 5.96770 4.48798 93 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 86 3.27378 4.70553 4.35708 3.99825 3.17780 4.11433 4.62122 2.38848 3.76496 0.75643 3.16963 4.26355 4.53226 4.10824 3.92358 3.69863 3.56359 2.45281 5.09417 3.84135 94 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 87 2.89484 4.63395 3.51346 3.36817 4.35306 3.31558 4.43642 3.92611 3.43456 3.54133 4.59617 3.66397 0.65427 3.82016 3.66760 3.06578 3.34480 3.55944 5.51022 4.47541 95 P - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 88 3.48726 4.82741 4.35628 4.01269 1.82549 4.23514 3.48811 3.25093 3.87322 2.62544 3.87831 3.93991 4.57991 3.96204 3.99151 3.61127 3.72377 3.16284 3.67256 0.95290 96 y - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 89 2.36871 4.29005 3.29968 3.12112 4.18153 3.01810 4.22768 3.71868 3.20194 3.43114 4.34903 3.32859 3.76571 3.54324 3.48419 0.94365 2.85682 3.23083 5.54583 4.26583 97 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 90 2.70964 0.75093 4.25205 4.01610 3.98428 3.30982 4.64026 3.14621 3.84384 3.05665 4.18165 3.97525 4.02496 4.18572 3.94943 2.98138 3.18527 2.88356 5.37752 4.27103 98 c - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 91 3.12574 4.95602 3.62729 3.11760 4.33719 3.59265 3.90370 3.88680 2.28467 3.38377 4.38192 3.46899 4.09078 3.11945 0.82993 3.20529 3.38498 3.60641 5.37824 4.24257 99 r - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 92 0.87297 4.24657 3.57075 3.36786 4.15839 3.06811 4.37727 3.29971 3.38685 3.17640 4.19749 3.49040 3.81731 3.71861 3.62959 2.59634 2.88098 2.93600 5.57511 4.38724 100 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 93 2.79923 4.56350 3.49435 3.40744 4.54632 0.58454 4.52062 4.17205 3.60289 3.81287 4.79002 3.65874 3.95796 3.91884 3.82676 2.97427 3.28861 3.68020 5.61312 4.65200 101 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 94 2.36871 4.29005 3.29968 3.12112 4.18153 3.01810 4.22768 3.71868 3.20194 3.43114 4.34903 3.32859 3.76571 3.54324 3.48419 0.94365 2.85682 3.23083 5.54583 4.26583 102 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 95 2.70964 0.75093 4.25205 4.01610 3.98428 3.30982 4.64026 3.14621 3.84384 3.05665 4.18165 3.97525 4.02496 4.18572 3.94943 2.98138 3.18527 2.88356 5.37752 4.27103 103 c - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 96 2.36871 4.29005 3.29968 3.12112 4.18153 3.01810 4.22768 3.71868 3.20194 3.43114 4.34903 3.32859 3.76571 3.54324 3.48419 0.94365 2.85682 3.23083 5.54583 4.26583 104 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 97 2.36871 4.29005 3.29968 3.12112 4.18153 3.01810 4.22768 3.71868 3.20194 3.43114 4.34903 3.32859 3.76571 3.54324 3.48419 0.94365 2.85682 3.23083 5.54583 4.26583 105 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 98 2.70964 0.75093 4.25205 4.01610 3.98428 3.30982 4.64026 3.14621 3.84384 3.05665 4.18165 3.97525 4.02496 4.18572 3.94943 2.98138 3.18527 2.88356 5.37752 4.27103 106 c - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 99 0.87297 4.24657 3.57075 3.36786 4.15839 3.06811 4.37727 3.29971 3.38685 3.17640 4.19749 3.49040 3.81731 3.71861 3.62959 2.59634 2.88098 2.93600 5.57511 4.38724 107 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 100 2.79923 4.56350 3.49435 3.40744 4.54632 0.58454 4.52062 4.17205 3.60289 3.81287 4.79002 3.65874 3.95796 3.91884 3.82676 2.97427 3.28861 3.68020 5.61312 4.65200 108 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 101 3.06946 5.03551 3.25229 2.85531 4.44585 3.54670 3.82012 3.88188 0.90373 3.42461 4.38128 3.27486 4.04036 3.00629 2.45564 3.10509 3.31538 3.58407 5.45821 4.28639 109 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 102 3.06247 4.41039 4.65086 4.13598 3.48324 4.35915 4.85935 1.65561 4.00771 1.89605 3.31161 4.38665 4.67296 4.28428 4.22305 3.72759 3.32396 1.08186 5.42132 4.21018 110 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 103 2.33323 4.28075 3.53672 3.04537 3.62455 3.45748 3.98551 2.58410 2.72399 2.59228 3.55231 3.38781 3.95328 3.30102 3.25844 2.79290 2.46624 1.66085 5.10597 3.87716 111 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 104 2.09904 4.31904 3.13967 2.79512 4.23584 2.43802 3.97520 3.66080 2.88605 3.30435 4.12032 2.79615 3.70254 3.18983 3.27753 1.61859 2.49732 3.17574 5.54095 4.27688 112 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 105 2.79923 4.56350 3.49435 3.40744 4.54632 0.58454 4.52062 4.17205 3.60289 3.81287 4.79002 3.65874 3.95796 3.91884 3.82676 2.97427 3.28861 3.68020 5.61312 4.65200 113 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 106 2.34210 4.57052 2.98887 2.43186 3.63497 3.31233 3.71920 3.32573 2.57569 2.97882 3.82112 2.81207 3.79423 2.91349 3.00476 1.86229 2.69145 3.00524 5.25570 3.95436 114 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 107 3.05964 4.41092 4.64145 4.12759 3.48238 4.35054 4.85240 1.66963 3.99735 1.89738 3.31309 4.37857 4.66775 4.27653 4.21363 3.71953 3.32208 1.07763 5.41853 4.20516 115 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 108 2.91005 5.38045 1.25818 2.12941 4.69830 3.20228 3.78776 4.26304 2.81947 3.79137 4.65619 2.14323 3.83796 2.96707 3.40279 2.81725 3.21882 3.83565 5.91563 4.42054 116 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 109 2.96665 4.95377 2.97494 2.73211 4.13599 3.43683 3.89106 3.78353 2.54586 3.27542 4.30113 3.19246 3.99230 1.05904 2.82765 3.01035 3.26391 3.50694 5.38986 4.09082 117 q - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 110 2.64618 4.90499 2.31134 2.18942 4.30332 3.26131 3.70172 3.73572 2.57300 3.32434 4.14511 2.84177 3.78986 2.86174 3.06104 1.76618 2.63178 3.35922 5.54260 4.16860 118 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 111 3.10426 5.24570 0.77891 2.40498 4.63731 3.29196 4.02650 4.24977 3.13093 3.83985 4.82107 2.96628 3.95224 3.26642 3.66070 3.05541 3.44536 3.87811 5.78539 4.49402 119 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 112 2.73269 4.96873 2.61141 2.26957 4.35491 2.17303 3.70728 3.80016 2.46897 3.36392 4.20366 2.88233 3.83451 1.94009 2.87446 2.73151 3.00866 3.43365 5.54626 4.19876 120 q - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 113 2.56630 4.67539 2.76483 2.50324 4.25470 3.20379 3.80042 3.71196 2.47872 3.32135 4.15966 2.47516 3.79205 2.98884 3.00841 1.53662 2.90903 3.30833 5.51362 4.18451 121 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 114 3.45422 4.77029 4.46140 4.11213 1.01250 4.26302 3.55945 3.07075 3.96969 2.40922 3.69615 4.01237 4.59409 4.02617 4.05737 3.63979 3.68916 3.02613 3.73517 1.83750 122 f - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 115 3.27378 4.70553 4.35708 3.99825 3.17780 4.11433 4.62122 2.38848 3.76496 0.75643 3.16963 4.26355 4.53226 4.10824 3.92358 3.69863 3.56359 2.45281 5.09417 3.84135 123 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 116 2.92493 5.35887 1.12201 2.14550 4.68054 3.19834 3.81470 4.26138 2.86788 3.80711 4.68829 2.43062 3.84716 3.00361 3.45124 2.83676 3.24430 3.83759 5.91360 4.42201 124 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02824 3.97705 4.69940 0.61958 0.77255 0.48576 0.95510 + 117 2.99103 5.43832 1.04731 2.03422 4.75036 3.21916 3.83186 4.26509 2.89245 3.82288 4.72422 2.72815 3.86743 3.02108 3.48036 2.88767 3.30065 3.86474 5.95049 4.48470 125 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.05161 3.97705 3.45590 0.61958 0.77255 0.48576 0.95510 + 118 2.86997 5.43069 1.57180 1.74614 4.72729 2.80306 3.71453 4.23943 2.69618 3.73332 4.56237 2.43722 3.80910 2.87126 3.27991 2.76596 3.14983 3.81040 5.89719 4.40314 126 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 119 2.94701 4.93449 2.95833 2.71460 4.11381 3.42085 3.87354 3.75736 2.52981 3.25157 4.27740 3.17495 3.97565 1.09531 2.81227 2.99143 3.24405 3.48203 5.37148 4.07074 127 q - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 120 2.77849 4.28259 3.99549 3.02221 3.34513 3.89873 4.21017 1.60238 3.32583 1.96055 3.04166 3.76188 4.24121 3.61775 3.59603 3.18793 3.01465 1.89778 5.01613 3.81900 128 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 121 2.05663 4.99383 2.42035 1.95337 4.30142 3.11016 3.64379 3.74448 2.38547 3.30891 4.11909 2.80952 3.78509 2.79112 2.97996 2.54099 2.92358 3.37653 5.51637 4.13250 129 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 122 2.37074 5.20065 2.03752 1.62561 4.52764 2.94012 3.68254 3.99698 2.59389 3.53203 4.34713 2.73405 3.79399 2.83254 3.13133 2.70217 3.03318 3.59496 5.71621 4.27884 130 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 123 2.76891 4.53595 3.45942 3.36936 4.50963 0.61326 4.48439 4.12940 3.56175 3.77320 4.74981 3.62373 3.92970 3.87945 3.78857 2.94321 3.25651 3.64192 5.58291 4.61439 131 G - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 124 3.45280 4.72560 4.55948 4.18538 1.45983 4.27876 3.45556 3.19175 4.01502 2.56322 3.77632 3.99268 4.58568 4.02082 4.06587 3.62371 3.67122 3.09770 1.76510 1.80304 132 f - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 125 2.87283 4.39315 4.23821 3.90420 3.61058 3.80809 4.69198 2.04849 3.77322 2.28363 3.56364 4.08078 4.36427 4.12727 3.97777 3.31702 3.23254 0.92773 5.40873 4.14528 133 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 126 3.24760 4.68579 4.32075 3.96132 3.16793 4.08580 4.59138 2.37683 3.72825 0.78064 3.16594 4.22883 4.50730 4.07699 3.89079 3.66669 3.53825 2.43535 5.07658 3.81868 134 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 127 2.45786 4.30296 3.50186 3.25812 4.04222 3.13941 4.26905 3.17937 3.20271 3.03994 4.08552 3.45408 3.84975 3.59352 3.45722 2.66008 1.04037 2.86556 5.47283 4.25897 135 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 128 2.68154 0.78852 4.21932 3.97783 3.95068 3.28696 4.60693 3.10838 3.80528 3.02007 4.14415 3.94300 4.00035 4.14805 3.91507 2.95331 3.15521 2.84739 5.34926 4.23772 136 c - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 129 2.02617 4.29048 3.42265 2.94627 3.54036 3.40652 3.31257 2.77872 2.86355 2.59741 3.53948 3.30371 3.90044 3.21666 3.18816 2.73904 2.82169 1.86270 5.00831 3.74432 137 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 130 0.90195 4.23400 3.54659 3.34205 4.13472 3.05626 4.35430 3.27256 3.36043 3.15035 4.17350 3.47069 3.80326 3.69417 3.60509 2.58374 2.86679 2.91280 5.55371 4.36315 138 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 131 3.44381 4.80306 4.30117 3.95207 1.85364 4.19548 3.48537 3.22033 3.81418 2.60484 3.85318 3.90681 4.54641 3.92239 3.94488 3.57229 3.68268 3.12961 3.68006 0.97942 139 y - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 132 2.86235 4.60578 3.47842 3.32948 4.31715 3.28867 4.39999 3.88386 3.39382 3.50174 4.55528 3.62780 0.68858 3.78012 3.62986 3.03247 3.31042 3.51987 5.48103 4.43903 140 P - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 133 2.60256 4.60991 3.08123 2.59418 3.90705 3.39886 3.69738 3.25085 2.27951 2.91739 3.78849 3.05676 3.84470 2.63540 2.79735 2.69573 1.94572 2.76699 5.21418 3.93668 141 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 134 2.16968 3.47307 3.59233 3.22260 4.15866 2.47411 4.19438 3.56363 3.18625 3.27458 4.10858 3.32406 3.66022 3.48496 3.48055 1.23700 2.65371 3.05043 5.52336 4.31592 142 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 135 3.07859 5.21813 0.80740 2.38838 4.60638 3.27362 4.00471 4.21341 3.10456 3.80732 4.78755 2.94873 3.93224 3.24424 3.63163 3.03196 3.41903 3.84400 5.75900 4.46621 143 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 136 2.87283 4.39315 4.23821 3.90420 3.61058 3.80809 4.69198 2.04849 3.77322 2.28363 3.56364 4.08078 4.36427 4.12727 3.97777 3.31702 3.23254 0.92773 5.40873 4.14528 144 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 137 2.50102 4.23694 3.76525 3.33965 3.72246 3.37067 4.24809 2.46042 3.23911 2.55924 3.64161 3.56053 3.97799 3.58142 3.52035 2.77764 1.69802 1.75863 5.30971 4.08018 145 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 138 3.09498 4.49149 4.45102 4.07022 3.43002 4.15408 4.78347 0.98199 3.89992 1.99977 3.35310 4.30411 4.57779 4.24002 4.08717 3.65761 3.39284 1.85079 5.33749 4.08258 146 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 139 3.02382 5.15051 2.52384 0.91441 4.50717 3.32764 3.92196 3.97736 2.81286 3.58149 4.55225 2.98104 3.93620 3.13613 3.22992 2.99812 3.32879 3.65289 5.66334 4.38601 147 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 140 2.45786 4.30296 3.50186 3.25812 4.04222 3.13941 4.26905 3.17937 3.20271 3.03994 4.08552 3.45408 3.84975 3.59352 3.45722 2.66008 1.04037 2.86556 5.47283 4.25897 148 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 141 3.08695 4.88934 3.20791 2.97643 3.34377 3.51816 0.98092 3.80251 2.81733 3.28606 4.33566 3.38232 4.07539 3.34383 3.07797 3.15699 3.39324 3.53609 4.80769 3.29239 149 h - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 142 2.99214 5.06805 3.26268 2.74531 4.47846 3.57206 3.65342 3.86981 1.12103 3.36156 4.25702 3.16311 3.99796 2.80635 2.11223 3.00404 3.19554 3.55761 5.42835 4.23089 150 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 143 3.02382 5.15051 2.52384 0.91441 4.50717 3.32764 3.92196 3.97736 2.81286 3.58149 4.55225 2.98104 3.93620 3.13613 3.22992 2.99812 3.32879 3.65289 5.66334 4.38601 151 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 144 2.49167 5.21869 2.13891 1.38935 4.54510 3.23855 3.71342 3.98470 2.64038 3.55288 4.39217 2.73628 3.81159 2.87379 3.17028 2.74234 3.08340 3.59770 5.74876 4.31122 152 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 145 2.67924 5.36825 1.81597 1.42545 4.67130 3.22067 3.71949 4.14895 2.68617 3.67868 4.51726 2.69278 3.81366 2.87890 3.25116 2.76699 3.13943 3.73938 5.85528 4.37934 153 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 146 3.24708 4.60677 4.69416 4.13988 3.08947 4.47063 4.76500 1.92492 3.96672 0.95356 2.71915 4.43331 4.67883 4.15873 4.13317 3.81764 3.47493 2.15974 5.15578 4.04247 154 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02889 3.95434 4.67668 0.61958 0.77255 0.50828 0.92013 + 147 2.69781 4.29649 3.84369 3.29786 3.44437 3.73086 4.15124 2.24231 3.19336 2.10104 3.11890 3.63278 4.14347 3.51043 3.49251 3.03876 2.03846 1.78833 5.07714 3.86271 155 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.18495 3.95434 1.89921 0.61958 0.77255 0.50828 0.92013 + 148 1.44115 4.10304 3.22225 2.99375 4.15355 2.08176 4.10711 3.47540 3.09081 3.24183 4.11431 3.18864 3.61518 3.39097 3.39593 2.35434 2.65737 2.99565 5.50492 4.29375 156 a - - - + 2.68608 4.42226 2.77520 2.73124 3.46354 2.40513 3.72495 3.29355 2.67741 2.69355 4.24690 2.90347 2.73740 3.18147 2.89801 2.37887 2.77520 2.98519 4.58477 3.61504 + 0.08120 2.55114 * 0.46726 0.98542 0.00000 * +// diff --git a/help/help.jhm b/help/help.jhm index 732f01b..506b3f3 100755 --- a/help/help.jhm +++ b/help/help.jhm @@ -22,7 +22,7 @@ - + @@ -126,6 +126,7 @@ + diff --git a/help/helpTOC.xml b/help/helpTOC.xml index 20dd8db..71b7ef9 100755 --- a/help/helpTOC.xml +++ b/help/helpTOC.xml @@ -152,6 +152,7 @@ + diff --git a/help/html/features/preferences.html b/help/html/features/preferences.html index b29b66b..533af5c 100755 --- a/help/html/features/preferences.html +++ b/help/html/features/preferences.html @@ -62,8 +62,10 @@ sequence alignments and EPS files.
  • The "Editing" - Preferences tab contains settings affecting the export of - sequence alignments and EPS files. + Preferences tab contains settings affecting the behaviour of alignments as you edit them. +
  • +
  • The "HMMER" + Preferences tab allows you to configure locally installed HMMER tools.
  • The "DAS Settings" Preferences tab allows you to select which DAS @@ -387,7 +389,13 @@ Sort with New Tree - When selected, any trees calculated or loaded onto the alignment will automatically sort the alignment.

    -

     

    -

     

    +

    + "HMMER" Preferences tab +

    +

    If you have installed HMMER tools (available from hmmer.org), + then you should specify on this screen the location of the installation (the path to the folder + containing binary executable programs). Double-click in the input field to open a file browser.

    +

    When this path is configured, the HMMER menu will be + enabled in the Alignment window.

    diff --git a/help/html/features/splitView.html b/help/html/features/splitView.html index be1bd66..e1c07c1 100644 --- a/help/html/features/splitView.html +++ b/help/html/features/splitView.html @@ -76,7 +76,7 @@ or "View→Nucleotide" (in the protein panel) allows you to show or hide one or other of the linked alignment panels.
  • -
  • Panel heights are adjusted dragging the divider between +
  • Panel heights are adjusted by dragging the divider between them using the mouse
  • "View→New View / Expand Views / Gather Views" behave as for a normal diff --git a/help/html/menus/alwhmmer.html b/help/html/menus/alwhmmer.html new file mode 100644 index 0000000..ce23c4b --- /dev/null +++ b/help/html/menus/alwhmmer.html @@ -0,0 +1,87 @@ + + + + + +

    + HMMER Menu +

    +

    This menu is available if hmmbuild tools have been installed and configured in the +HMMER Preferences panel. +

    + + hmmbuild +

    Run hmmbuild to create a Hidden Markov Model profile of your sequence alignment or sub-groups. +

    The consensus sequence for the computed profile is inserted as the first sequence of + the alignment (or group) for which hmmbuild is run. +
    Jalview also computes and displays an annotation below the alignment, showing + the information content of each column. +
    This is calculated as the sum over residue symbols of +

    +    match emission probability * log(match emission probability / background frequency) / log(2)
    +  
    + where the background frequencies are taken from (tbc: where? not https://www.ebi.ac.uk/uniprot/TrEMBLstats) +
      +
    • Edit settings and run... +

      Choose whether to run hmmbuild for the whole alignment, or all or selected groups, or both + (default is the alignment). +
      Optionally enter a name to give the HMM profile consensus sequence + (default is "Alignment" or group name, with "_HMM" appended). +
      Use Reference Annotation: select this option if your alignment has an RF reference annotation, + and you wish to constrain the HMM profile to it (hmmbuild option '--hand'). +

    • +
    • hmmbuild with default settings +

      Runs hmmbuild for the whole alignment.
    • +
    + + hmmalign and hmmsearch require an HMM consensus sequence to be selected first. +
    To do this, right-click on the name of an HMM sequence added by hmmbuild, and 'Select HMM'. + The alignment will be with respect to the HMM profile for the consensus sequence. +

    + hmmalign +

    Run hmmalign to align selected sequences (or the whole alignment) to a selected HMM profile. +
      +
    • Edit settings and run... +

      Choose whether to 'trim non-matching termini' - hmmalign option '--trim'. +

    • +
    • hmmalign with default settings
    • +
    + hmmsearch +

    Run hmmsearch to use an HMM profile as input to search a sequence database. +
      +
    • Edit settings and run... +
        +
      • tbc: choose database
      • +
      • tbc: automatically align
      • +
      • tbc: return accessions
      • +
      • tbc: number of results
      • +
      • tbc: sequence eValue cutoff
      • +
      • tbc: domains eValue cutoff
      • +
      +
    • +
    • hmmsearch with default settings
    • +
    • Add database +
      Browse to select a local sequence data file to be searched
    • +
    +
    + + diff --git a/help/html/releases.html b/help/html/releases.html index 83d2ce4..006ee5c 100755 --- a/help/html/releases.html +++ b/help/html/releases.html @@ -70,6 +70,44 @@ li:before {
    + 2.10.4
    27/02/2018
    +
    + +
    + +
      +
    • + Mouse cursor changes to indicate Sequence ID and annotation area margins can be click-dragged to adjust them.
    • +
    • + Jalview uses HTTPS for Uniprot, Xfam and Ensembl services +
    • +
    • + Improved performance for large alignments and lots of hidden columns +
    • +
    +
    + +
    +
      +
    • + Slow redraw when Overview panel shown overlapping alignment panel +
    • +
    • + Linked scrolling via protein horizontal scroll bar doesn't work for some CDS/Protein views +
    • +
    • Trackpad scrolling is broken on OSX on Java 1.8u153 onwards and Java 1.9u4+.
    • +
    • Tooltip shouldn't be displayed for empty columns in annotation row
    • +
    • Preferences panel's ID Width control is honored in interactive and batch mode
    • +
    Applet
      +
    • Copy consensus sequence option in applet should copy the group consensus when popup is opened on it
    • + +
    +
    + + + + +
    2.10.3b1
    24/1/2018
    diff --git a/help/html/whatsNew.html b/help/html/whatsNew.html index 6d75f0f..d3972f5 100755 --- a/help/html/whatsNew.html +++ b/help/html/whatsNew.html @@ -24,25 +24,15 @@

    - What's new in Jalview 2.10.3b1 ? + What's new in Jalview 2.10.4 ?

    - This is the January 2018 patch release, which addresses critical bugs including trackpad function in OSX, and display of multiple 3D structures. - The full list bugs fixed in this release can be found in the 2.10.3b1 - Release Notes. In addition, Jalview 2.10.3 provides: + This is the February 2018 release of Jalview, with several minor bug fixes and enhanvements. + The full list bugs fixed in this release can be found in the 2.10.4 + Release Notes. In addition, Jalview 2.10.4 provides:

      -
    • Faster and more responsive UI when importing and working - with wide alignments and handling hundreds and thousands of - sequence features
    • -
    • Improved usability with PDB and UniProt Free Text - Search dialog, and new tab for retrieval of sequences for lists of - IDs. -
    • -
    • Short names assigned to sequences retrieved from UniProt
    • -
    • Groovy console upgraded to 2.4.12 (improved support for Java 9)
    • +

    Experimental Features diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 3f5aa94..06c8b6b 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -11,6 +11,7 @@ action.paste = Paste action.show_html_source = Show HTML Source action.print = Print... action.web_service = Web Service +action.hmmer = HMMER action.cancel_job = Cancel Job action.start_job = Start Job action.revert = Revert @@ -203,6 +204,8 @@ label.colourScheme_purine/pyrimidine = Purine/Pyrimidine label.colourScheme_nucleotide = Nucleotide label.colourScheme_t-coffee_scores = T-Coffee Scores label.colourScheme_rna_helices = By RNA Helices +label.colourScheme_hmmer-uniprot = HMMER profile v global background +label.colourScheme_hmmer-alignment = HMMER profile v alignment background label.blc = BLC label.fasta = Fasta label.msf = MSF @@ -1147,6 +1150,9 @@ status.loading_cached_pdb_entries = Loading Cached PDB Entries status.searching_for_pdb_structures = Searching for PDB Structures status.opening_file_for = opening file for status.colouring_chimera = Colouring Chimera +status.running_hmmbuild = Building Hidden Markov Model +status.running_hmmalign = Creating alignment with Hidden Markov Model +status.running_hmmsearch = Searching for matching sequences label.font_doesnt_have_letters_defined = Font doesn't have letters defined\nso cannot be used\nwith alignment data label.font_too_small = Font size is too small label.error_loading_file_params = Error loading file {0} @@ -1367,3 +1373,65 @@ label.most_bound_molecules = Most Bound Molecules label.most_polymer_residues = Most Polymer Residues label.cached_structures = Cached Structures label.free_text_search = Free Text Search +label.hmmalign = hmmalign +label.hmmbuild = hmmbuild +label.hmmbuild_group = Build HMM from Selected Group +label.group_hmmbuild = Build HMM from Group +label.hmmsearch = hmmsearch +label.hmmer_location = HMMER Binaries Installation Location +warn.null_hmm = Please ensure the alignment contains a hidden Markov model. +label.ignore_below_background_frequency = Ignore Below Background Frequency +label.information_description = Information content, measured in bits +warn.no_selected_hmm = Please select a hidden Markov model sequence. +label.select_hmm = Select HMM +warn.no_sequence_data = No sequence data found. +warn.empty_grp_or_alignment = An empty group or alignment was found. +label.no_sequences_found = No matching sequences, or an error occurred. +label.hmmer = HMMER +label.trim_termini = Trim Non-Matching Termini +label.trim_termini_desc = If true, non-matching regions on either end of the resulting alignment are removed. +label.no_of_sequences = Sequences Returned +label.freq_alignment = Use Alignment Background Frequencies +label.freq_uniprot = Use Uniprot Background Frequencies +label.hmmalign_label = hmmalign Options +label.hmmsearch_label = hmmsearch Options +label.hmmbuild_not_found = The hmmbuild binary was not found +label.hmmalign_not_found = The hmmalign binary was not found +label.hmmsearch_not_found = The hmmsearch binary was not found +warn.hmm_command_failed = hmm command not found +label.invalid_folder = Invalid Folder +label.folder_not_exists = HMMER binaries not found. \n Please enter the path to the HMMER binaries (if installed). +label.hmmer_installed = HMMER installed +label.hmmer_no_sequences_found = No sequences found +label.number_of_results = Number of Results to Return +label.auto_align_seqs = Automatically Align Fetched Sequences +label.use_accessions = Return Accessions +label.seq_e_value = Sequence E-value Cutoff +label.seq_score = Sequence Score Threshold +label.dom_e_value = Domain E-value Cutoff +label.dom_score = Domain Score Threshold +label.number_of_results_desc = The maximum number of results that hmmsearch will return +label.auto_align_seqs_desc = If true, all fetched sequences will be aligned to the hidden Markov model with which the search was performed +label.use_accessions_desc = If true, the accession number of each sequence is returned, rather than that sequences name +label.seq_e_value_desc = The E-value cutoff for returned sequences +label.seq_score_desc = The score threshold for returned sequences +label.dom_e_value_desc = The E-value cutoff for returned domains +label.dom_score_desc = The score threshold for returned domains +label.not_enough_sequences = There are not enough sequences to run {0} +label.add_database = Add Database +label.this_alignment = This alignment +warn.file_not_exists = File does not exist +warn.invalid_format = This is not a valid database file format. The current supported formats are Fasta, Stockholm and Pfam. +label.database_for_hmmsearch = The database hmmsearch will search through +label.use_reference = Use Reference Annotation +label.use_reference_desc = If true, hmmbuild will keep all columns defined as a reference position by the reference annotation +label.hmm_name = HMM Name +label.hmm_name_desc = The name given to the HMM. +warn.no_reference_annotation = No reference annotation found. +label.hmmbuild_for = Build HMM for +label.hmmbuild_for_desc = Build an HMM for the selected sequence groups. +label.alignment = Alignment +label.groups_and_alignment = All groups and alignment +label.groups = All groups +label.selected_group = Selected group +label.use_info_for_height = Use Information Content as Letter Height diff --git a/src/MCview/PDBChain.java b/src/MCview/PDBChain.java index f4bd31c..29b994e 100755 --- a/src/MCview/PDBChain.java +++ b/src/MCview/PDBChain.java @@ -162,6 +162,50 @@ public class PDBChain } /** + * Annotate the residues with their corresponding positions in s1 using the + * alignment in as NOTE: This clears all atom.alignmentMapping values on the + * structure. + * + * @param as + * @param s1 + */ + public void makeExactMapping(StructureMapping mapping, SequenceI s1) + { + // first clear out any old alignmentMapping values: + for (Atom atom : atoms) + { + atom.alignmentMapping = -1; + } + SequenceI ds = s1; + while (ds.getDatasetSequence() != null) + { + ds = ds.getDatasetSequence(); + } + int pdboffset = 0; + for (Residue res : residues) + { + // res.number isn't set correctly for discontinuous/mismapped residues + int seqpos = mapping.getSeqPos(res.atoms.get(0).resNumber); + char strchar = sequence.getCharAt(pdboffset++); + if (seqpos == StructureMapping.UNASSIGNED_VALUE) + { + continue; + } + char seqchar = ds.getCharAt(seqpos - ds.getStart()); + + boolean sameResidue = Comparison.isSameResidue( + seqchar, strchar, false); + if (sameResidue) + { + for (Atom atom : res.atoms) + { + atom.alignmentMapping = seqpos - 1; + } + } + } + } + + /** * Copies over the RESNUM seqfeatures from the internal chain sequence to the * mapped sequence * @@ -550,6 +594,12 @@ public class PDBChain { SequenceI sq = mapping.getSequence(); SequenceI dsq = sq; + if (sqmpping == null) + { + // SIFTS mappings are recorded in the StructureMapping object... + + sqmpping = mapping.getSeqToPdbMapping(); + } if (sq != null) { while (dsq.getDatasetSequence() != null) diff --git a/src/jalview/analysis/AAFrequency.java b/src/jalview/analysis/AAFrequency.java index e4f2dfa..11c8f72 100755 --- a/src/jalview/analysis/AAFrequency.java +++ b/src/jalview/analysis/AAFrequency.java @@ -24,6 +24,7 @@ import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.Profile; import jalview.datamodel.ProfileI; import jalview.datamodel.Profiles; @@ -32,6 +33,7 @@ import jalview.datamodel.ResidueCount; import jalview.datamodel.ResidueCount.SymbolCounts; import jalview.datamodel.SequenceI; import jalview.ext.android.SparseIntArray; +import jalview.schemes.ResidueProperties; import jalview.util.Comparison; import jalview.util.Format; import jalview.util.MappingUtils; @@ -48,25 +50,12 @@ import java.util.List; * This class is used extensively in calculating alignment colourschemes that * depend on the amount of conservation in each alignment column. * - * @author $author$ - * @version $Revision$ */ public class AAFrequency { - public static final String PROFILE = "P"; - - /* - * Quick look-up of String value of char 'A' to 'Z' - */ - private static final String[] CHARS = new String['Z' - 'A' + 1]; + private static final double LOG2 = Math.log(2); - static - { - for (char c = 'A'; c <= 'Z'; c++) - { - CHARS[c - 'A'] = String.valueOf(c); - } - } + public static final String PROFILE = "P"; public static final ProfilesI calculate(List list, int start, int end) @@ -192,6 +181,52 @@ public class AAFrequency } /** + * Returns the full set of profiles for a hidden Markov model. The underlying + * data is the raw probabilities of a residue being emitted at each node, + * however the profiles returned by this function contain the percentage + * chance of a residue emission. + * + * @param hmm + * @param width + * The width of the Profile array (Profiles) to be returned. + * @param start + * The alignment column on which the first profile is based. + * @param end + * The alignment column on which the last profile is based. + * @param removeBelowBackground + * if true, symbols with a match emission probability less than + * background frequency are ignored + * @return + */ + public static ProfilesI calculateHMMProfiles(final HiddenMarkovModel hmm, + int width, int start, int end, boolean removeBelowBackground, + boolean infoLetterHeight) + { + ProfileI[] result = new ProfileI[width]; + char[] symbols = hmm.getSymbols().toCharArray(); + int symbolCount = symbols.length; + for (int column = start; column < end; column++) + { + ResidueCount counts = new ResidueCount(); + for (char symbol : symbols) + { + int value = getAnalogueCount(hmm, column, symbol, + removeBelowBackground, infoLetterHeight); + counts.put(symbol, value); + } + int maxCount = counts.getModalCount(); + String maxResidue = counts.getResiduesForCount(maxCount); + int gapCount = counts.getGapCount(); + ProfileI profile = new Profile(symbolCount, gapCount, maxCount, + maxResidue); + profile.setCounts(counts); + + result[column] = profile; + } + return new Profiles(result); + } + + /** * Make an estimate of the profile size we are going to compute i.e. how many * different characters may be present in it. Overestimating has a cost of * using more memory than necessary. Underestimating has a cost of needing to @@ -289,9 +324,80 @@ public class AAFrequency } /** - * Derive the gap count annotation row. + * Derive the information annotations to be added to the alignment for + * display. This does not recompute the raw data, but may be called on a + * change in display options, such as 'ignore below background frequency', + * which may in turn result in a change in the derived values. * - * @param gaprow + * @param information + * the annotation row to add annotations to + * @param profiles + * the source information data + * @param startCol + * start column (inclusive) + * @param endCol + * end column (exclusive) + * @param ignoreGaps + * if true, normalise residue percentages + * @param showSequenceLogo + * if true include all information symbols, else just show modal + * residue + */ + public static float completeInformation(AlignmentAnnotation information, + ProfilesI profiles, int startCol, int endCol) + { + // long now = System.currentTimeMillis(); + if (information == null || information.annotations == null) + { + /* + * called with a bad alignment annotation row + * wait for it to be initialised properly + */ + return 0; + } + + float max = 0f; + SequenceI hmmSeq = information.sequenceRef; + + int seqLength = hmmSeq.getLength(); + if (information.annotations.length < seqLength) + { + return 0; + } + + HiddenMarkovModel hmm = hmmSeq.getHMM(); + + for (int column = startCol; column < endCol; column++) + { + if (column >= seqLength) + { + // hmm consensus sequence is shorter than the alignment + break; + } + + float value = hmm.getInformationContent(column); + boolean isNaN = Float.isNaN(value); + if (!isNaN) + { + max = Math.max(max, value); + } + + String description = isNaN ? null + : String.format("%.4f bits", value); + information.annotations[column] = new Annotation( + Character.toString( + Character.toUpperCase(hmmSeq.getCharAt(column))), + description, ' ', value); + } + + information.graphMax = max; + return max; + } + + /** + * Derive the occupancy count annotation + * + * @param occupancy * the annotation row to add annotations to * @param profiles * the source consensus data @@ -300,11 +406,11 @@ public class AAFrequency * @param endCol * end column (exclusive) */ - public static void completeGapAnnot(AlignmentAnnotation gaprow, + public static void completeOccupancyAnnot(AlignmentAnnotation occupancy, ProfilesI profiles, int startCol, int endCol, long nseq) { - if (gaprow == null || gaprow.annotations == null - || gaprow.annotations.length < endCol) + if (occupancy == null || occupancy.annotations == null + || occupancy.annotations.length < endCol) { /* * called with a bad alignment annotation row @@ -313,8 +419,8 @@ public class AAFrequency return; } // always set ranges again - gaprow.graphMax = nseq; - gaprow.graphMin = 0; + occupancy.graphMax = nseq; + occupancy.graphMin = 0; double scale = 0.8 / nseq; for (int i = startCol; i < endCol; i++) { @@ -325,7 +431,7 @@ public class AAFrequency * happens if sequences calculated over were * shorter than alignment width */ - gaprow.annotations[i] = null; + occupancy.annotations[i] = null; return; } @@ -333,7 +439,8 @@ public class AAFrequency String description = "" + gapped; - gaprow.annotations[i] = new Annotation("", description, '\0', gapped, + occupancy.annotations[i] = new Annotation("", description, '\0', + gapped, jalview.util.ColorUtils.bleachColour(Color.DARK_GRAY, (float) scale * gapped)); } @@ -449,6 +556,7 @@ public class AAFrequency return result; } + /** * Extract a sorted extract of cDNA codon profile data. The returned array * contains @@ -531,7 +639,7 @@ public class AAFrequency for (int col = 0; col < cols; col++) { // todo would prefer a Java bean for consensus data - Hashtable columnHash = new Hashtable(); + Hashtable columnHash = new Hashtable<>(); // #seqs, #ungapped seqs, counts indexed by (codon encoded + 1) int[] codonCounts = new int[66]; codonCounts[0] = alignment.getSequences().size(); @@ -718,4 +826,118 @@ public class AAFrequency } return scale; } + + /** + * Returns the sorted HMM profile for the given column of the alignment. The + * returned array contains + * + *

    +   *    [profileType=0, numberOfValues, 100, charValue1, percentage1, charValue2, percentage2, ...]
    +   * in descending order of percentage value
    +   * 
    + * + * @param hmm + * @param column + * @param removeBelowBackground + * if true, ignores residues with probability less than their + * background frequency + * @param infoHeight + * if true, uses the log ratio 'information' measure to scale the + * value + * @return + */ + public static int[] extractHMMProfile(HiddenMarkovModel hmm, int column, + boolean removeBelowBackground, boolean infoHeight) + { + if (hmm == null) + { + return null; + } + String alphabet = hmm.getSymbols(); + int size = alphabet.length(); + char symbols[] = new char[size]; + int values[] = new int[size]; + int totalCount = 0; + + for (int i = 0; i < size; i++) + { + char symbol = alphabet.charAt(i); + symbols[i] = symbol; + int value = getAnalogueCount(hmm, column, symbol, + removeBelowBackground, infoHeight); + values[i] = value; + totalCount += value; + } + + /* + * sort symbols by increasing emission probability + */ + QuickSort.sort(values, symbols); + + int[] profile = new int[3 + size * 2]; + + profile[0] = AlignmentAnnotation.SEQUENCE_PROFILE; + profile[1] = size; + profile[2] = 100; + + /* + * order symbol/count profile by decreasing emission probability + */ + if (totalCount != 0) + { + int arrayPos = 3; + for (int k = size - 1; k >= 0; k--) + { + Float percentage; + int value = values[k]; + if (removeBelowBackground) + { + percentage = ((float) value) / totalCount * 100f; + } + else + { + percentage = value / 100f; + } + int intPercent = Math.round(percentage); + profile[arrayPos] = symbols[k]; + profile[arrayPos + 1] = intPercent; + arrayPos += 2; + } + } + return profile; + } + + /** + * Converts the emission probability of a residue at a column in the alignment + * to a 'count', suitable for rendering as an annotation value + * + * @param hmm + * @param column + * @param symbol + * @param removeBelowBackground + * if true, returns 0 for any symbol with a match emission + * probability less than the background frequency + * @infoHeight if true, uses the log ratio 'information content' to scale the + * value + * @return + */ + static int getAnalogueCount(HiddenMarkovModel hmm, int column, + char symbol, boolean removeBelowBackground, boolean infoHeight) + { + double value = hmm.getMatchEmissionProbability(column, symbol); + double freq = ResidueProperties.backgroundFrequencies + .get(hmm.getAlphabetType()).get(symbol); + if (value < freq && removeBelowBackground) + { + return 0; + } + + if (infoHeight) + { + value = value * (Math.log(value / freq) / LOG2); + } + + value = value * 10000d; + return Math.round((float) value); + } } diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index 5e11446..d1217bf 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -1888,7 +1888,7 @@ public class AlignmentUtils * @param seqMappings * the set of mappings involving dnaSeq * @param aMapping - * an initial candidate from seqMappings + * a transcript-to-peptide mapping * @return */ static SequenceI findCdsForProtein(List mappings, @@ -1913,7 +1913,15 @@ public class AlignmentUtils if (mappedFromLength == dnaLength || mappedFromLength == dnaLength - CODON_LENGTH) { - return seqDss; + /* + * if sequence has CDS features, this is a transcript with no UTR + * - do not take this as the CDS sequence! (JAL-2789) + */ + if (seqDss.getFeatures().getFeaturesByOntology(SequenceOntologyI.CDS) + .isEmpty()) + { + return seqDss; + } } /* @@ -1938,10 +1946,12 @@ public class AlignmentUtils { /* * found a 3:1 mapping to the protein product which covers - * the whole dna sequence i.e. is from CDS; finally check it - * is from the dna start sequence + * the whole dna sequence i.e. is from CDS; finally check the CDS + * is mapped from the given dna start sequence */ SequenceI cdsSeq = map.getFromSeq(); + // todo this test is weak if seqMappings contains multiple mappings; + // we get away with it if transcript:cds relationship is 1:1 List dnaToCdsMaps = MappingUtils .findMappingsForSequence(cdsSeq, seqMappings); if (!dnaToCdsMaps.isEmpty()) @@ -2056,9 +2066,11 @@ public class AlignmentUtils protected static List propagateDBRefsToCDS(SequenceI cdsSeq, SequenceI contig, SequenceI proteinProduct, Mapping mapping) { + // gather direct refs from contig congruent with mapping List direct = new ArrayList<>(); HashSet directSources = new HashSet<>(); + if (contig.getDBRefs() != null) { for (DBRefEntry dbr : contig.getDBRefs()) @@ -2235,12 +2247,13 @@ public class AlignmentUtils int mappedDnaLength = MappingUtils.getLength(ranges); /* - * if not a whole number of codons, something is wrong, - * abort mapping + * if not a whole number of codons, truncate mapping */ - if (mappedDnaLength % CODON_LENGTH > 0) + int codonRemainder = mappedDnaLength % CODON_LENGTH; + if (codonRemainder > 0) { - return null; + mappedDnaLength -= codonRemainder; + MappingUtils.removeEndPositions(codonRemainder, ranges); } int proteinLength = proteinSeq.getLength(); diff --git a/src/jalview/analysis/Dna.java b/src/jalview/analysis/Dna.java index ef05a58..2ad8487 100644 --- a/src/jalview/analysis/Dna.java +++ b/src/jalview/analysis/Dna.java @@ -44,6 +44,7 @@ import jalview.util.ShiftList; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Iterator; import java.util.List; public class Dna @@ -56,19 +57,23 @@ public class Dna * 'final' variables describe the inputs to the translation, which should not * be modified. */ - final private List selection; + private final List selection; - final private String[] seqstring; + private final String[] seqstring; - final private int[] contigs; + private final Iterator contigs; - final private char gapChar; + private final char gapChar; - final private AlignmentAnnotation[] annotations; + private final AlignmentAnnotation[] annotations; - final private int dnaWidth; + private final int dnaWidth; - final private AlignmentI dataset; + private final AlignmentI dataset; + + private ShiftList vismapping; + + private int[] startcontigs; /* * Working variables for the translation. @@ -91,7 +96,7 @@ public class Dna * @param viewport * @param visibleContigs */ - public Dna(AlignViewportI viewport, int[] visibleContigs) + public Dna(AlignViewportI viewport, Iterator visibleContigs) { this.selection = Arrays.asList(viewport.getSequenceSelection()); this.seqstring = viewport.getViewAsString(true); @@ -100,6 +105,45 @@ public class Dna this.annotations = viewport.getAlignment().getAlignmentAnnotation(); this.dnaWidth = viewport.getAlignment().getWidth(); this.dataset = viewport.getAlignment().getDataset(); + initContigs(); + } + + /** + * Initialise contigs used as starting point for translateCodingRegion + */ + private void initContigs() + { + vismapping = new ShiftList(); // map from viscontigs to seqstring + // intervals + + int npos = 0; + int[] lastregion = null; + ArrayList tempcontigs = new ArrayList<>(); + while (contigs.hasNext()) + { + int[] region = contigs.next(); + if (lastregion == null) + { + vismapping.addShift(npos, region[0]); + } + else + { + // hidden region + vismapping.addShift(npos, region[0] - lastregion[1] + 1); + } + lastregion = region; + tempcontigs.add(region[0]); + tempcontigs.add(region[1]); + } + + startcontigs = new int[tempcontigs.size()]; + int i = 0; + for (Integer val : tempcontigs) + { + startcontigs[i] = val; + i++; + } + tempcontigs = null; } /** @@ -392,26 +436,13 @@ public class Dna List proteinSeqs) { List skip = new ArrayList<>(); - int skipint[] = null; - ShiftList vismapping = new ShiftList(); // map from viscontigs to seqstring - // intervals - int vc; - int[] scontigs = new int[contigs.length]; + int[] skipint = null; + int npos = 0; - for (vc = 0; vc < contigs.length; vc += 2) - { - if (vc == 0) - { - vismapping.addShift(npos, contigs[vc]); - } - else - { - // hidden region - vismapping.addShift(npos, contigs[vc] - contigs[vc - 1] + 1); - } - scontigs[vc] = contigs[vc]; - scontigs[vc + 1] = contigs[vc + 1]; - } + int vc = 0; + + int[] scontigs = new int[startcontigs.length]; + System.arraycopy(startcontigs, 0, scontigs, 0, startcontigs.length); // allocate a roughly sized buffer for the protein sequence StringBuilder protein = new StringBuilder(seqstring.length() / 2); diff --git a/src/jalview/analysis/SeqsetUtils.java b/src/jalview/analysis/SeqsetUtils.java index fabd0c6..2c077b6 100755 --- a/src/jalview/analysis/SeqsetUtils.java +++ b/src/jalview/analysis/SeqsetUtils.java @@ -20,6 +20,7 @@ */ package jalview.analysis; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; @@ -35,7 +36,7 @@ public class SeqsetUtils /** * Store essential properties of a sequence in a hashtable for later recovery - * Keys are Name, Start, End, SeqFeatures, PdbId + * Keys are Name, Start, End, SeqFeatures, PdbId, HMM * * @param seq * SequenceI @@ -69,6 +70,10 @@ public class SeqsetUtils (seq.getDatasetSequence() != null) ? seq.getDatasetSequence() : new Sequence("THISISAPLACEHOLDER", "")); } + if (seq.isHMMConsensusSequence()) + { + sqinfo.put("HMM", seq.getHMM()); + } return sqinfo; } @@ -97,6 +102,7 @@ public class SeqsetUtils Vector pdbid = (Vector) sqinfo.get("PdbId"); String description = (String) sqinfo.get("Description"); Sequence seqds = (Sequence) sqinfo.get("datasetSequence"); + HiddenMarkovModel hmm = (HiddenMarkovModel) sqinfo.get("HMM"); if (oldname == null) { namePresent = false; @@ -135,6 +141,11 @@ public class SeqsetUtils sq.setDatasetSequence(seqds); } + if (hmm != null) + { + sq.setHMM(new HiddenMarkovModel(hmm)); + sq.setIsHMMConsensusSequence(true); + } return namePresent; } diff --git a/src/jalview/api/AlignCalcWorkerI.java b/src/jalview/api/AlignCalcWorkerI.java index 85157c4..1387cba 100644 --- a/src/jalview/api/AlignCalcWorkerI.java +++ b/src/jalview/api/AlignCalcWorkerI.java @@ -39,8 +39,8 @@ public interface AlignCalcWorkerI extends Runnable /** * Updates the display of calculated annotation values (does not recalculate - * the values). This allows ßquick redraw of annotations when display settings - * are changed. + * the values). This allows a quick redraw of annotations when display + * settings are changed. */ void updateAnnotation(); diff --git a/src/jalview/api/AlignViewportI.java b/src/jalview/api/AlignViewportI.java index 931eba6..6b3cbe8 100644 --- a/src/jalview/api/AlignViewportI.java +++ b/src/jalview/api/AlignViewportI.java @@ -54,7 +54,7 @@ public interface AlignViewportI extends ViewStyleI * * @return */ - public ViewportRanges getRanges(); + ViewportRanges getRanges(); /** * calculate the height for visible annotation, revalidating bounds where @@ -62,7 +62,7 @@ public interface AlignViewportI extends ViewStyleI * * @return total height of annotation */ - public int calcPanelHeight(); + int calcPanelHeight(); /** * Answers true if the viewport has at least one column selected @@ -86,6 +86,12 @@ public interface AlignViewportI extends ViewStyleI boolean isNormaliseSequenceLogo(); + boolean isShowInformationHistogram(); + + boolean isShowHMMSequenceLogo(); + + boolean isNormaliseHMMSequenceLogo(); + ColourSchemeI getGlobalColourScheme(); /** @@ -100,7 +106,7 @@ public interface AlignViewportI extends ViewStyleI ColumnSelection getColumnSelection(); - ProfilesI getSequenceConsensusHash(); + ProfilesI getConsensusProfiles(); /** * Get consensus data table for the cDNA complement of this alignment (if any) @@ -113,6 +119,8 @@ public interface AlignViewportI extends ViewStyleI boolean isIgnoreGapsConsensus(); + boolean isIgnoreBelowBackground(); + boolean isCalculationInProgress(AlignmentAnnotation alignmentAnnotation); AlignmentAnnotation getAlignmentQualityAnnot(); @@ -131,7 +139,7 @@ public interface AlignViewportI extends ViewStyleI * * @return */ - AlignmentAnnotation getAlignmentGapAnnotation(); + AlignmentAnnotation getOccupancyAnnotation(); /** * get the container for cDNA complement consensus annotation @@ -170,7 +178,7 @@ public interface AlignViewportI extends ViewStyleI * * @param hconsensus */ - void setSequenceConsensusHash(ProfilesI hconsensus); + void setConsensusProfiles(ProfilesI hconsensus); /** * Set the cDNA complement consensus for the viewport @@ -380,14 +388,14 @@ public interface AlignViewportI extends ViewStyleI * * @return a copy of this view's current display settings */ - public ViewStyleI getViewStyle(); + ViewStyleI getViewStyle(); /** * update the view's display settings with the given style set * * @param settingsForView */ - public void setViewStyle(ViewStyleI settingsForView); + void setViewStyle(ViewStyleI settingsForView); /** * Returns a viewport which holds the cDna for this (protein), or vice versa, @@ -431,7 +439,7 @@ public interface AlignViewportI extends ViewStyleI */ void setFollowHighlight(boolean b); - public void applyFeaturesStyle(FeatureSettingsModelI featureSettings); + void applyFeaturesStyle(FeatureSettingsModelI featureSettings); /** * check if current selection group is defined on the view, or is simply a @@ -487,7 +495,21 @@ public interface AlignViewportI extends ViewStyleI @Override void setProteinFontAsCdna(boolean b); - public abstract TreeModel getCurrentTree(); + void setHmmProfiles(ProfilesI info); + + ProfilesI getHmmProfiles(); + + /** + * Registers and starts a worker thread to calculate Information Content + * annotation, if it is not already registered + * + * @param ap + */ + void initInformationWorker(AlignmentViewPanel ap); + + boolean isInfoLetterHeight(); + + abstract TreeModel getCurrentTree(); - public abstract void setCurrentTree(TreeModel tree); + abstract void setCurrentTree(TreeModel tree); } diff --git a/src/jalview/api/structures/JalviewStructureDisplayI.java b/src/jalview/api/structures/JalviewStructureDisplayI.java index fd66388..b4612cf 100644 --- a/src/jalview/api/structures/JalviewStructureDisplayI.java +++ b/src/jalview/api/structures/JalviewStructureDisplayI.java @@ -62,4 +62,11 @@ public interface JalviewStructureDisplayI */ void setJalviewColourScheme(ColourSchemeI colourScheme); + /** + * + * @return true if all background sequence/structure binding threads have + * completed for this viewer instance + */ + boolean hasMapping(); + } diff --git a/src/jalview/appletgui/AlignFrame.java b/src/jalview/appletgui/AlignFrame.java index fe6b8d9..28aabe1 100644 --- a/src/jalview/appletgui/AlignFrame.java +++ b/src/jalview/appletgui/AlignFrame.java @@ -234,6 +234,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, alignPanel); viewport.updateConservation(alignPanel); viewport.updateConsensus(alignPanel); + viewport.initInformationWorker(alignPanel); displayNonconservedMenuItem.setState(viewport.getShowUnconserved()); followMouseOverFlag.setState(viewport.isFollowHighlight()); @@ -1906,7 +1907,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, static StringBuffer copiedSequences; - static Vector copiedHiddenColumns; + static HiddenColumns copiedHiddenColumns; protected void copy_actionPerformed() { @@ -1930,14 +1931,14 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, if (viewport.hasHiddenColumns() && viewport.getSelectionGroup() != null) { - copiedHiddenColumns = new Vector<>(viewport.getAlignment() - .getHiddenColumns().getHiddenColumnsCopy()); int hiddenOffset = viewport.getSelectionGroup().getStartRes(); - for (int[] region : copiedHiddenColumns) - { - region[0] = region[0] - hiddenOffset; - region[1] = region[1] - hiddenOffset; - } + int hiddenCutoff = viewport.getSelectionGroup().getEndRes(); + + // create new HiddenColumns object with copy of hidden regions + // between startRes and endRes, offset by startRes + copiedHiddenColumns = new HiddenColumns( + viewport.getAlignment().getHiddenColumns(), hiddenOffset, + hiddenCutoff, hiddenOffset); } else { @@ -2006,13 +2007,13 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, { try { - if (copiedSequences == null) { return; } - StringTokenizer st = new StringTokenizer(copiedSequences.toString()); + StringTokenizer st = new StringTokenizer(copiedSequences.toString(), + "\t"); Vector seqs = new Vector(); while (st.hasMoreElements()) { @@ -2044,14 +2045,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener, } AlignFrame af = new AlignFrame(new Alignment(newSeqs), viewport.applet, newtitle, false); - if (copiedHiddenColumns != null) - { - for (int i = 0; i < copiedHiddenColumns.size(); i++) - { - int[] region = copiedHiddenColumns.elementAt(i); - af.viewport.hideColumns(region[0], region[1]); - } - } + af.viewport.setHiddenColumns(copiedHiddenColumns); jalview.bin.JalviewLite.addFrame(af, newtitle, frameWidth, frameHeight); diff --git a/src/jalview/appletgui/AlignViewport.java b/src/jalview/appletgui/AlignViewport.java index 262948d..753e972 100644 --- a/src/jalview/appletgui/AlignViewport.java +++ b/src/jalview/appletgui/AlignViewport.java @@ -1,6 +1,6 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * * This file is part of Jalview. * @@ -25,14 +25,11 @@ import jalview.api.FeatureSettingsModelI; import jalview.bin.JalviewLite; import jalview.commands.CommandI; import jalview.datamodel.AlignmentI; -import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; -import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; -import jalview.datamodel.SequenceI; import jalview.renderer.ResidueShader; import jalview.schemes.ColourSchemeProperty; import jalview.schemes.UserColourScheme; @@ -59,6 +56,12 @@ public class AlignViewport extends AlignmentViewport private AnnotationColumnChooser annotationColumnSelectionState; + java.awt.Frame nullFrame; + + protected FeatureSettings featureSettings = null; + + private float heightScale = 1, widthScale = 1; + public AlignViewport(AlignmentI al, JalviewLite applet) { super(al); @@ -200,10 +203,11 @@ public class AlignViewport extends AlignmentViewport if (colour != null) { residueShading = new ResidueShader( - ColourSchemeProperty.getColourScheme(alignment, colour)); + ColourSchemeProperty.getColourScheme(getAlignment(), + colour)); if (residueShading != null) { - residueShading.setConsensus(hconsensus); + residueShading.setConsensus(consensusProfiles); } } @@ -214,15 +218,8 @@ public class AlignViewport extends AlignmentViewport } } initAutoAnnotation(); - } - java.awt.Frame nullFrame; - - protected FeatureSettings featureSettings = null; - - private float heightScale = 1, widthScale = 1; - /** * {@inheritDoc} */ @@ -302,17 +299,6 @@ public class AlignViewport extends AlignmentViewport .getStructureSelectionManager(applet); } - @Override - public boolean isNormaliseSequenceLogo() - { - return normaliseSequenceLogo; - } - - public void setNormaliseSequenceLogo(boolean state) - { - normaliseSequenceLogo = state; - } - /** * * @return true if alignment characters should be displayed diff --git a/src/jalview/appletgui/AlignmentPanel.java b/src/jalview/appletgui/AlignmentPanel.java index 270b2f7..730434f 100644 --- a/src/jalview/appletgui/AlignmentPanel.java +++ b/src/jalview/appletgui/AlignmentPanel.java @@ -421,8 +421,8 @@ public class AlignmentPanel extends Panel if (av.hasHiddenColumns()) { AlignmentI al = av.getAlignment(); - start = al.getHiddenColumns().findColumnPosition(ostart); - end = al.getHiddenColumns().findColumnPosition(end); + start = al.getHiddenColumns().absoluteToVisibleColumn(ostart); + end = al.getHiddenColumns().absoluteToVisibleColumn(end); if (start == end) { if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart)) @@ -554,8 +554,8 @@ public class AlignmentPanel extends Panel // this is called after loading new annotation onto alignment if (alignFrame.getSize().height == 0) { - System.out.println( - "adjustAnnotationHeight frame size zero NEEDS FIXING"); + // panel not laid out yet? + return; } fontChanged(); validateAnnotationDimensions(true); @@ -675,7 +675,7 @@ public class AlignmentPanel extends Panel if (av.hasHiddenColumns()) { width = av.getAlignment().getHiddenColumns() - .findColumnPosition(width); + .absoluteToVisibleColumn(width); } if (x < 0) { diff --git a/src/jalview/appletgui/AnnotationLabels.java b/src/jalview/appletgui/AnnotationLabels.java index c049326..71dc3da 100755 --- a/src/jalview/appletgui/AnnotationLabels.java +++ b/src/jalview/appletgui/AnnotationLabels.java @@ -23,6 +23,7 @@ package jalview.appletgui; import jalview.analysis.AlignmentUtils; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.util.MessageManager; @@ -51,13 +52,22 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Arrays; import java.util.Collections; -import java.util.Vector; public class AnnotationLabels extends Panel implements ActionListener, MouseListener, MouseMotionListener { Image image; + /** + * width in pixels within which height adjuster arrows are shown and active + */ + private static final int HEIGHT_ADJUSTER_WIDTH = 50; + + /** + * height in pixels for allowing height adjuster to be active + */ + private static int HEIGHT_ADJUSTER_HEIGHT = 10; + boolean active = false; AlignmentPanel ap; @@ -93,23 +103,6 @@ public class AnnotationLabels extends Panel this.ap = ap; this.av = ap.av; setLayout(null); - - /** - * this retrieves the adjustable height glyph from resources. we don't use - * it at the moment. java.net.URL url = - * getClass().getResource("/images/idwidth.gif"); Image temp = null; - * - * if (url != null) { temp = - * java.awt.Toolkit.getDefaultToolkit().createImage(url); } - * - * try { MediaTracker mt = new MediaTracker(this); mt.addImage(temp, 0); - * mt.waitForID(0); } catch (Exception ex) { } - * - * BufferedImage bi = new BufferedImage(temp.getHeight(this), - * temp.getWidth(this), BufferedImage.TYPE_INT_RGB); Graphics2D g = - * (Graphics2D) bi.getGraphics(); g.rotate(Math.toRadians(90)); - * g.drawImage(temp, 0, -bi.getWidth(this), this); image = (Image) bi; - */ addMouseListener(this); addMouseMotionListener(this); } @@ -209,7 +202,9 @@ public class AnnotationLabels extends Panel } else if (evt.getActionCommand().equals(COPYCONS_SEQ)) { - SequenceI cons = av.getConsensusSeq(); + SequenceGroup group = aa[selectedRow].groupRef; + SequenceI cons = group == null ? av.getConsensusSeq() + : group.getConsensusSeq(); if (cons != null) { copy_annotseqtoclipboard(cons); @@ -269,7 +264,8 @@ public class AnnotationLabels extends Panel @Override public void mouseMoved(MouseEvent evt) { - resizePanel = evt.getY() < 10 && evt.getX() < 14; + resizePanel = evt.getY() < HEIGHT_ADJUSTER_HEIGHT + && evt.getX() < HEIGHT_ADJUSTER_WIDTH; setCursor(Cursor.getPredefinedCursor( resizePanel ? Cursor.S_RESIZE_CURSOR : Cursor.DEFAULT_CURSOR)); int row = getSelectedRow(evt.getY() + scrollOffset); @@ -538,7 +534,7 @@ public class AnnotationLabels extends Panel MessageManager.getString("label.ignore_gaps_consensus"), (aa[selectedRow].groupRef != null) ? aa[selectedRow].groupRef - .getIgnoreGapsConsensus() + .isIgnoreGapsConsensus() : ap.av.isIgnoreGapsConsensus()); final AlignmentAnnotation aaa = aa[selectedRow]; cbmi.addItemListener(new ItemListener() @@ -849,8 +845,8 @@ public class AnnotationLabels extends Panel + "\t" + sq.getSequenceAsString() + "\n"); if (av.hasHiddenColumns()) { - jalview.appletgui.AlignFrame.copiedHiddenColumns = new Vector<>( - av.getAlignment().getHiddenColumns().getHiddenColumnsCopy()); + jalview.appletgui.AlignFrame.copiedHiddenColumns = new HiddenColumns( + av.getAlignment().getHiddenColumns()); } } @@ -909,14 +905,8 @@ public class AnnotationLabels extends Panel } } g.translate(0, +scrollOffset); - if (resizePanel) - { - // g.setColor(Color.red); - // g.setPaintMode(); - // g.drawLine(2, 8, 5, 2); - // g.drawLine(5, 2, 8, 8); - } - else if (!dragCancelled && dragEvent != null && aa != null) + + if (!resizePanel && !dragCancelled && dragEvent != null && aa != null) { g.setColor(Color.lightGray); g.drawString(aa[selectedRow].label, dragEvent.getX(), diff --git a/src/jalview/appletgui/AnnotationPanel.java b/src/jalview/appletgui/AnnotationPanel.java index 50a9e33..50bc184 100755 --- a/src/jalview/appletgui/AnnotationPanel.java +++ b/src/jalview/appletgui/AnnotationPanel.java @@ -480,7 +480,7 @@ public class AnnotationPanel extends Panel if (av.hasHiddenColumns()) { column = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(column); + .visibleToAbsoluteColumn(column); } if (row > -1 && column < aa[row].annotations.length diff --git a/src/jalview/appletgui/FeatureSettings.java b/src/jalview/appletgui/FeatureSettings.java index ad04171..a60aacd 100755 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@ -66,7 +66,7 @@ import java.util.Set; public class FeatureSettings extends Panel implements ItemListener, MouseListener, MouseMotionListener, - ActionListener, AdjustmentListener, FeatureSettingsControllerI + AdjustmentListener, FeatureSettingsControllerI { FeatureRenderer fr; @@ -121,8 +121,17 @@ public class FeatureSettings extends Panel add(scrollPane, BorderLayout.CENTER); } - Button invert = new Button("Invert Selection"); - invert.addActionListener(this); + Button invert = new Button( + MessageManager.getString("label.invert_selection")); + invert.addActionListener(new ActionListener() + { + + @Override + public void actionPerformed(ActionEvent e) + { + invertSelection(); + } + }); Panel lowerPanel = new Panel(new GridLayout(2, 1, 5, 10)); lowerPanel.add(invert); @@ -546,8 +555,7 @@ public class FeatureSettings extends Panel } } - @Override - public void actionPerformed(ActionEvent evt) + protected void invertSelection() { for (int i = 0; i < featurePanel.getComponentCount(); i++) { diff --git a/src/jalview/appletgui/IdCanvas.java b/src/jalview/appletgui/IdCanvas.java index f5ea12e..296f898 100755 --- a/src/jalview/appletgui/IdCanvas.java +++ b/src/jalview/appletgui/IdCanvas.java @@ -286,7 +286,7 @@ public class IdCanvas extends Panel implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/appletgui/IdwidthAdjuster.java b/src/jalview/appletgui/IdwidthAdjuster.java index e9722fe..2602268 100755 --- a/src/jalview/appletgui/IdwidthAdjuster.java +++ b/src/jalview/appletgui/IdwidthAdjuster.java @@ -20,10 +20,9 @@ */ package jalview.appletgui; +import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Image; import java.awt.Panel; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @@ -36,20 +35,13 @@ public class IdwidthAdjuster extends Panel int oldX = 0; - Image image; - AlignmentPanel ap; public IdwidthAdjuster(AlignmentPanel ap) { setLayout(null); this.ap = ap; - java.net.URL url = getClass().getResource("/images/idwidth.gif"); - if (url != null) - { - image = java.awt.Toolkit.getDefaultToolkit().getImage(url); - } - + setBackground(Color.WHITE); addMouseListener(this); addMouseMotionListener(this); } @@ -129,19 +121,4 @@ public class IdwidthAdjuster extends Panel public void mouseClicked(MouseEvent evt) { } - - @Override - public void paint(Graphics g) - { - // g.setColor(Color.white); - // g.fillRect(0, 0, getSize().width, getSize().height); - // if (active) - // { - // if (image != null) - // { - // g.drawImage(image, getSize().width - 20, 2, this); - // } - // } - } - } diff --git a/src/jalview/appletgui/OverviewCanvas.java b/src/jalview/appletgui/OverviewCanvas.java index 9597b44..ecc90b8 100644 --- a/src/jalview/appletgui/OverviewCanvas.java +++ b/src/jalview/appletgui/OverviewCanvas.java @@ -132,7 +132,6 @@ public class OverviewCanvas extends Component od.getColumns(av.getAlignment())); mg.translate(0, -od.getSequencesHeight()); } - System.gc(); if (restart) { diff --git a/src/jalview/appletgui/OverviewPanel.java b/src/jalview/appletgui/OverviewPanel.java index 8ce597d..e09280f 100755 --- a/src/jalview/appletgui/OverviewPanel.java +++ b/src/jalview/appletgui/OverviewPanel.java @@ -69,7 +69,7 @@ public class OverviewPanel extends Panel implements Runnable, od = new OverviewDimensionsShowHidden(av.getRanges(), (av.isShowAnnotation() - && av.getSequenceConsensusHash() != null)); + && av.getConsensusProfiles() != null)); oviewCanvas = new OverviewCanvas(od, av); setLayout(new BorderLayout()); @@ -155,6 +155,10 @@ public class OverviewPanel extends Panel implements Runnable, if (!od.isPositionInBox(evt.getX(), evt.getY())) { draggingBox = false; + + // display drag cursor at mouse position + setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment().getHiddenSequences(), av.getAlignment().getHiddenColumns()); @@ -172,6 +176,7 @@ public class OverviewPanel extends Panel implements Runnable, @Override public void mouseReleased(MouseEvent evt) { + draggingBox = false; } @Override diff --git a/src/jalview/appletgui/ScalePanel.java b/src/jalview/appletgui/ScalePanel.java index 04fb22b..c91449f 100755 --- a/src/jalview/appletgui/ScalePanel.java +++ b/src/jalview/appletgui/ScalePanel.java @@ -42,6 +42,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; +import java.util.Iterator; import java.util.List; public class ScalePanel extends Panel @@ -86,7 +87,7 @@ public class ScalePanel extends Panel if (av.hasHiddenColumns()) { - res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); + res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x); } else { @@ -173,7 +174,7 @@ public class ScalePanel extends Panel }); pop.add(item); - if (av.getAlignment().getHiddenColumns().hasManyHiddenColumns()) + if (av.getAlignment().getHiddenColumns().hasMultiHiddenColumnRegions()) { item = new MenuItem(MessageManager.getString("action.reveal_all")); item.addActionListener(new ActionListener() @@ -234,7 +235,7 @@ public class ScalePanel extends Panel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } if (!stretchingGroup) @@ -275,7 +276,7 @@ public class ScalePanel extends Panel int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); res = Math.max(0, res); - res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res); res = Math.min(res, av.getAlignment().getWidth() - 1); min = Math.min(res, min); max = Math.max(res, max); @@ -377,7 +378,7 @@ public class ScalePanel extends Panel { if (hidden.isVisible(sel)) { - sel = hidden.findColumnPosition(sel); + sel = hidden.absoluteToVisibleColumn(sel); } else { @@ -436,24 +437,17 @@ public class ScalePanel extends Panel if (av.getShowHiddenMarkers()) { int widthx = 1 + endx - startx; - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator it = hidden.getStartRegionIterator(startx, + startx + widthx + 1); + while (it.hasNext()) { - - res = pos - startx; - - if (res < 0 || res > widthx) - { - continue; - } + res = it.next() - startx; gg.fillPolygon( new int[] - { -1 + res * avCharWidth - avcharHeight / 4, - -1 + res * avCharWidth + avcharHeight / 4, - -1 + res * avCharWidth }, - new int[] - { y, y, y + 2 * yOf }, 3); + { -1 + res * avCharWidth - avcharHeight / 4, -1 + res * avCharWidth + avcharHeight / 4, + -1 + res * avCharWidth }, new int[] + { y, y, y + 2 * yOf }, 3); } } } diff --git a/src/jalview/appletgui/SeqCanvas.java b/src/jalview/appletgui/SeqCanvas.java index 2420cf7..35d73de 100755 --- a/src/jalview/appletgui/SeqCanvas.java +++ b/src/jalview/appletgui/SeqCanvas.java @@ -25,6 +25,7 @@ import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.datamodel.VisibleContigsIterator; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.viewmodel.AlignmentViewport; @@ -37,7 +38,7 @@ import java.awt.Graphics; import java.awt.Image; import java.awt.Panel; import java.beans.PropertyChangeEvent; -import java.util.List; +import java.util.Iterator; public class SeqCanvas extends Panel implements ViewportListenerI { @@ -130,16 +131,16 @@ public class SeqCanvas extends Panel implements ViewportListenerI if (av.hasHiddenColumns()) { startx = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(startx); + .visibleToAbsoluteColumn(startx); endx = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(endx); + .visibleToAbsoluteColumn(endx); } int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } // WEST SCALE @@ -180,7 +181,7 @@ public class SeqCanvas extends Panel implements ViewportListenerI if (av.hasHiddenColumns()) { endx = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(endx); + .visibleToAbsoluteColumn(endx); } SequenceI seq; @@ -417,71 +418,71 @@ public class SeqCanvas extends Panel implements ViewportListenerI int canvasHeight, int startRes) { AlignmentI al = av.getAlignment(); - + FontMetrics fm = getFontMetrics(av.getFont()); - + LABEL_EAST = 0; LABEL_WEST = 0; - + if (av.getScaleRightWrapped()) { LABEL_EAST = fm.stringWidth(getMask()); } - + if (av.getScaleLeftWrapped()) { LABEL_WEST = fm.stringWidth(getMask()); } - + int hgap = avcharHeight; if (av.getScaleAboveWrapped()) { hgap += avcharHeight; } - + int cWidth = (canvasWidth - LABEL_EAST - LABEL_WEST) / avcharWidth; int cHeight = av.getAlignment().getHeight() * avcharHeight; - + av.setWrappedWidth(cWidth); - + av.getRanges().setViewportStartAndWidth(startRes, cWidth); - + int endx; int ypos = hgap; - + int maxwidth = av.getAlignment().getWidth(); - + if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } - + while ((ypos <= canvasHeight) && (startRes < maxwidth)) { endx = startRes + cWidth - 1; - + if (endx > maxwidth) { endx = maxwidth; } - + g.setColor(Color.black); - + if (av.getScaleLeftWrapped()) { drawWestScale(g, startRes, endx, ypos); } - + if (av.getScaleRightWrapped()) { g.translate(canvasWidth - LABEL_EAST, 0); drawEastScale(g, startRes, endx, ypos); g.translate(-(canvasWidth - LABEL_EAST), 0); } - + g.translate(LABEL_WEST, 0); - + if (av.getScaleAboveWrapped()) { drawNorthScale(g, startRes, endx, ypos); @@ -491,37 +492,27 @@ public class SeqCanvas extends Panel implements ViewportListenerI HiddenColumns hidden = av.getAlignment().getHiddenColumns(); g.setColor(Color.blue); int res; - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator it = hidden.getStartRegionIterator(startRes, + endx + 1); + while (it.hasNext()) { - res = pos - startRes; - - if (res < 0 || res > endx - startRes) - { - continue; - } - + res = it.next() - startRes; gg.fillPolygon( new int[] - { res * avcharWidth - avcharHeight / 4, - res * avcharWidth + avcharHeight / 4, - res * avcharWidth }, + { res * avcharWidth - avcharHeight / 4, res * avcharWidth + avcharHeight / 4, res * avcharWidth }, new int[] - { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2), - ypos - (avcharHeight / 2) + 8 }, - 3); - + { ypos - (avcharHeight / 2), ypos - (avcharHeight / 2), ypos - (avcharHeight / 2) + 8 }, 3); } } - + if (g.getClip() == null) { g.setClip(0, 0, cWidth * avcharWidth, canvasHeight); } - + drawPanel(g, startRes, endx, 0, al.getHeight() - 1, ypos); g.setClip(null); - + if (av.isShowAnnotation()) { g.translate(0, cHeight + ypos + 4); @@ -529,17 +520,17 @@ public class SeqCanvas extends Panel implements ViewportListenerI { annotations = new AnnotationPanel(av); } - + annotations.drawComponent(g, startRes, endx + 1); g.translate(0, -cHeight - ypos - 4); } g.translate(-LABEL_WEST, 0); - + ypos += cHeight + getAnnotationHeight() + hgap; - + startRes += cWidth; } - + } AnnotationPanel annotations; @@ -570,70 +561,44 @@ public class SeqCanvas extends Panel implements ViewportListenerI else { int screenY = 0; - final int screenYMax = endRes - startRes; - int blockStart = startRes; - int blockEnd = endRes; - - if (av.hasHiddenColumns()) - { - HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - for (int[] region : hidden.getHiddenColumnsCopy()) - { - int hideStart = region[0]; - int hideEnd = region[1]; - - if (hideStart <= blockStart) - { - blockStart += (hideEnd - hideStart) + 1; - continue; - } - - /* - * draw up to just before the next hidden region, or the end of - * the visible region, whichever comes first - */ - blockEnd = Math.min(hideStart - 1, blockStart + screenYMax - - screenY); - - g1.translate(screenY * avcharWidth, 0); + int blockStart; + int blockEnd; - draw(g1, blockStart, blockEnd, startSeq, endSeq, offset); + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + VisibleContigsIterator regions = (VisibleContigsIterator) hidden + .getVisContigsIterator(startRes, endRes + 1, true); - /* - * draw the downline of the hidden column marker (ScalePanel draws the - * triangle on top) if we reached it - */ - if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1) - { - g1.setColor(Color.blue); - g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1, - 0 + offset, - (blockEnd - blockStart + 1) * avcharWidth - 1, - (endSeq - startSeq + 1) * avcharHeight + offset); - } - - g1.translate(-screenY * avcharWidth, 0); - screenY += blockEnd - blockStart + 1; - blockStart = hideEnd + 1; - - if (screenY > screenYMax) - { - // already rendered last block - return; - } - } - } - if (screenY <= screenYMax) + while (regions.hasNext()) { - // remaining visible region to render - blockEnd = blockStart + (endRes - startRes) - screenY; + int[] region = regions.next(); + blockEnd = region[1]; + blockStart = region[0]; + + /* + * draw up to just before the next hidden region, or the end of + * the visible region, whichever comes first + */ g1.translate(screenY * avcharWidth, 0); + draw(g1, blockStart, blockEnd, startSeq, endSeq, offset); + /* + * draw the downline of the hidden column marker (ScalePanel draws the + * triangle on top) if we reached it + */ + if (av.getShowHiddenMarkers() + && (regions.hasNext() || regions.endsAtHidden())) + { + g1.setColor(Color.blue); + g1.drawLine((blockEnd - blockStart + 1) * avcharWidth - 1, + 0 + offset, (blockEnd - blockStart + 1) * avcharWidth - 1, + (endSeq - startSeq + 1) * avcharHeight + offset); + } + g1.translate(-screenY * avcharWidth, 0); + screenY += blockEnd - blockStart + 1; } } - } // int startRes, int endRes, int startSeq, int endSeq, int x, int y, diff --git a/src/jalview/appletgui/SeqPanel.java b/src/jalview/appletgui/SeqPanel.java index d74bbb7..285c737 100644 --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@ -647,7 +647,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } return res; @@ -1123,9 +1123,9 @@ public class SeqPanel extends Panel implements MouseMotionListener, { fixedColumns = true; int y1 = av.getAlignment().getHiddenColumns() - .getHiddenBoundaryLeft(startres); + .getNextHiddenBoundary(true, startres); int y2 = av.getAlignment().getHiddenColumns() - .getHiddenBoundaryRight(startres); + .getNextHiddenBoundary(false, startres); if ((insertGap && startres > y1 && lastres < y1) || (!insertGap && startres < y2 && lastres > y2)) @@ -1197,7 +1197,8 @@ public class SeqPanel extends Panel implements MouseMotionListener, if (sg.getSize() == av.getAlignment().getHeight()) { if ((av.hasHiddenColumns() && startres < av.getAlignment() - .getHiddenColumns().getHiddenBoundaryRight(startres))) + .getHiddenColumns() + .getNextHiddenBoundary(false, startres))) { endEditing(); return; @@ -1497,7 +1498,7 @@ public class SeqPanel extends Panel implements MouseMotionListener, } // always do this - annotation has own state // but defer colourscheme update until hidden sequences are passed in - boolean vischange = stretchGroup.recalcConservation(true); + boolean vischange = stretchGroup.recalcAnnotations(true); // here we rely on stretchGroup == av.getSelection() needOverviewUpdate |= vischange && av.isSelectionDefinedGroup() && afterDrag; diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index dc50843..dcd6546 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -281,7 +281,7 @@ public class Cache @Override public synchronized Enumeration keys() { - return Collections.enumeration(new TreeSet(super.keySet())); + return Collections.enumeration(new TreeSet<>(super.keySet())); } }; @@ -334,7 +334,10 @@ public class Cache } } - /** Called when Jalview is started */ + /** + * Loads properties from the given properties file. Any existing properties + * are first cleared. + */ public static void loadProperties(String propsFile) { propertiesFile = propsFile; @@ -369,6 +372,7 @@ public class Cache { fis = new FileInputStream(propertiesFile); } + applicationProperties.clear(); applicationProperties.load(fis); // remove any old build properties @@ -621,14 +625,14 @@ public class Cache * @param obj * String value of property * - * @return String value of property + * @return previous value of property (or null) */ - public static String setProperty(String key, String obj) + public static Object setProperty(String key, String obj) { - + Object oldValue = null; try { - applicationProperties.setProperty(key, obj); + oldValue = applicationProperties.setProperty(key, obj); if (!propsAreReadOnly) { FileOutputStream out = new FileOutputStream(propertiesFile); @@ -640,7 +644,7 @@ public class Cache System.out.println( "Error setting property: " + key + " " + obj + "\n" + ex); } - return obj; + return oldValue; } /** diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index 9ec0033..bc93c37 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -20,9 +20,6 @@ */ package jalview.bin; -import groovy.lang.Binding; -import groovy.util.GroovyScriptEngine; - import jalview.ext.so.SequenceOntology; import jalview.gui.AlignFrame; import jalview.gui.Desktop; @@ -66,6 +63,9 @@ import java.util.Vector; import javax.swing.UIManager; +import groovy.lang.Binding; +import groovy.util.GroovyScriptEngine; + /** * Main class for Jalview Application
    *
    @@ -175,6 +175,8 @@ public class Jalview * * @param args * open filename + * @throws InterruptedException + * @throws IOException */ public static void main(String[] args) { @@ -184,6 +186,8 @@ public class Jalview /** * @param args + * @throws InterruptedException + * @throws IOException */ void doMain(String[] args) { @@ -970,7 +974,7 @@ public class Jalview } try { - Map vbinding = new HashMap(); + Map vbinding = new HashMap<>(); vbinding.put("Jalview", this); if (af != null) { @@ -1036,7 +1040,7 @@ public class Jalview + nickname + "|" + url); if (source == null) { - source = new Vector(); + source = new Vector<>(); } source.addElement(nickname); } @@ -1054,7 +1058,7 @@ public class Jalview System.out.println("adding source '" + data + "'"); if (source == null) { - source = new Vector(); + source = new Vector<>(); } source.addElement(data); } diff --git a/src/jalview/bin/JalviewLite.java b/src/jalview/bin/JalviewLite.java index 6504290..a60496c 100644 --- a/src/jalview/bin/JalviewLite.java +++ b/src/jalview/bin/JalviewLite.java @@ -31,7 +31,6 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.ColumnSelection; -import jalview.datamodel.HiddenColumns; import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; @@ -471,7 +470,7 @@ public class JalviewLite extends Applet SequenceI rs = sel.getSequenceAt(0); start = rs.findIndex(start); end = rs.findIndex(end); - List cs = new ArrayList(csel.getSelected()); + List cs = new ArrayList<>(csel.getSelected()); csel.clear(); for (Integer selectedCol : cs) { @@ -921,7 +920,7 @@ public class JalviewLite extends Applet setMouseoverListener(currentAlignFrame, listener); } - private Vector javascriptListeners = new Vector(); + private Vector javascriptListeners = new Vector<>(); /* * (non-Javadoc) @@ -2165,8 +2164,8 @@ public class JalviewLite extends Applet else { param = st.nextToken(); - List tmp = new ArrayList(); - List tmp2 = new ArrayList(); + List tmp = new ArrayList<>(); + List tmp2 = new ArrayList<>(); while (st.hasMoreTokens()) { @@ -2279,12 +2278,9 @@ public class JalviewLite extends Applet JnetAnnotationMaker.add_annotation(predictions, alignFrame.viewport.getAlignment(), 0, false); // false == do not add sequence profile from concise output - SequenceI repseq = alignFrame.viewport.getAlignment() - .getSequenceAt(0); - alignFrame.viewport.getAlignment().setSeqrep(repseq); - HiddenColumns cs = new HiddenColumns(); - cs.hideInsertionsFor(repseq); - alignFrame.viewport.getAlignment().setHiddenColumns(cs); + + alignFrame.viewport.getAlignment().setupJPredAlignment(); + alignFrame.alignPanel.fontChanged(); alignFrame.alignPanel.setScrollValues(0, 0); result = true; @@ -2802,9 +2798,9 @@ public class JalviewLite extends Applet // callInitCallback(); } - private Hashtable jshashes = new Hashtable(); + private Hashtable jshashes = new Hashtable<>(); - private Hashtable> jsmessages = new Hashtable>(); + private Hashtable> jsmessages = new Hashtable<>(); public void setJsMessageSet(String messageclass, String viewId, String[] colcommands) @@ -2812,7 +2808,7 @@ public class JalviewLite extends Applet Hashtable msgset = jsmessages.get(messageclass); if (msgset == null) { - msgset = new Hashtable(); + msgset = new Hashtable<>(); jsmessages.put(messageclass, msgset); } msgset.put(viewId, colcommands); diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index f268d37..6b100ea 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -29,10 +29,12 @@ import jalview.util.MessageManager; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,7 +51,9 @@ public class Alignment implements AlignmentI { private Alignment dataset; - protected List sequences; + private List sequences; + + private SequenceI hmmConsensus; protected List groups; @@ -198,6 +202,7 @@ public class Alignment implements AlignmentI return sequences.get(i); } } + return null; } @@ -288,6 +293,32 @@ public class Alignment implements AlignmentI } /** + * Inserts a sequence at a point in the alignment. + * + * @param i + * the index of the position the sequence is to be inserted in. + */ + @Override + public void insertSequenceAt(int i, SequenceI snew) + { + synchronized (sequences) + { + if (sequences.size() > i) + { + sequences.add(i, snew); + return; + + } + else + { + sequences.add(snew); + hiddenSequences.adjustHeightSequenceAdded(); + } + return; + } + } + + /** * DOCUMENT ME! * * @return DOCUMENT ME! @@ -706,7 +737,7 @@ public class Alignment implements AlignmentI public int getWidth() { int maxLength = -1; - + for (int i = 0; i < sequences.size(); i++) { if (getSequenceAt(i).getLength() > maxLength) @@ -714,9 +745,34 @@ public class Alignment implements AlignmentI maxLength = getSequenceAt(i).getLength(); } } - + return maxLength; } + /* + @Override + public int getWidth() + { + final Wrapper temp = new Wrapper(); + + forEachSequence(new Consumer() + { + @Override + public void accept(SequenceI s) + { + if (s.getLength() > temp.inner) + { + temp.inner = s.getLength(); + } + } + }, 0, sequences.size() - 1); + + return temp.inner; + } + + public static class Wrapper + { + public int inner; + }*/ /** * DOCUMENT ME! @@ -1603,7 +1659,10 @@ public class Alignment implements AlignmentI AlignmentAnnotation annot = new AlignmentAnnotation(name, name, new Annotation[1], 0f, 0f, AlignmentAnnotation.BAR_GRAPH); annot.hasText = false; - annot.setCalcId(new String(calcId)); + if (calcId != null) + { + annot.setCalcId(calcId); + } annot.autoCalculated = autoCalc; if (seqRef != null) { @@ -1895,4 +1954,128 @@ public class Alignment implements AlignmentI { hiddenCols = cols; } + + @Override + public SequenceI getHmmConsensus() + { + return hmmConsensus; + } + + @Override + public void setHmmConsensus(SequenceI hmmConsensus) + { + this.hmmConsensus = hmmConsensus; + } + + @Override + public void setupJPredAlignment() + { + SequenceI repseq = getSequenceAt(0); + setSeqrep(repseq); + HiddenColumns cs = new HiddenColumns(); + cs.hideList(repseq.getInsertions()); + setHiddenColumns(cs); + } + + @Override + public HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentView input) + { + int profsqpos = 0; + + char gc = getGapCharacter(); + Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); + HiddenColumns nview = (HiddenColumns) alandhidden[1]; + SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; + return propagateInsertions(profileseq, origseq, nview); + } + + /** + * + * @param profileseq + * sequence in al which corresponds to origseq + * @param al + * alignment which is to have gaps inserted into it + * @param origseq + * sequence corresponding to profileseq which defines gap map for + * modifying al + */ + private HiddenColumns propagateInsertions(SequenceI profileseq, + SequenceI origseq, HiddenColumns hc) + { + // take the set of hidden columns, and the set of gaps in origseq, + // and remove all the hidden gaps from hiddenColumns + + // first get the gaps as a Bitset + // then calculate hidden ^ not(gap) + BitSet gaps = origseq.gapBitset(); + hc.andNot(gaps); + + // for each sequence in the alignment, except the profile sequence, + // insert gaps corresponding to each hidden region but where each hidden + // column region is shifted backwards by the number of preceding visible + // gaps update hidden columns at the same time + HiddenColumns newhidden = new HiddenColumns(); + + int numGapsBefore = 0; + int gapPosition = 0; + Iterator it = hc.iterator(); + while (it.hasNext()) + { + int[] region = it.next(); + + // get region coordinates accounting for gaps + // we can rely on gaps not being *in* hidden regions because we already + // removed those + while (gapPosition < region[0]) + { + gapPosition++; + if (gaps.get(gapPosition)) + { + numGapsBefore++; + } + } + + int left = region[0] - numGapsBefore; + int right = region[1] - numGapsBefore; + + newhidden.hideColumns(left, right); + padGaps(left, right, profileseq); + } + return newhidden; + } + + /** + * Pad gaps in all sequences in alignment except profileseq + * + * @param left + * position of first gap to insert + * @param right + * position of last gap to insert + * @param profileseq + * sequence not to pad + */ + private void padGaps(int left, int right, SequenceI profileseq) + { + char gc = getGapCharacter(); + + // make a string with number of gaps = length of hidden region + StringBuilder sb = new StringBuilder(); + for (int g = 0; g < right - left + 1; g++) + { + sb.append(gc); + } + + // loop over the sequences and pad with gaps where required + for (int s = 0, ns = getHeight(); s < ns; s++) + { + SequenceI sqobj = getSequenceAt(s); + if ((sqobj != profileseq) && (sqobj.getLength() >= left)) + { + String sq = sqobj.getSequenceAsString(); + sqobj.setSequence( + sq.substring(0, left) + sb.toString() + sq.substring(left)); + } + } + } } diff --git a/src/jalview/datamodel/AlignmentAnnotation.java b/src/jalview/datamodel/AlignmentAnnotation.java index f7bf4d8..0f7883e 100755 --- a/src/jalview/datamodel/AlignmentAnnotation.java +++ b/src/jalview/datamodel/AlignmentAnnotation.java @@ -94,76 +94,6 @@ public class AlignmentAnnotation private long invalidrnastruc = -2; /** - * Updates the _rnasecstr field Determines the positions that base pair and - * the positions of helices based on secondary structure from a Stockholm file - * - * @param rnaAnnotation - */ - private void _updateRnaSecStr(CharSequence rnaAnnotation) - { - try - { - _rnasecstr = Rna.getHelixMap(rnaAnnotation); - invalidrnastruc = -1; - } catch (WUSSParseException px) - { - // DEBUG System.out.println(px); - invalidrnastruc = px.getProblemPos(); - } - if (invalidrnastruc > -1) - { - return; - } - - if (_rnasecstr != null && _rnasecstr.length > 0) - { - // show all the RNA secondary structure annotation symbols. - isrna = true; - showAllColLabels = true; - scaleColLabel = true; - _markRnaHelices(); - } - // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup()); - - } - - private void _markRnaHelices() - { - int mxval = 0; - // Figure out number of helices - // Length of rnasecstr is the number of pairs of positions that base pair - // with each other in the secondary structure - for (int x = 0; x < _rnasecstr.length; x++) - { - - /* - * System.out.println(this.annotation._rnasecstr[x] + " Begin" + - * this.annotation._rnasecstr[x].getBegin()); - */ - // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup()); - int val = 0; - try - { - val = Integer.valueOf(_rnasecstr[x].getFeatureGroup()); - if (mxval < val) - { - mxval = val; - } - } catch (NumberFormatException q) - { - } - ; - - annotations[_rnasecstr[x].getBegin()].value = val; - annotations[_rnasecstr[x].getEnd()].value = val; - - // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val; - // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val; - } - setScore(mxval); - } - - /** * map of positions in the associated annotation */ private Map sequenceMapping; @@ -258,27 +188,266 @@ public class AlignmentAnnotation } } - /** - * Creates a new AlignmentAnnotation object. - * - * @param label - * short label shown under sequence labels - * @param description - * text displayed on mouseover - * @param annotations - * set of positional annotation elements - */ - public AlignmentAnnotation(String label, String description, - Annotation[] annotations) - { - setAnnotationId(); - // always editable? - editable = true; - this.label = label; - this.description = description; - this.annotations = annotations; + /** + * Creates a new AlignmentAnnotation object. + * + * @param label + * short label shown under sequence labels + * @param description + * text displayed on mouseover + * @param annotations + * set of positional annotation elements + */ + public AlignmentAnnotation(String label, String description, + Annotation[] annotations) + { + setAnnotationId(); + // always editable? + editable = true; + this.label = label; + this.description = description; + this.annotations = annotations; + + validateRangeAndDisplay(); + } + + /** + * Copy constructor creates a new independent annotation row with the same + * associated sequenceRef + * + * @param annotation + */ + public AlignmentAnnotation(AlignmentAnnotation annotation) + { + setAnnotationId(); + this.label = new String(annotation.label); + if (annotation.description != null) + { + this.description = new String(annotation.description); + } + this.graphMin = annotation.graphMin; + this.graphMax = annotation.graphMax; + this.graph = annotation.graph; + this.graphHeight = annotation.graphHeight; + this.graphGroup = annotation.graphGroup; + this.groupRef = annotation.groupRef; + this.editable = annotation.editable; + this.autoCalculated = annotation.autoCalculated; + this.hasIcons = annotation.hasIcons; + this.hasText = annotation.hasText; + this.height = annotation.height; + this.label = annotation.label; + this.padGaps = annotation.padGaps; + this.visible = annotation.visible; + this.centreColLabels = annotation.centreColLabels; + this.scaleColLabel = annotation.scaleColLabel; + this.showAllColLabels = annotation.showAllColLabels; + this.calcId = annotation.calcId; + if (annotation.properties != null) + { + properties = new HashMap<>(); + for (Map.Entry val : annotation.properties.entrySet()) + { + properties.put(val.getKey(), val.getValue()); + } + } + if (this.hasScore = annotation.hasScore) + { + this.score = annotation.score; + } + if (annotation.threshold != null) + { + threshold = new GraphLine(annotation.threshold); + } + Annotation[] ann = annotation.annotations; + if (annotation.annotations != null) + { + this.annotations = new Annotation[ann.length]; + for (int i = 0; i < ann.length; i++) + { + if (ann[i] != null) + { + annotations[i] = new Annotation(ann[i]); + if (_linecolour != null) + { + _linecolour = annotations[i].colour; + } + } + } + } + if (annotation.sequenceRef != null) + { + this.sequenceRef = annotation.sequenceRef; + if (annotation.sequenceMapping != null) + { + Integer p = null; + sequenceMapping = new HashMap<>(); + Iterator pos = annotation.sequenceMapping.keySet() + .iterator(); + while (pos.hasNext()) + { + // could optimise this! + p = pos.next(); + Annotation a = annotation.sequenceMapping.get(p); + if (a == null) + { + continue; + } + if (ann != null) + { + for (int i = 0; i < ann.length; i++) + { + if (ann[i] == a) + { + sequenceMapping.put(p, annotations[i]); + } + } + } + } + } + else + { + this.sequenceMapping = null; + } + } + // TODO: check if we need to do this: JAL-952 + // if (this.isrna=annotation.isrna) + { + // _rnasecstr=new SequenceFeature[annotation._rnasecstr]; + } + validateRangeAndDisplay(); // construct hashcodes, etc. + } + + /** + * copy constructor with edit based on the hidden columns marked in colSel + * + * @param alignmentAnnotation + * @param colSel + */ + public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, + HiddenColumns hidden) + { + this(alignmentAnnotation); + if (annotations == null) + { + return; + } + makeVisibleAnnotation(hidden); + } + + /** + * Creates a new AlignmentAnnotation object. + * + * @param label + * DOCUMENT ME! + * @param description + * DOCUMENT ME! + * @param annotations + * DOCUMENT ME! + * @param min + * DOCUMENT ME! + * @param max + * DOCUMENT ME! + * @param winLength + * DOCUMENT ME! + */ + public AlignmentAnnotation(String label, String description, + Annotation[] annotations, float min, float max, int graphType) + { + setAnnotationId(); + // graphs are not editable + editable = graphType == 0; + + this.label = label; + this.description = description; + this.annotations = annotations; + graph = graphType; + graphMin = min; + graphMax = max; + validateRangeAndDisplay(); + } + + /** + * Score only annotation + * + * @param label + * @param description + * @param score + */ + public AlignmentAnnotation(String label, String description, double score) + { + this(label, description, null); + setScore(score); + } + + /** + * Updates the _rnasecstr field Determines the positions that base pair and + * the positions of helices based on secondary structure from a Stockholm file + * + * @param rnaAnnotation + */ + private void _updateRnaSecStr(CharSequence rnaAnnotation) + { + try + { + _rnasecstr = Rna.getHelixMap(rnaAnnotation); + invalidrnastruc = -1; + } catch (WUSSParseException px) + { + // DEBUG System.out.println(px); + invalidrnastruc = px.getProblemPos(); + } + if (invalidrnastruc > -1) + { + return; + } + + if (_rnasecstr != null && _rnasecstr.length > 0) + { + // show all the RNA secondary structure annotation symbols. + isrna = true; + showAllColLabels = true; + scaleColLabel = true; + _markRnaHelices(); + } + // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup()); + + } + + private void _markRnaHelices() + { + int mxval = 0; + // Figure out number of helices + // Length of rnasecstr is the number of pairs of positions that base pair + // with each other in the secondary structure + for (int x = 0; x < _rnasecstr.length; x++) + { + + /* + * System.out.println(this.annotation._rnasecstr[x] + " Begin" + + * this.annotation._rnasecstr[x].getBegin()); + */ + // System.out.println(this.annotation._rnasecstr[x].getFeatureGroup()); + int val = 0; + try + { + val = Integer.valueOf(_rnasecstr[x].getFeatureGroup()); + if (mxval < val) + { + mxval = val; + } + } catch (NumberFormatException q) + { + } + ; + + annotations[_rnasecstr[x].getBegin()].value = val; + annotations[_rnasecstr[x].getEnd()].value = val; - validateRangeAndDisplay(); + // annotations[_rnasecstr[x].getBegin()].displayCharacter = "" + val; + // annotations[_rnasecstr[x].getEnd()].displayCharacter = "" + val; + } + setScore(mxval); } /** @@ -521,38 +690,6 @@ public class AlignmentAnnotation } /** - * Creates a new AlignmentAnnotation object. - * - * @param label - * DOCUMENT ME! - * @param description - * DOCUMENT ME! - * @param annotations - * DOCUMENT ME! - * @param min - * DOCUMENT ME! - * @param max - * DOCUMENT ME! - * @param winLength - * DOCUMENT ME! - */ - public AlignmentAnnotation(String label, String description, - Annotation[] annotations, float min, float max, int graphType) - { - setAnnotationId(); - // graphs are not editable - editable = graphType == 0; - - this.label = label; - this.description = description; - this.annotations = annotations; - graph = graphType; - graphMin = min; - graphMax = max; - validateRangeAndDisplay(); - } - - /** * checks graphMin and graphMax, secondary structure symbols, sets graphType * appropriately, sets null labels to the empty string if appropriate. */ @@ -633,113 +770,6 @@ public class AlignmentAnnotation } /** - * Copy constructor creates a new independent annotation row with the same - * associated sequenceRef - * - * @param annotation - */ - public AlignmentAnnotation(AlignmentAnnotation annotation) - { - setAnnotationId(); - this.label = new String(annotation.label); - if (annotation.description != null) - { - this.description = new String(annotation.description); - } - this.graphMin = annotation.graphMin; - this.graphMax = annotation.graphMax; - this.graph = annotation.graph; - this.graphHeight = annotation.graphHeight; - this.graphGroup = annotation.graphGroup; - this.groupRef = annotation.groupRef; - this.editable = annotation.editable; - this.autoCalculated = annotation.autoCalculated; - this.hasIcons = annotation.hasIcons; - this.hasText = annotation.hasText; - this.height = annotation.height; - this.label = annotation.label; - this.padGaps = annotation.padGaps; - this.visible = annotation.visible; - this.centreColLabels = annotation.centreColLabels; - this.scaleColLabel = annotation.scaleColLabel; - this.showAllColLabels = annotation.showAllColLabels; - this.calcId = annotation.calcId; - if (annotation.properties != null) - { - properties = new HashMap(); - for (Map.Entry val : annotation.properties.entrySet()) - { - properties.put(val.getKey(), val.getValue()); - } - } - if (this.hasScore = annotation.hasScore) - { - this.score = annotation.score; - } - if (annotation.threshold != null) - { - threshold = new GraphLine(annotation.threshold); - } - Annotation[] ann = annotation.annotations; - if (annotation.annotations != null) - { - this.annotations = new Annotation[ann.length]; - for (int i = 0; i < ann.length; i++) - { - if (ann[i] != null) - { - annotations[i] = new Annotation(ann[i]); - if (_linecolour != null) - { - _linecolour = annotations[i].colour; - } - } - } - } - if (annotation.sequenceRef != null) - { - this.sequenceRef = annotation.sequenceRef; - if (annotation.sequenceMapping != null) - { - Integer p = null; - sequenceMapping = new HashMap(); - Iterator pos = annotation.sequenceMapping.keySet() - .iterator(); - while (pos.hasNext()) - { - // could optimise this! - p = pos.next(); - Annotation a = annotation.sequenceMapping.get(p); - if (a == null) - { - continue; - } - if (ann != null) - { - for (int i = 0; i < ann.length; i++) - { - if (ann[i] == a) - { - sequenceMapping.put(p, annotations[i]); - } - } - } - } - } - else - { - this.sequenceMapping = null; - } - } - // TODO: check if we need to do this: JAL-952 - // if (this.isrna=annotation.isrna) - { - // _rnasecstr=new SequenceFeature[annotation._rnasecstr]; - } - validateRangeAndDisplay(); // construct hashcodes, etc. - } - - /** * clip the annotation to the columns given by startRes and endRes (inclusive) * and prune any existing sequenceMapping to just those columns. * @@ -782,7 +812,7 @@ public class AlignmentAnnotation int epos = sequenceRef.findPosition(endRes); if (sequenceMapping != null) { - Map newmapping = new HashMap(); + Map newmapping = new HashMap<>(); Iterator e = sequenceMapping.keySet().iterator(); while (e.hasNext()) { @@ -909,7 +939,7 @@ public class AlignmentAnnotation { return; } - sequenceMapping = new HashMap(); + sequenceMapping = new HashMap<>(); int seqPos; @@ -1097,36 +1127,6 @@ public class AlignmentAnnotation return hasScore || !Double.isNaN(score); } - /** - * Score only annotation - * - * @param label - * @param description - * @param score - */ - public AlignmentAnnotation(String label, String description, double score) - { - this(label, description, null); - setScore(score); - } - - /** - * copy constructor with edit based on the hidden columns marked in colSel - * - * @param alignmentAnnotation - * @param colSel - */ - public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation, - HiddenColumns hidden) - { - this(alignmentAnnotation); - if (annotations == null) - { - return; - } - hidden.makeVisibleAnnotation(this); - } - public void setPadGaps(boolean padgaps, char gapchar) { this.padGaps = padgaps; @@ -1185,12 +1185,12 @@ public class AlignmentAnnotation /** * machine readable ID string indicating what generated this annotation */ - protected String calcId = ""; + private String calcId = ""; /** * properties associated with the calcId */ - protected Map properties = new HashMap(); + protected Map properties = new HashMap<>(); /** * base colour for line graphs. If null, will be set automatically by @@ -1236,7 +1236,7 @@ public class AlignmentAnnotation : false; // TODO build a better annotation element map and get rid of annotations[] - Map mapForsq = new HashMap(); + Map mapForsq = new HashMap<>(); if (sequenceMapping != null) { if (sp2sq != null) @@ -1289,7 +1289,7 @@ public class AlignmentAnnotation if (mapping != null) { Map old = sequenceMapping; - Map remap = new HashMap(); + Map remap = new HashMap<>(); int index = -1; for (int mp[] : mapping.values()) { @@ -1347,7 +1347,7 @@ public class AlignmentAnnotation { if (properties == null) { - properties = new HashMap(); + properties = new HashMap<>(); } properties.put(property, value); } @@ -1473,12 +1473,120 @@ public class AlignmentAnnotation return graphMin < graphMax; } + /** + * delete any columns in alignmentAnnotation that are hidden (including + * sequence associated annotation). + * + * @param hiddenColumns + * the set of hidden columns + */ + public void makeVisibleAnnotation(HiddenColumns hiddenColumns) + { + if (annotations != null) + { + makeVisibleAnnotation(0, annotations.length, hiddenColumns); + } + } + + /** + * delete any columns in alignmentAnnotation that are hidden (including + * sequence associated annotation). + * + * @param start + * remove any annotation to the right of this column + * @param end + * remove any annotation to the left of this column + * @param hiddenColumns + * the set of hidden columns + */ + public void makeVisibleAnnotation(int start, int end, + HiddenColumns hiddenColumns) + { + if (annotations != null) + { + if (hiddenColumns.hasHiddenColumns()) + { + removeHiddenAnnotation(start, end, hiddenColumns); + } + else + { + restrict(start, end); + } + } + } + + /** + * The actual implementation of deleting hidden annotation columns + * + * @param start + * remove any annotation to the right of this column + * @param end + * remove any annotation to the left of this column + * @param hiddenColumns + * the set of hidden columns + */ + private void removeHiddenAnnotation(int start, int end, + HiddenColumns hiddenColumns) + { + // mangle the alignmentAnnotation annotation array + ArrayList annels = new ArrayList<>(); + Annotation[] els = null; + + int w = 0; + + Iterator blocks = hiddenColumns.getVisContigsIterator(start, + end + 1, false); + + int copylength; + int annotationLength; + while (blocks.hasNext()) + { + int[] block = blocks.next(); + annotationLength = block[1] - block[0] + 1; + + if (blocks.hasNext()) + { + // copy just the visible segment of the annotation row + copylength = annotationLength; + } + else + { + if (annotationLength + block[0] <= annotations.length) + { + // copy just the visible segment of the annotation row + copylength = annotationLength; + } + else + { + // copy to the end of the annotation row + copylength = annotations.length - block[0]; + } + } + + els = new Annotation[annotationLength]; + annels.add(els); + System.arraycopy(annotations, block[0], els, 0, copylength); + w += annotationLength; + } + + if (w != 0) + { + annotations = new Annotation[w]; + + w = 0; + for (Annotation[] chnk : annels) + { + System.arraycopy(chnk, 0, annotations, w, chnk.length); + w += chnk.length; + } + } + } + public static Iterable findAnnotations( Iterable list, SequenceI seq, String calcId, String label) { - - ArrayList aa = new ArrayList<>(); + List aa = new ArrayList<>(); for (AlignmentAnnotation ann : list) { if ((calcId == null || (ann.getCalcId() != null @@ -1522,7 +1630,6 @@ public class AlignmentAnnotation public static Iterable findAnnotation( List list, String calcId) { - List aa = new ArrayList<>(); if (calcId == null) { diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index 084b80e..d591f42 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -504,8 +504,6 @@ public interface AlignmentI extends AnnotatedCollectionI * - null or specific sequence reference * @param groupRef * - null or specific group reference - * @param method - * - CalcId for the annotation (must match) * * @return existing annotation matching the given attributes */ @@ -580,6 +578,41 @@ public interface AlignmentI extends AnnotatedCollectionI */ AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo); + /** + * Set the hidden columns collection on the alignment + * + * @param cols + */ public void setHiddenColumns(HiddenColumns cols); + /** + * Insert a sequence at a position in an alignment + * + * @param i + * The index of the position. + * @param snew + * The new sequence. + */ + void insertSequenceAt(int i, SequenceI snew); + + /** + * Set the first sequence as representative and hide its insertions. Typically + * used when loading JPred files. + */ + public void setupJPredAlignment(); + + /** + * Add gaps into the sequences aligned to profileseq under the given + * AlignmentView + * + * @param profileseq + * sequence in al which sequences are aligned to + * @param input + * alignment view where sequence corresponding to profileseq is first + * entry + * @return new HiddenColumns for new alignment view, with insertions into + * profileseq marked as hidden. + */ + public HiddenColumns propagateInsertions(SequenceI profileseq, + AlignmentView input); } diff --git a/src/jalview/datamodel/AlignmentOrder.java b/src/jalview/datamodel/AlignmentOrder.java index 6d09145..ef46d79 100755 --- a/src/jalview/datamodel/AlignmentOrder.java +++ b/src/jalview/datamodel/AlignmentOrder.java @@ -80,7 +80,7 @@ public class AlignmentOrder */ public AlignmentOrder(AlignmentI orderFrom) { - Order = new ArrayList(); + Order = new ArrayList<>(); for (SequenceI seq : orderFrom.getSequences()) { @@ -96,7 +96,7 @@ public class AlignmentOrder */ public AlignmentOrder(SequenceI[] orderFrom) { - Order = new ArrayList(Arrays.asList(orderFrom)); + Order = new ArrayList<>(Arrays.asList(orderFrom)); } /** diff --git a/src/jalview/datamodel/AnnotatedCollectionI.java b/src/jalview/datamodel/AnnotatedCollectionI.java index 2963fd5..878f22a 100644 --- a/src/jalview/datamodel/AnnotatedCollectionI.java +++ b/src/jalview/datamodel/AnnotatedCollectionI.java @@ -61,4 +61,6 @@ public interface AnnotatedCollectionI extends SequenceCollectionI * alignment, parent group). */ AnnotatedCollectionI getContext(); + + } diff --git a/src/jalview/datamodel/CigarArray.java b/src/jalview/datamodel/CigarArray.java index 1723f1d..17e9ea6 100644 --- a/src/jalview/datamodel/CigarArray.java +++ b/src/jalview/datamodel/CigarArray.java @@ -20,7 +20,7 @@ */ package jalview.datamodel; -import java.util.List; +import java.util.Iterator; public class CigarArray extends CigarBase { @@ -90,9 +90,7 @@ public class CigarArray extends CigarBase SequenceGroup selectionGroup) { this(constructSeqCigarArray(alignment, selectionGroup)); - constructFromAlignment(alignment, - hidden != null ? hidden.getHiddenColumnsCopy() : null, - selectionGroup); + constructFromAlignment(alignment, hidden, selectionGroup); } private static int[] _calcStartEndBounds(AlignmentI alignment, @@ -154,33 +152,25 @@ public class CigarArray extends CigarBase * @param selectionGroup */ private void constructFromAlignment(AlignmentI alignment, - List list, SequenceGroup selectionGroup) + HiddenColumns hidden, SequenceGroup selectionGroup) { int[] _startend = _calcStartEndBounds(alignment, selectionGroup); - int start = _startend[1], end = _startend[2]; + int start = _startend[1]; + int end = _startend[2]; // now construct the CigarArray operations - if (list != null) + if (hidden != null) { int[] region; - int hideStart, hideEnd; + int hideStart; + int hideEnd; int last = start; - for (int j = 0; last < end & j < list.size(); j++) + + Iterator regions = hidden.getBoundedIterator(start, end); + while (regions.hasNext()) { - region = list.get(j); + region = regions.next(); hideStart = region[0]; hideEnd = region[1]; - // edit hidden regions to selection range - - // just move on if hideEnd is before last - if (hideEnd < last) - { - continue; - } - // exit if next region is after end - if (hideStart > end) - { - break; - } // truncate region at start if last falls in region if ((hideStart < last) && (hideEnd >= last)) @@ -204,6 +194,7 @@ public class CigarArray extends CigarBase addOperation(CigarArray.D, 1 + hideEnd - hideStart); last = hideEnd + 1; } + // Final match if necessary. if (last <= end) { diff --git a/src/jalview/datamodel/DBRefSource.java b/src/jalview/datamodel/DBRefSource.java index 0ac14e5..7a30141 100755 --- a/src/jalview/datamodel/DBRefSource.java +++ b/src/jalview/datamodel/DBRefSource.java @@ -96,7 +96,7 @@ public class DBRefSource * List of databases whose sequences might have coding regions annotated */ public static final String[] DNACODINGDBS = { EMBL, EMBLCDS, GENEDB, - ENSEMBL }; + ENSEMBL, ENSEMBLGENOMES }; public static final String[] CODINGDBS = { EMBLCDS, GENEDB, ENSEMBL }; @@ -105,7 +105,7 @@ public class DBRefSource public static String[] allSources() { - List src = new ArrayList(); + List src = new ArrayList<>(); for (Field f : DBRefSource.class.getFields()) { if (String.class.equals(f.getType())) diff --git a/src/jalview/datamodel/HMMNode.java b/src/jalview/datamodel/HMMNode.java new file mode 100644 index 0000000..b646eee --- /dev/null +++ b/src/jalview/datamodel/HMMNode.java @@ -0,0 +1,148 @@ +package jalview.datamodel; + +/** + * stores data for each node in the hmm model + * @author TZVanaalten + * + */ +public class HMMNode +{ + //contains the match emissions for each symbol + double[] matchEmissions; + + //contains the insert emissions for each symbol + double[] insertEmissions; + + // contains the state transitions for each possible transition. These are mm, + // mi, md, im, ii, dm and dd in order + double[] stateTransitions; + + //annotations + int residueNumber; + char consensusResidue; + char referenceAnnotation; + char maskValue; + char consensusStructure; + + /** + * Constructor + */ + public HMMNode() + { + } + + public double[] getMatchEmissions() + { + return matchEmissions; + } + + double getMatchEmission(int symbolIndex) + { + return matchEmissions[symbolIndex]; + } + + public void setMatchEmissions(double[] matches) + { + this.matchEmissions = matches; + } + + public double[] getInsertEmissions() + { + return insertEmissions; + } + + double getInsertEmission(int symbolIndex) + { + return insertEmissions[symbolIndex]; + } + + public void setInsertEmissions(double[] insertEmissionsL) + { + this.insertEmissions = insertEmissionsL; + } + + public double[] getStateTransitions() + { + return stateTransitions; + } + + double getStateTransition(int transition) + { + return stateTransitions[transition]; + } + + public void setStateTransitions(double[] stateTransitionsM) + { + this.stateTransitions = stateTransitionsM; + } + + int getResidueNumber() + { + return residueNumber; + } + public void setResidueNumber(int resNo) + { + this.residueNumber = resNo; + } + + char getConsensusResidue() + { + return consensusResidue; + } + public void setConsensusResidue(char consensusResidue) + { + this.consensusResidue = consensusResidue; + } + + char getReferenceAnnotation() + { + return referenceAnnotation; + } + public void setReferenceAnnotation(char referenceAnnotation) + { + this.referenceAnnotation = referenceAnnotation; + } + + char getMaskValue() + { + return maskValue; + } + public void setMaskValue(char maskValue) + { + this.maskValue = maskValue; + } + + char getConsensusStructure() + { + return consensusStructure; + } + public void setConsensusStructure(char consensusStructure) + { + this.consensusStructure = consensusStructure; + } + + /** + * Answers the symbol index of the symbol with the highest match emission + * probability (first symbol in case of a tie). Note this object stores + * probabilities, not the negative logarithms as in the HMM file. + * + * @return + */ + int getMaxMatchEmissionIndex() + { + int maxIndex = 0; + double max = 0D; + + for (int i = 0; i < matchEmissions.length; i++) + { + if (matchEmissions[i] > max) + { + max = matchEmissions[i]; + maxIndex = i; + } + } + return maxIndex; + } +} + + diff --git a/src/jalview/datamodel/HiddenColumns.java b/src/jalview/datamodel/HiddenColumns.java index c0a43ee..a7e93da 100644 --- a/src/jalview/datamodel/HiddenColumns.java +++ b/src/jalview/datamodel/HiddenColumns.java @@ -20,25 +20,71 @@ */ package jalview.datamodel; -import jalview.util.Comparison; -import jalview.util.ShiftList; - import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; -import java.util.Collections; +import java.util.Iterator; import java.util.List; -import java.util.Vector; import java.util.concurrent.locks.ReentrantReadWriteLock; +/** + * This class manages the collection of hidden columns associated with an + * alignment. To iterate over the collection, or over visible columns/regions, + * use an iterator obtained from one of: + * + * - getBoundedIterator: iterates over the hidden regions, within some bounds, + * returning *absolute* positions + * + * - getBoundedStartIterator: iterates over the start positions of hidden + * regions, within some bounds, returning *visible* positions + * + * - getVisContigsIterator: iterates over visible regions in a range, returning + * *absolute* positions + * + * - getVisibleColsIterator: iterates over the visible *columns* + * + * For performance reasons, provide bounds where possible. Note that column + * numbering begins at 0 throughout this class. + * + * @author kmourao + */ + +/* Implementation notes: + * + * Methods which change the hiddenColumns collection should use a writeLock to + * prevent other threads accessing the hiddenColumns collection while changes + * are being made. They should also reset the hidden columns cursor, and either + * update the hidden columns count, or set it to 0 (so that it will later be + * updated when needed). + * + * + * Methods which only need read access to the hidden columns collection should + * use a readLock to prevent other threads changing the hidden columns + * collection while it is in use. + */ public class HiddenColumns { + private static final int HASH_MULTIPLIER = 31; + private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock(); /* + * Cursor which tracks the last used hidden columns region, and the number + * of hidden columns up to (but not including) that region. + */ + private HiddenColumnsCursor cursor = new HiddenColumnsCursor(); + + /* + * cache of the number of hidden columns: must be kept up to date by methods + * which add or remove hidden columns + */ + private int numColumns = 0; + + /* * list of hidden column [start, end] ranges; the list is maintained in * ascending start column order */ - private ArrayList hiddenColumns; + private List hiddenColumns = new ArrayList<>(); /** * Constructor @@ -51,19 +97,263 @@ public class HiddenColumns * Copy constructor * * @param copy + * the HiddenColumns object to copy from */ public HiddenColumns(HiddenColumns copy) { + this(copy, Integer.MIN_VALUE, Integer.MAX_VALUE, 0); + } + + /** + * Copy constructor within bounds and with offset. Copies hidden column + * regions fully contained between start and end, and offsets positions by + * subtracting offset. + * + * @param copy + * HiddenColumns instance to copy from + * @param start + * lower bound to copy from + * @param end + * upper bound to copy to + * @param offset + * offset to subtract from each region boundary position + * + */ + public HiddenColumns(HiddenColumns copy, int start, int end, int offset) + { try { LOCK.writeLock().lock(); if (copy != null) { - if (copy.hiddenColumns != null) + numColumns = 0; + Iterator it = copy.getBoundedIterator(start, end); + while (it.hasNext()) + { + int[] region = it.next(); + // still need to check boundaries because iterator returns + // all overlapping regions and we need contained regions + if (region[0] >= start && region[1] <= end) + { + hiddenColumns.add( + new int[] + { region[0] - offset, region[1] - offset }); + numColumns += region[1] - region[0] + 1; + } + } + cursor = new HiddenColumnsCursor(hiddenColumns); + } + } finally + { + LOCK.writeLock().unlock(); + } + } + + /** + * Adds the specified column range to the hidden columns collection + * + * @param start + * start of range to add (absolute position in alignment) + * @param end + * end of range to add (absolute position in alignment) + */ + public void hideColumns(int start, int end) + { + try + { + LOCK.writeLock().lock(); + + int previndex = 0; + int prevHiddenCount = 0; + int regionindex = 0; + if (!hiddenColumns.isEmpty()) + { + // set up cursor reset values + HiddenCursorPosition cursorPos = cursor.findRegionForColumn(start, false); + regionindex = cursorPos.getRegionIndex(); + + if (regionindex > 0) + { + // get previous index and hidden count for updating the cursor later + previndex = regionindex - 1; + int[] prevRegion = hiddenColumns.get(previndex); + prevHiddenCount = cursorPos.getHiddenSoFar() + - (prevRegion[1] - prevRegion[0] + 1); + } + } + + // new range follows everything else; check first to avoid looping over + // whole hiddenColumns collection + if (hiddenColumns.isEmpty() + || start > hiddenColumns.get(hiddenColumns.size() - 1)[1]) + { + hiddenColumns.add(new int[] { start, end }); + numColumns += end - start + 1; + } + else + { + /* + * traverse existing hidden ranges and insert / amend / append as + * appropriate + */ + boolean added = false; + if (regionindex > 0) + { + added = insertRangeAtRegion(regionindex - 1, start, end); + } + if (!added && regionindex < hiddenColumns.size()) + { + insertRangeAtRegion(regionindex, start, end); + } + } + + // reset the cursor to just before our insertion point: this saves + // a lot of reprocessing in large alignments + cursor = new HiddenColumnsCursor(hiddenColumns, previndex, + prevHiddenCount); + } finally + { + LOCK.writeLock().unlock(); + } + } + + /** + * Insert [start, range] at the region at index i in hiddenColumns, if + * feasible + * + * @param i + * index to insert at + * @param start + * start of range to insert + * @param end + * end of range to insert + * @return true if range was successfully inserted + */ + private boolean insertRangeAtRegion(int i, int start, int end) + { + boolean added = false; + + int[] region = hiddenColumns.get(i); + if (end < region[0] - 1) + { + /* + * insert discontiguous preceding range + */ + hiddenColumns.add(i, new int[] { start, end }); + numColumns += end - start + 1; + added = true; + } + else if (end <= region[1]) + { + /* + * new range overlaps existing, or is contiguous preceding it - adjust + * start column + */ + int oldstart = region[0]; + region[0] = Math.min(region[0], start); + numColumns += oldstart - region[0]; // new columns are between old and + // adjusted starts + added = true; + } + else if (start <= region[1] + 1) + { + /* + * new range overlaps existing, or is contiguous following it - adjust + * start and end columns + */ + insertRangeAtOverlap(i, start, end, region); + added = true; + } + return added; + } + + /** + * Insert a range whose start position overlaps an existing region and/or is + * contiguous to the right of the region + * + * @param i + * index to insert at + * @param start + * start of range to insert + * @param end + * end of range to insert + * @param region + * the overlapped/continued region + */ + private void insertRangeAtOverlap(int i, int start, int end, int[] region) + { + int oldstart = region[0]; + int oldend = region[1]; + region[0] = Math.min(region[0], start); + region[1] = Math.max(region[1], end); + + numColumns += oldstart - region[0]; + + /* + * also update or remove any subsequent ranges + * that are overlapped + */ + int endi = i; + while (endi < hiddenColumns.size() - 1) + { + int[] nextRegion = hiddenColumns.get(endi + 1); + if (nextRegion[0] > end + 1) + { + /* + * gap to next hidden range - no more to update + */ + break; + } + numColumns -= nextRegion[1] - nextRegion[0] + 1; + region[1] = Math.max(nextRegion[1], end); + endi++; + } + numColumns += region[1] - oldend; + hiddenColumns.subList(i + 1, endi + 1).clear(); + } + + /** + * hide a list of ranges + * + * @param ranges + */ + public void hideList(List ranges) + { + try + { + LOCK.writeLock().lock(); + for (int[] r : ranges) + { + hideColumns(r[0], r[1]); + } + cursor = new HiddenColumnsCursor(hiddenColumns); + + } finally + { + LOCK.writeLock().unlock(); + } + } + + /** + * Unhides, and adds to the selection list, all hidden columns + */ + public void revealAllHiddenColumns(ColumnSelection sel) + { + try + { + LOCK.writeLock().lock(); + + for (int[] region : hiddenColumns) + { + for (int j = region[0]; j < region[1] + 1; j++) { - hiddenColumns = copy.copyHiddenRegionsToArrayList(); + sel.addElement(j); } } + hiddenColumns.clear(); + cursor = new HiddenColumnsCursor(hiddenColumns); + numColumns = 0; + } finally { LOCK.writeLock().unlock(); @@ -71,16 +361,46 @@ public class HiddenColumns } /** - * This method is used to return all the HiddenColumn regions and is intended - * to remain private. External callers which need a copy of the regions can - * call getHiddenColumnsCopyAsList. + * Reveals, and marks as selected, the hidden column range with the given + * start column * - * @return empty list or List of hidden column intervals + * @param start + * the start column to look for + * @param sel + * the column selection to add the hidden column range to */ - private List getHiddenRegions() + public void revealHiddenColumns(int start, ColumnSelection sel) { - return hiddenColumns == null ? Collections. emptyList() - : hiddenColumns; + try + { + LOCK.writeLock().lock(); + + if (!hiddenColumns.isEmpty()) + { + int regionIndex = cursor.findRegionForColumn(start, false) + .getRegionIndex(); + + if (regionIndex != -1 && regionIndex != hiddenColumns.size()) + { + // regionIndex is the region which either contains start + // or lies to the right of start + int[] region = hiddenColumns.get(regionIndex); + if (start == region[0]) + { + for (int j = region[0]; j < region[1] + 1; j++) + { + sel.addElement(j); + } + int colsToRemove = region[1] - region[0] + 1; + hiddenColumns.remove(regionIndex); + numColumns -= colsToRemove; + } + } + } + } finally + { + LOCK.writeLock().unlock(); + } } /** @@ -99,16 +419,22 @@ public class HiddenColumns { LOCK.readLock().lock(); StringBuilder regionBuilder = new StringBuilder(); - if (hiddenColumns != null) + + boolean first = true; + for (int[] range : hiddenColumns) { - for (int[] range : hiddenColumns) + if (!first) + { + regionBuilder.append(delimiter); + } + else { - regionBuilder.append(delimiter).append(range[0]).append(between) - .append(range[1]); + first = false; } + regionBuilder.append(range[0]).append(between).append(range[1]); - regionBuilder.deleteCharAt(0); } + return regionBuilder.toString(); } finally { @@ -123,18 +449,20 @@ public class HiddenColumns */ public int getSize() { + return numColumns; + } + + /** + * Get the number of distinct hidden regions + * + * @return number of regions + */ + public int getNumberOfRegions() + { try { LOCK.readLock().lock(); - int size = 0; - if (hasHiddenColumns()) - { - for (int[] range : hiddenColumns) - { - size += range[1] - range[0] + 1; - } - } - return size; + return hiddenColumns.size(); } finally { LOCK.readLock().unlock(); @@ -157,25 +485,23 @@ public class HiddenColumns /* * check hidden columns are either both null, or match */ - if (this.hiddenColumns == null) - { - return (that.hiddenColumns == null); - } - if (that.hiddenColumns == null - || that.hiddenColumns.size() != this.hiddenColumns.size()) + + if (that.hiddenColumns.size() != this.hiddenColumns.size()) { return false; } - int i = 0; - for (int[] thisRange : hiddenColumns) + + Iterator it = this.iterator(); + Iterator thatit = that.iterator(); + while (it.hasNext()) { - int[] thatRange = that.hiddenColumns.get(i++); - if (thisRange[0] != thatRange[0] || thisRange[1] != thatRange[1]) + if (!(Arrays.equals(it.next(), thatit.next()))) { return false; } } return true; + } finally { LOCK.readLock().unlock(); @@ -189,23 +515,19 @@ public class HiddenColumns * int column index in alignment view (count from zero) * @return alignment column index for column */ - public int adjustForHiddenColumns(int column) + public int visibleToAbsoluteColumn(int column) { try { LOCK.readLock().lock(); int result = column; - if (hiddenColumns != null) + + if (!hiddenColumns.isEmpty()) { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.get(i); - if (result >= region[0]) - { - result += region[1] - region[0] + 1; - } - } + result += cursor.findRegionForColumn(column, true) + .getHiddenSoFar(); } + return result; } finally { @@ -216,54 +538,52 @@ public class HiddenColumns /** * Use this method to find out where a column will appear in the visible * alignment when hidden columns exist. If the column is not visible, then the - * left-most visible column will always be returned. + * index of the next visible column on the left will be returned (or 0 if + * there is no visible column on the left) * * @param hiddenColumn * the column index in the full alignment including hidden columns * @return the position of the column in the visible alignment */ - public int findColumnPosition(int hiddenColumn) + public int absoluteToVisibleColumn(int hiddenColumn) { try { LOCK.readLock().lock(); int result = hiddenColumn; - if (hiddenColumns != null) - { - int index = 0; - int[] region; - do - { - region = hiddenColumns.get(index++); - if (hiddenColumn > region[1]) - { - result -= region[1] + 1 - region[0]; - } - } while ((hiddenColumn > region[1]) - && (index < hiddenColumns.size())); - if (hiddenColumn >= region[0] && hiddenColumn <= region[1]) + if (!hiddenColumns.isEmpty()) + { + HiddenCursorPosition cursorPos = cursor + .findRegionForColumn(hiddenColumn, false); + int index = cursorPos.getRegionIndex(); + int hiddenBeforeCol = cursorPos.getHiddenSoFar(); + + // just subtract hidden cols count - this works fine if column is + // visible + result = hiddenColumn - hiddenBeforeCol; + + // now check in case column is hidden - it will be in the returned + // hidden region + if (index < hiddenColumns.size()) { - // Here the hidden column is within a region, so - // we want to return the position of region[0]-1, adjusted for any - // earlier hidden columns. - // Calculate the difference between the actual hidden col position - // and region[0]-1, and then subtract from result to convert result - // from - // the adjusted hiddenColumn value to the adjusted region[0]-1 value - - // However, if the region begins at 0 we cannot return region[0]-1 - // just return 0 - if (region[0] == 0) - { - return 0; - } - else + int[] region = hiddenColumns.get(index); + if (hiddenColumn >= region[0] && hiddenColumn <= region[1]) { - return result - (hiddenColumn - region[0] + 1); + // actually col is hidden, return region[0]-1 + // unless region[0]==0 in which case return 0 + if (region[0] == 0) + { + result = 0; + } + else + { + result = region[0] - 1 - hiddenBeforeCol; + } } } } + return result; // return the shifted position after removing hidden // columns. } finally @@ -274,113 +594,75 @@ public class HiddenColumns /** * Find the visible column which is a given visible number of columns to the - * left of another visible column. i.e. for a startColumn x, the column which - * is distance 1 away will be column x-1. + * left (negative visibleDistance) or right (positive visibleDistance) of + * startColumn. If startColumn is not visible, we use the visible column at + * the left boundary of the hidden region containing startColumn. * * @param visibleDistance - * the number of visible columns to offset by + * the number of visible columns to offset by (left offset = negative + * value; right offset = positive value) * @param startColumn - * the column to start from - * @return the position of the column in the visible alignment + * the position of the column to start from (absolute position) + * @return the position of the column which is away + * (absolute position) */ - public int subtractVisibleColumns(int visibleDistance, int startColumn) + public int offsetByVisibleColumns(int visibleDistance, int startColumn) { try { - LOCK.readLock().lock(); - int distance = visibleDistance; - - // in case startColumn is in a hidden region, move it to the left - int start = adjustForHiddenColumns(findColumnPosition(startColumn)); - - // get index of hidden region to left of start - int index = getHiddenIndexLeft(start); - if (index == -1) - { - // no hidden regions to left of startColumn - return start - distance; - } - - // walk backwards through the alignment subtracting the counts of visible - // columns from distance - int[] region; - int gap = 0; - int nextstart = start; - - while ((index > -1) && (distance - gap > 0)) - { - // subtract the gap to right of region from distance - distance -= gap; - start = nextstart; - - // calculate the next gap - region = hiddenColumns.get(index); - gap = start - region[1]; - - // set start to just to left of current region - nextstart = region[0] - 1; - index--; - } + int start = absoluteToVisibleColumn(startColumn); + return visibleToAbsoluteColumn(start + visibleDistance); - if (distance - gap > 0) - { - // fell out of loop because there are no more hidden regions - distance -= gap; - return nextstart - distance; - } - return start - distance; } finally { LOCK.readLock().unlock(); } - } /** - * Use this method to determine the set of hiddenRegion start positions + * This method returns the rightmost limit of a region of an alignment with + * hidden columns. In otherwords, the next hidden column. * - * @return list of column number in visible view where hidden regions start + * @param alPos + * the absolute (visible) alignmentPosition to find the next hidden + * column for + * @return the index of the next hidden column, or alPos if there is no next + * hidden column */ - public List findHiddenRegionPositions() + public int getNextHiddenBoundary(boolean left, int alPos) { try { LOCK.readLock().lock(); - List positions = null; - - if (hiddenColumns != null) + if (!hiddenColumns.isEmpty()) { - positions = new ArrayList<>(hiddenColumns.size()); + int index = cursor.findRegionForColumn(alPos, false) + .getRegionIndex(); - positions.add(hiddenColumns.get(0)[0]); - for (int i = 1; i < hiddenColumns.size(); ++i) + if (left && index > 0) { - - int result = 0; - if (hiddenColumns != null) + int[] region = hiddenColumns.get(index - 1); + return region[1]; + } + else if (!left && index < hiddenColumns.size()) + { + int[] region = hiddenColumns.get(index); + if (alPos < region[0]) { - int index = 0; - int gaps = 0; - do - { - int[] region = hiddenColumns.get(index); - gaps += region[1] + 1 - region[0]; - result = region[1] + 1; - index++; - } while (index <= i); - - result -= gaps; + return region[0]; + } + else if ((alPos <= region[1]) + && (index + 1 < hiddenColumns.size())) + { + // alPos is within a hidden region, return the next one + // if there is one + region = hiddenColumns.get(index + 1); + return region[0]; } - positions.add(result); } } - else - { - positions = new ArrayList<>(); - } - - return positions; + return alPos; } finally { LOCK.readLock().unlock(); @@ -388,69 +670,54 @@ public class HiddenColumns } /** - * This method returns the rightmost limit of a region of an alignment with - * hidden columns. In otherwords, the next hidden column. + * Answers if a column in the alignment is visible * - * @param index - * int + * @param column + * absolute position of column in the alignment + * @return true if column is visible */ - public int getHiddenBoundaryRight(int alPos) + public boolean isVisible(int column) { try { LOCK.readLock().lock(); - if (hiddenColumns != null) + + if (!hiddenColumns.isEmpty()) { - int index = 0; - do + int regionindex = cursor.findRegionForColumn(column, false) + .getRegionIndex(); + if (regionindex > -1 && regionindex < hiddenColumns.size()) { - int[] region = hiddenColumns.get(index); - if (alPos < region[0]) + int[] region = hiddenColumns.get(regionindex); + // already know that column <= region[1] as cursor returns containing + // region or region to right + if (column >= region[0]) { - return region[0]; + return false; } - - index++; - } while (index < hiddenColumns.size()); + } } + return true; - return alPos; } finally { LOCK.readLock().unlock(); } - } /** - * This method returns the leftmost limit of a region of an alignment with - * hidden columns. In otherwords, the previous hidden column. * - * @param index - * int + * @return true if there are columns hidden */ - public int getHiddenBoundaryLeft(int alPos) + public boolean hasHiddenColumns() { try { LOCK.readLock().lock(); - if (hiddenColumns != null) - { - int index = hiddenColumns.size() - 1; - do - { - int[] region = hiddenColumns.get(index); - if (alPos > region[1]) - { - return region[1]; - } - - index--; - } while (index > -1); - } - - return alPos; + // we don't use getSize()>0 here because it has to iterate over + // the full hiddenColumns collection and so will be much slower + return (!hiddenColumns.isEmpty()); } finally { LOCK.readLock().unlock(); @@ -458,258 +725,169 @@ public class HiddenColumns } /** - * This method returns the index of the hidden region to the left of a column - * position. If the column is in a hidden region it returns the index of the - * region to the left. If there is no hidden region to the left it returns -1. * - * @param pos - * int + * @return true if there is more than one hidden column region */ - private int getHiddenIndexLeft(int pos) + public boolean hasMultiHiddenColumnRegions() { try { - LOCK.readLock().lock(); - if (hiddenColumns != null) - { - int index = hiddenColumns.size() - 1; - do - { - int[] region = hiddenColumns.get(index); - if (pos > region[1]) - { - return index; - } - - index--; - } while (index > -1); - } - - return -1; + return !hiddenColumns.isEmpty() && hiddenColumns.size() > 1; } finally { LOCK.readLock().unlock(); } - } + /** - * Adds the specified column range to the hidden columns - * - * @param start - * @param end + * Returns a hashCode built from hidden column ranges */ - public void hideColumns(int start, int end) + @Override + public int hashCode() { - boolean wasAlreadyLocked = false; try { - // check if the write lock was already locked by this thread, - // as this method can be called internally in loops within HiddenColumns - if (!LOCK.isWriteLockedByCurrentThread()) - { - LOCK.writeLock().lock(); - } - else - { - wasAlreadyLocked = true; - } - - if (hiddenColumns == null) - { - hiddenColumns = new ArrayList<>(); - } + LOCK.readLock().lock(); + int hashCode = 1; - /* - * traverse existing hidden ranges and insert / amend / append as - * appropriate - */ - for (int i = 0; i < hiddenColumns.size(); i++) + for (int[] hidden : hiddenColumns) { - int[] region = hiddenColumns.get(i); - - if (end < region[0] - 1) - { - /* - * insert discontiguous preceding range - */ - hiddenColumns.add(i, new int[] { start, end }); - return; - } - - if (end <= region[1]) - { - /* - * new range overlaps existing, or is contiguous preceding it - adjust - * start column - */ - region[0] = Math.min(region[0], start); - return; - } - - if (start <= region[1] + 1) - { - /* - * new range overlaps existing, or is contiguous following it - adjust - * start and end columns - */ - region[0] = Math.min(region[0], start); - region[1] = Math.max(region[1], end); - - /* - * also update or remove any subsequent ranges - * that are overlapped - */ - while (i < hiddenColumns.size() - 1) - { - int[] nextRegion = hiddenColumns.get(i + 1); - if (nextRegion[0] > end + 1) - { - /* - * gap to next hidden range - no more to update - */ - break; - } - region[1] = Math.max(nextRegion[1], end); - hiddenColumns.remove(i + 1); - } - return; - } + hashCode = HASH_MULTIPLIER * hashCode + hidden[0]; + hashCode = HASH_MULTIPLIER * hashCode + hidden[1]; } - - /* - * remaining case is that the new range follows everything else - */ - hiddenColumns.add(new int[] { start, end }); + return hashCode; } finally { - if (!wasAlreadyLocked) - { - LOCK.writeLock().unlock(); - } + LOCK.readLock().unlock(); } } - public boolean isVisible(int column) + /** + * Hide columns corresponding to the marked bits + * + * @param inserts + * - columns mapped to bits starting from zero + */ + public void hideColumns(BitSet inserts) + { + hideColumns(inserts, 0, inserts.length() - 1); + } + + /** + * Hide columns corresponding to the marked bits, within the range + * [start,end]. Entries in tohide which are outside [start,end] are ignored. + * + * @param tohide + * columns mapped to bits starting from zero + * @param start + * start of range to hide columns within + * @param end + * end of range to hide columns within + */ + private void hideColumns(BitSet tohide, int start, int end) { try { - LOCK.readLock().lock(); - - if (hiddenColumns != null) + LOCK.writeLock().lock(); + for (int firstSet = tohide + .nextSetBit(start), lastSet = start; firstSet >= start + && lastSet <= end; firstSet = tohide + .nextSetBit(lastSet)) { - for (int[] region : hiddenColumns) + lastSet = tohide.nextClearBit(firstSet); + if (lastSet <= end) { - if (column >= region[0] && column <= region[1]) - { - return false; - } + hideColumns(firstSet, lastSet - 1); + } + else if (firstSet <= end) + { + hideColumns(firstSet, end); } } - - return true; + cursor = new HiddenColumnsCursor(hiddenColumns); } finally { - LOCK.readLock().unlock(); - } - } - - private ArrayList copyHiddenRegionsToArrayList() - { - int size = 0; - if (hiddenColumns != null) - { - size = hiddenColumns.size(); - } - ArrayList copy = new ArrayList<>(size); - - for (int i = 0, j = size; i < j; i++) - { - int[] rh; - int[] cp; - rh = hiddenColumns.get(i); - if (rh != null) - { - cp = new int[rh.length]; - System.arraycopy(rh, 0, cp, 0, rh.length); - copy.add(cp); - } + LOCK.writeLock().unlock(); } - - return copy; } /** - * Returns a copy of the vector of hidden regions, as an ArrayList. Before - * using this method please consider if you really need access to the hidden - * regions - a new (or existing!) method on HiddenColumns might be more - * appropriate. + * Hide columns corresponding to the marked bits, within the range + * [start,end]. Entries in tohide which are outside [start,end] are ignored. + * NB Existing entries in [start,end] are cleared. * - * @return hidden regions as an ArrayList of [start,end] pairs + * @param tohide + * columns mapped to bits starting from zero + * @param start + * start of range to hide columns within + * @param end + * end of range to hide columns within */ - public ArrayList getHiddenColumnsCopy() + public void clearAndHideColumns(BitSet tohide, int start, int end) { - try - { - LOCK.readLock().lock(); - return copyHiddenRegionsToArrayList(); - } finally - { - LOCK.readLock().unlock(); - } + clearHiddenColumnsInRange(start, end); + hideColumns(tohide, start, end); } /** - * propagate shift in alignment columns to column selection + * Make all columns in the range [start,end] visible * * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) + * start of range to show columns + * @param end + * end of range to show columns */ - public List compensateForEdit(int start, int change, - ColumnSelection sel) + private void clearHiddenColumnsInRange(int start, int end) { try { LOCK.writeLock().lock(); - List deletedHiddenColumns = null; - - if (hiddenColumns != null) + + if (!hiddenColumns.isEmpty()) { - deletedHiddenColumns = new ArrayList<>(); - int hSize = hiddenColumns.size(); - for (int i = 0; i < hSize; i++) + HiddenCursorPosition pos = cursor.findRegionForColumn(start, false); + int index = pos.getRegionIndex(); + + if (index != -1 && index != hiddenColumns.size()) { - int[] region = hiddenColumns.get(i); - if (region[0] > start && start + change > region[1]) + // regionIndex is the region which either contains start + // or lies to the right of start + int[] region = hiddenColumns.get(index); + if (region[0] < start && region[1] >= start) { - deletedHiddenColumns.add(region); - - hiddenColumns.remove(i); - i--; - hSize--; - continue; + // region contains start, truncate so that it ends just before start + numColumns -= region[1] - start + 1; + region[1] = start - 1; + index++; } - if (region[0] > start) + int endi = index; + while (endi < hiddenColumns.size()) { - region[0] -= change; - region[1] -= change; - } + region = hiddenColumns.get(endi); - if (region[0] < 0) - { - region[0] = 0; + if (region[1] > end) + { + if (region[0] <= end) + { + // region contains end, truncate so it starts just after end + numColumns -= end - region[0] + 1; + region[0] = end + 1; + } + break; + } + + numColumns -= region[1] - region[0] + 1; + endi++; } + hiddenColumns.subList(index, endi).clear(); } - this.revealHiddenColumns(0, sel); + cursor = new HiddenColumnsCursor(hiddenColumns); } - - return deletedHiddenColumns; } finally { LOCK.writeLock().unlock(); @@ -717,47 +895,24 @@ public class HiddenColumns } /** - * propagate shift in alignment columns to column selection special version of - * compensateForEdit - allowing for edits within hidden regions * - * @param start - * beginning of edit - * @param left - * shift in edit (+ve for removal, or -ve for inserts) + * @param updates + * BitSet where hidden columns will be marked */ - public void compensateForDelEdits(int start, int change) + protected void andNot(BitSet updates) { try { LOCK.writeLock().lock(); - if (hiddenColumns != null) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.get(i); - if (region[0] >= start) - { - region[0] -= change; - } - if (region[1] >= start) - { - region[1] -= change; - } - if (region[1] < region[0]) - { - hiddenColumns.remove(i--); - } - if (region[0] < 0) - { - region[0] = 0; - } - if (region[1] < 0) - { - region[1] = 0; - } - } + BitSet hiddenBitSet = new BitSet(); + for (int[] range : hiddenColumns) + { + hiddenBitSet.set(range[0], range[1] + 1); } + hiddenBitSet.andNot(updates); + hiddenColumns.clear(); + hideColumns(hiddenBitSet); } finally { LOCK.writeLock().unlock(); @@ -765,135 +920,80 @@ public class HiddenColumns } /** - * return all visible segments between the given start and end boundaries + * Calculate the visible start and end index of an alignment. * - * @param start - * (first column inclusive from 0) - * @param end - * (last column - not inclusive) - * @return int[] {i_start, i_end, ..} where intervals lie in - * start<=i_start<=i_end 0) - { - List visiblecontigs = new ArrayList<>(); - List regions = getHiddenRegions(); - int vstart = start; - int[] region; - int hideStart; - int hideEnd; + int firstVisible = 0; + int lastVisible = width - 1; - for (int j = 0; vstart < end && j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideEnd < vstart) - { - continue; - } - if (hideStart > vstart) - { - visiblecontigs.add(new int[] { vstart, hideStart - 1 }); - } - vstart = hideEnd + 1; - } + if (!hiddenColumns.isEmpty()) + { + // first visible col with index 0, convert to absolute index + firstVisible = visibleToAbsoluteColumn(0); - if (vstart < end) + // last visible column is either immediately to left of + // last hidden region, or is just the last column in the alignment + int[] lastregion = hiddenColumns.get(hiddenColumns.size() - 1); + if (lastregion[1] == width - 1) { - visiblecontigs.add(new int[] { vstart, end - 1 }); + // last region is at very end of alignment + // last visible column immediately precedes it + lastVisible = lastregion[0] - 1; } - int[] vcontigs = new int[visiblecontigs.size() * 2]; - for (int i = 0, j = visiblecontigs.size(); i < j; i++) - { - int[] vc = visiblecontigs.get(i); - visiblecontigs.set(i, null); - vcontigs[i * 2] = vc[0]; - vcontigs[i * 2 + 1] = vc[1]; - } - visiblecontigs.clear(); - return vcontigs; - } - else - { - return new int[] { start, end - 1 }; } + return new int[] { firstVisible, lastVisible }; + } finally { LOCK.readLock().unlock(); } } - public String[] getVisibleSequenceStrings(int start, int end, - SequenceI[] seqs) + /** + * Finds the hidden region (if any) which starts or ends at res + * + * @param res + * visible residue position, unadjusted for hidden columns + * @return region as [start,end] or null if no matching region is found. If + * res is adjacent to two regions, returns the left region. + */ + public int[] getRegionWithEdgeAtRes(int res) { try { LOCK.readLock().lock(); - int iSize = seqs.length; - String[] selections = new String[iSize]; - if (hiddenColumns != null && hiddenColumns.size() > 0) - { - for (int i = 0; i < iSize; i++) - { - StringBuffer visibleSeq = new StringBuffer(); - List regions = getHiddenRegions(); - - int blockStart = start; - int blockEnd = end; - int[] region; - int hideStart; - int hideEnd; + int adjres = visibleToAbsoluteColumn(res); - for (int j = 0; j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideStart < start) - { - continue; - } - - blockStart = Math.min(blockStart, hideEnd + 1); - blockEnd = Math.min(blockEnd, hideStart); - - if (blockStart > blockEnd) - { - break; - } - - visibleSeq.append(seqs[i].getSequence(blockStart, blockEnd)); - - blockStart = hideEnd + 1; - blockEnd = end; - } - - if (end > blockStart) - { - visibleSeq.append(seqs[i].getSequence(blockStart, end)); - } + int[] reveal = null; - selections[i] = visibleSeq.toString(); - } - } - else + if (!hiddenColumns.isEmpty()) { - for (int i = 0; i < iSize; i++) + // look for a region ending just before adjres + int regionindex = cursor.findRegionForColumn(adjres - 1, false) + .getRegionIndex(); + if (regionindex < hiddenColumns.size() + && hiddenColumns.get(regionindex)[1] == adjres - 1) + { + reveal = hiddenColumns.get(regionindex); + } + // check if the region ends just after adjres + else if (regionindex < hiddenColumns.size() + && hiddenColumns.get(regionindex)[0] == adjres + 1) { - selections[i] = seqs[i].getSequenceAsString(start, end); + reveal = hiddenColumns.get(regionindex); } } + return reveal; - return selections; } finally { LOCK.readLock().unlock(); @@ -901,92 +1001,14 @@ public class HiddenColumns } /** - * Locate the first and last position visible for this sequence. if seq isn't - * visible then return the position of the left and right of the hidden - * boundary region, and the corresponding alignment column indices for the - * extent of the sequence - * - * @param seq - * @return int[] { visible start, visible end, first seqpos, last seqpos, - * alignment index for seq start, alignment index for seq end } + * Return an iterator over the hidden regions */ - public int[] locateVisibleBoundsOfSequence(SequenceI seq) + public Iterator iterator() { try { LOCK.readLock().lock(); - int fpos = seq.getStart(); - int lpos = seq.getEnd(); - int start = 0; - - if (hiddenColumns == null || hiddenColumns.size() == 0) - { - int ifpos = seq.findIndex(fpos) - 1; - int ilpos = seq.findIndex(lpos) - 1; - return new int[] { ifpos, ilpos, fpos, lpos, ifpos, ilpos }; - } - - // Simply walk along the sequence whilst watching for hidden column - // boundaries - List regions = getHiddenRegions(); - int spos = fpos; - int lastvispos = -1; - int rcount = 0; - int hideStart = seq.getLength(); - int hideEnd = -1; - int visPrev = 0; - int visNext = 0; - int firstP = -1; - int lastP = -1; - boolean foundStart = false; - for (int p = 0, pLen = seq.getLength(); spos <= seq.getEnd() - && p < pLen; p++) - { - if (!Comparison.isGap(seq.getCharAt(p))) - { - // keep track of first/last column - // containing sequence data regardless of visibility - if (firstP == -1) - { - firstP = p; - } - lastP = p; - // update hidden region start/end - while (hideEnd < p && rcount < regions.size()) - { - int[] region = regions.get(rcount++); - visPrev = visNext; - visNext += region[0] - visPrev; - hideStart = region[0]; - hideEnd = region[1]; - } - if (hideEnd < p) - { - hideStart = seq.getLength(); - } - // update visible boundary for sequence - if (p < hideStart) - { - if (!foundStart) - { - fpos = spos; - start = p; - foundStart = true; - } - lastvispos = p; - lpos = spos; - } - // look for next sequence position - spos++; - } - } - if (foundStart) - { - return new int[] { findColumnPosition(start), - findColumnPosition(lastvispos), fpos, lpos, firstP, lastP }; - } - // otherwise, sequence was completely hidden - return new int[] { visPrev, visNext, 0, 0, firstP, lastP }; + return new RangeIterator(hiddenColumns); } finally { LOCK.readLock().unlock(); @@ -994,120 +1016,54 @@ public class HiddenColumns } /** - * delete any columns in alignmentAnnotation that are hidden (including - * sequence associated annotation). + * Return a bounded iterator over the hidden regions * - * @param alignmentAnnotation + * @param start + * position to start from (inclusive, absolute column position) + * @param end + * position to end at (inclusive, absolute column position) + * @return */ - public void makeVisibleAnnotation(AlignmentAnnotation alignmentAnnotation) + public Iterator getBoundedIterator(int start, int end) { - makeVisibleAnnotation(-1, -1, alignmentAnnotation); + try + { + LOCK.readLock().lock(); + return new RangeIterator(start, end, hiddenColumns); + } finally + { + LOCK.readLock().unlock(); + } } /** - * delete any columns in alignmentAnnotation that are hidden (including - * sequence associated annotation). + * Return a bounded iterator over the *visible* start positions of hidden + * regions * * @param start - * remove any annotation to the right of this column + * position to start from (inclusive, visible column position) * @param end - * remove any annotation to the left of this column - * @param alignmentAnnotation - * the annotation to operate on + * position to end at (inclusive, visible column position) */ - public void makeVisibleAnnotation(int start, int end, - AlignmentAnnotation alignmentAnnotation) + public Iterator getStartRegionIterator(int start, int end) { try { LOCK.readLock().lock(); - if (alignmentAnnotation.annotations == null) - { - return; - } - if (start == end && end == -1) - { - start = 0; - end = alignmentAnnotation.annotations.length; - } - if (hiddenColumns != null && hiddenColumns.size() > 0) - { - // then mangle the alignmentAnnotation annotation array - Vector annels = new Vector<>(); - Annotation[] els = null; - List regions = getHiddenRegions(); - int blockStart = start; - int blockEnd = end; - int[] region; - int hideStart; - int hideEnd; - int w = 0; - - for (int j = 0; j < regions.size(); j++) - { - region = regions.get(j); - hideStart = region[0]; - hideEnd = region[1]; - - if (hideStart < start) - { - continue; - } - - blockStart = Math.min(blockStart, hideEnd + 1); - blockEnd = Math.min(blockEnd, hideStart); - - if (blockStart > blockEnd) - { - break; - } - - annels.addElement(els = new Annotation[blockEnd - blockStart]); - System.arraycopy(alignmentAnnotation.annotations, blockStart, els, - 0, els.length); - w += els.length; - blockStart = hideEnd + 1; - blockEnd = end; - } - if (end > blockStart) - { - annels.addElement(els = new Annotation[end - blockStart + 1]); - if ((els.length - + blockStart) <= alignmentAnnotation.annotations.length) - { - // copy just the visible segment of the annotation row - System.arraycopy(alignmentAnnotation.annotations, blockStart, - els, 0, els.length); - } - else - { - // copy to the end of the annotation row - System.arraycopy(alignmentAnnotation.annotations, blockStart, - els, 0, - (alignmentAnnotation.annotations.length - blockStart)); - } - w += els.length; - } - if (w == 0) - { - return; - } + // get absolute position of column in alignment + int absoluteStart = visibleToAbsoluteColumn(start); - alignmentAnnotation.annotations = new Annotation[w]; - w = 0; + // Get cursor position and supply it to the iterator: + // Since we want visible region start, we look for a cursor for the + // (absoluteStart-1), then if absoluteStart is the start of a visible + // region we'll get the cursor pointing to the region before, which is + // what we want + HiddenCursorPosition pos = cursor + .findRegionForColumn(absoluteStart - 1, false); - for (Annotation[] chnk : annels) - { - System.arraycopy(chnk, 0, alignmentAnnotation.annotations, w, - chnk.length); - w += chnk.length; - } - } - else - { - alignmentAnnotation.restrict(start, end); - } + return new StartRegionIterator(pos, start, end, + hiddenColumns); } finally { LOCK.readLock().unlock(); @@ -1115,15 +1071,21 @@ public class HiddenColumns } /** + * Return an iterator over visible *columns* (not regions) between the given + * start and end boundaries * - * @return true if there are columns hidden + * @param start + * first column (inclusive) + * @param end + * last column (inclusive) */ - public boolean hasHiddenColumns() + public Iterator getVisibleColsIterator(int start, int end) { try { LOCK.readLock().lock(); - return hiddenColumns != null && hiddenColumns.size() > 0; + return new RangeElementsIterator( + new VisibleContigsIterator(start, end + 1, hiddenColumns)); } finally { LOCK.readLock().unlock(); @@ -1131,577 +1093,36 @@ public class HiddenColumns } /** + * return an iterator over visible segments between the given start and end + * boundaries * - * @return true if there are more than one set of columns hidden + * @param start + * first column, inclusive from 0 + * @param end + * last column - not inclusive + * @param useVisibleCoords + * if true, start and end are visible column positions, not absolute + * positions* */ - public boolean hasManyHiddenColumns() + public VisibleContigsIterator getVisContigsIterator(int start, + int end, + boolean useVisibleCoords) { + int adjstart = start; + int adjend = end; + if (useVisibleCoords) + { + adjstart = visibleToAbsoluteColumn(start); + adjend = visibleToAbsoluteColumn(end); + } + try { LOCK.readLock().lock(); - return hiddenColumns != null && hiddenColumns.size() > 1; + return new VisibleContigsIterator(adjstart, adjend, hiddenColumns); } finally { LOCK.readLock().unlock(); } } - - /** - * mark the columns corresponding to gap characters as hidden in the column - * selection - * - * @param sr - */ - public void hideInsertionsFor(SequenceI sr) - { - try - { - LOCK.writeLock().lock(); - List inserts = sr.getInsertions(); - for (int[] r : inserts) - { - hideColumns(r[0], r[1]); - } - } finally - { - LOCK.writeLock().unlock(); - } - } - - /** - * Unhides, and adds to the selection list, all hidden columns - */ - public void revealAllHiddenColumns(ColumnSelection sel) - { - try - { - LOCK.writeLock().lock(); - if (hiddenColumns != null) - { - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.get(i); - for (int j = region[0]; j < region[1] + 1; j++) - { - sel.addElement(j); - } - } - } - - hiddenColumns = null; - } finally - { - LOCK.writeLock().unlock(); - } - } - - /** - * Reveals, and marks as selected, the hidden column range with the given - * start column - * - * @param start - */ - public void revealHiddenColumns(int start, ColumnSelection sel) - { - try - { - LOCK.writeLock().lock(); - for (int i = 0; i < hiddenColumns.size(); i++) - { - int[] region = hiddenColumns.get(i); - if (start == region[0]) - { - for (int j = region[0]; j < region[1] + 1; j++) - { - sel.addElement(j); - } - - hiddenColumns.remove(region); - break; - } - } - if (hiddenColumns.size() == 0) - { - hiddenColumns = null; - } - } finally - { - LOCK.writeLock().unlock(); - } - } - - /** - * removes intersection of position,length ranges in deletions from the - * start,end regions marked in intervals. - * - * @param shifts - * @param intervals - * @return - */ - private boolean pruneIntervalList(final List shifts, - ArrayList intervals) - { - boolean pruned = false; - int i = 0; - int j = intervals.size() - 1; - int s = 0; - int t = shifts.size() - 1; - int[] hr = intervals.get(i); - int[] sr = shifts.get(s); - while (i <= j && s <= t) - { - boolean trailinghn = hr[1] >= sr[0]; - if (!trailinghn) - { - if (i < j) - { - hr = intervals.get(++i); - } - else - { - i++; - } - continue; - } - int endshift = sr[0] + sr[1]; // deletion ranges - -ve means an insert - if (endshift < hr[0] || endshift < sr[0]) - { // leadinghc disjoint or not a deletion - if (s < t) - { - sr = shifts.get(++s); - } - else - { - s++; - } - continue; - } - boolean leadinghn = hr[0] >= sr[0]; - boolean leadinghc = hr[0] < endshift; - boolean trailinghc = hr[1] < endshift; - if (leadinghn) - { - if (trailinghc) - { // deleted hidden region. - intervals.remove(i); - pruned = true; - j--; - if (i <= j) - { - hr = intervals.get(i); - } - continue; - } - if (leadinghc) - { - hr[0] = endshift; // clip c terminal region - leadinghn = !leadinghn; - pruned = true; - } - } - if (!leadinghn) - { - if (trailinghc) - { - if (trailinghn) - { - hr[1] = sr[0] - 1; - pruned = true; - } - } - else - { - // sr contained in hr - if (s < t) - { - sr = shifts.get(++s); - } - else - { - s++; - } - continue; - } - } - } - return pruned; // true if any interval was removed or modified by - // operations. - } - - /** - * remove any hiddenColumns or selected columns and shift remaining based on a - * series of position, range deletions. - * - * @param deletions - */ - public void pruneDeletions(List shifts) - { - try - { - LOCK.writeLock().lock(); - // delete any intervals intersecting. - if (hiddenColumns != null) - { - pruneIntervalList(shifts, hiddenColumns); - if (hiddenColumns != null && hiddenColumns.size() == 0) - { - hiddenColumns = null; - } - } - } finally - { - LOCK.writeLock().unlock(); - } - } - - /** - * Add gaps into the sequences aligned to profileseq under the given - * AlignmentView - * - * @param profileseq - * @param al - * - alignment to have gaps inserted into it - * @param input - * - alignment view where sequence corresponding to profileseq is - * first entry - * @return new HiddenColumns for new alignment view, with insertions into - * profileseq marked as hidden. - */ - public static HiddenColumns propagateInsertions(SequenceI profileseq, - AlignmentI al, AlignmentView input) - { - int profsqpos = 0; - - char gc = al.getGapCharacter(); - Object[] alandhidden = input.getAlignmentAndHiddenColumns(gc); - HiddenColumns nview = (HiddenColumns) alandhidden[1]; - SequenceI origseq = ((SequenceI[]) alandhidden[0])[profsqpos]; - nview.propagateInsertions(profileseq, al, origseq); - return nview; - } - - /** - * - * @param profileseq - * - sequence in al which corresponds to origseq - * @param al - * - alignment which is to have gaps inserted into it - * @param origseq - * - sequence corresponding to profileseq which defines gap map for - * modifying al - */ - private void propagateInsertions(SequenceI profileseq, AlignmentI al, - SequenceI origseq) - { - char gc = al.getGapCharacter(); - // recover mapping between sequence's non-gap positions and positions - // mapping to view. - pruneDeletions(ShiftList.parseMap(origseq.gapMap())); - int[] viscontigs = getVisibleContigs(0, profileseq.getLength()); - int spos = 0; - int offset = 0; - - // add profile to visible contigs - for (int v = 0; v < viscontigs.length; v += 2) - { - if (viscontigs[v] > spos) - { - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = viscontigs[v] - spos; s < ns; s++) - { - sb.append(gc); - } - for (int s = 0, ns = al.getHeight(); s < ns; s++) - { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj != profileseq) - { - String sq = al.getSequenceAt(s).getSequenceAsString(); - if (sq.length() <= spos + offset) - { - // pad sequence - int diff = spos + offset - sq.length() - 1; - if (diff > 0) - { - // pad gaps - sq = sq + sb; - while ((diff = spos + offset - sq.length() - 1) > 0) - { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - } - } - sq += sb.toString(); - } - else - { - al.getSequenceAt(s).setSequence(sq.substring(0, spos + offset) - + sb.toString() + sq.substring(spos + offset)); - } - } - } - // offset+=sb.length(); - } - spos = viscontigs[v + 1] + 1; - } - if ((offset + spos) < profileseq.getLength()) - { - // pad the final region with gaps. - StringBuffer sb = new StringBuffer(); - for (int s = 0, ns = profileseq.getLength() - spos - - offset; s < ns; s++) - { - sb.append(gc); - } - for (int s = 0, ns = al.getHeight(); s < ns; s++) - { - SequenceI sqobj = al.getSequenceAt(s); - if (sqobj == profileseq) - { - continue; - } - String sq = sqobj.getSequenceAsString(); - // pad sequence - int diff = origseq.getLength() - sq.length(); - while (diff > 0) - { - // sq = sq - // + ((diff >= sb.length()) ? sb.toString() : sb - // .substring(0, diff)); - if (diff >= sb.length()) - { - sq += sb.toString(); - } - else - { - char[] buf = new char[diff]; - sb.getChars(0, diff, buf, 0); - sq += buf.toString(); - } - diff = origseq.getLength() - sq.length(); - } - } - } - } - - /** - * remove any hiddenColumns or selected columns and shift remaining based on a - * series of position, range deletions. - * - * @param deletions - */ - private void pruneDeletions(ShiftList deletions) - { - if (deletions != null) - { - final List shifts = deletions.getShifts(); - if (shifts != null && shifts.size() > 0) - { - pruneDeletions(shifts); - - // and shift the rest. - this.compensateForEdits(deletions); - } - } - } - - /** - * Adjust hidden column boundaries based on a series of column additions or - * deletions in visible regions. - * - * @param shiftrecord - * @return - */ - private ShiftList compensateForEdits(ShiftList shiftrecord) - { - if (shiftrecord != null) - { - final List shifts = shiftrecord.getShifts(); - if (shifts != null && shifts.size() > 0) - { - int shifted = 0; - for (int i = 0, j = shifts.size(); i < j; i++) - { - int[] sh = shifts.get(i); - compensateForDelEdits(shifted + sh[0], sh[1]); - shifted -= sh[1]; - } - } - return shiftrecord.getInverse(); - } - return null; - } - - /** - * Returns a hashCode built from hidden column ranges - */ - @Override - public int hashCode() - { - try - { - LOCK.readLock().lock(); - int hashCode = 1; - if (hiddenColumns != null) - { - for (int[] hidden : hiddenColumns) - { - hashCode = 31 * hashCode + hidden[0]; - hashCode = 31 * hashCode + hidden[1]; - } - } - return hashCode; - } finally - { - LOCK.readLock().unlock(); - } - } - - /** - * Hide columns corresponding to the marked bits - * - * @param inserts - * - columns map to bits starting from zero - */ - public void hideMarkedBits(BitSet inserts) - { - try - { - LOCK.writeLock().lock(); - for (int firstSet = inserts - .nextSetBit(0), lastSet = 0; firstSet >= 0; firstSet = inserts - .nextSetBit(lastSet)) - { - lastSet = inserts.nextClearBit(firstSet); - hideColumns(firstSet, lastSet - 1); - } - } finally - { - LOCK.writeLock().unlock(); - } - } - - /** - * - * @param inserts - * BitSet where hidden columns will be marked - */ - public void markHiddenRegions(BitSet inserts) - { - try - { - LOCK.readLock().lock(); - if (hiddenColumns == null) - { - return; - } - for (int[] range : hiddenColumns) - { - inserts.set(range[0], range[1] + 1); - } - } finally - { - LOCK.readLock().unlock(); - } - } - - /** - * Calculate the visible start and end index of an alignment. - * - * @param width - * full alignment width - * @return integer array where: int[0] = startIndex, and int[1] = endIndex - */ - public int[] getVisibleStartAndEndIndex(int width) - { - try - { - LOCK.readLock().lock(); - int[] alignmentStartEnd = new int[] { 0, width - 1 }; - int startPos = alignmentStartEnd[0]; - int endPos = alignmentStartEnd[1]; - - int[] lowestRange = new int[] { -1, -1 }; - int[] higestRange = new int[] { -1, -1 }; - - if (hiddenColumns == null) - { - return new int[] { startPos, endPos }; - } - - for (int[] hiddenCol : hiddenColumns) - { - lowestRange = (hiddenCol[0] <= startPos) ? hiddenCol : lowestRange; - higestRange = (hiddenCol[1] >= endPos) ? hiddenCol : higestRange; - } - - if (lowestRange[0] == -1 && lowestRange[1] == -1) - { - startPos = alignmentStartEnd[0]; - } - else - { - startPos = lowestRange[1] + 1; - } - - if (higestRange[0] == -1 && higestRange[1] == -1) - { - endPos = alignmentStartEnd[1]; - } - else - { - endPos = higestRange[0] - 1; - } - return new int[] { startPos, endPos }; - } finally - { - LOCK.readLock().unlock(); - } - - } - - /** - * Finds the hidden region (if any) which starts or ends at res - * - * @param res - * visible residue position, unadjusted for hidden columns - * @return region as [start,end] or null if no matching region is found - */ - public int[] getRegionWithEdgeAtRes(int res) - { - try - { - LOCK.readLock().lock(); - int adjres = adjustForHiddenColumns(res); - - int[] reveal = null; - if (hiddenColumns != null) - { - for (int[] region : hiddenColumns) - { - if (adjres + 1 == region[0] || adjres - 1 == region[1]) - { - reveal = region; - break; - } - } - } - return reveal; - } finally - { - LOCK.readLock().unlock(); - } - } - } diff --git a/src/jalview/datamodel/HiddenColumnsCursor.java b/src/jalview/datamodel/HiddenColumnsCursor.java new file mode 100644 index 0000000..2e9d798 --- /dev/null +++ b/src/jalview/datamodel/HiddenColumnsCursor.java @@ -0,0 +1,213 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import java.util.ArrayList; +import java.util.List; + +public class HiddenColumnsCursor +{ + // absolute position of first hidden column + private int firstColumn; + + private List hiddenColumns = new ArrayList<>(); + + private HiddenCursorPosition cursorPos = new HiddenCursorPosition(0, 0); + + protected HiddenColumnsCursor() + { + + } + + protected HiddenColumnsCursor(List hiddenCols) + { + resetCursor(hiddenCols, 0, 0); + } + + protected HiddenColumnsCursor(List hiddenCols, int index, + int hiddencount) + { + resetCursor(hiddenCols, index, hiddencount); + } + + /** + * Reset the cursor with a new hidden columns collection, where we know in + * advance the index and hidden columns count of a particular location. + * + * @param hiddenCols + * new hidden columns collection + * @param index + * cursor index to reset to + * @param hiddencount + * hidden columns count to reset to + */ + private void resetCursor(List hiddenCols, int index, + int hiddencount) + { + hiddenColumns = hiddenCols; + if (!hiddenCols.isEmpty()) + { + firstColumn = hiddenColumns.get(0)[0]; + cursorPos = new HiddenCursorPosition(index, + hiddencount); + } + } + + /** + * Get the cursor pointing to the hidden region that column is within (if + * column is hidden) or which is to the right of column (if column is + * visible). If no hidden columns are to the right, returns a cursor pointing + * to an imaginary hidden region beyond the end of the hidden columns + * collection (this ensures the count of previous hidden columns is correct). + * If hidden columns is empty returns null. + * + * @param column + * index of column in visible or absolute coordinates + * @param useVisible + * true if column is in visible coordinates, false if absolute + * @return cursor pointing to hidden region containing the column (if hidden) + * or to the right of the column (if visible) + */ + protected HiddenCursorPosition findRegionForColumn(int column, + boolean useVisible) + { + if (hiddenColumns.isEmpty()) + { + return null; + } + + // used to add in hiddenColumns offset when working with visible columns + int offset = (useVisible ? 1 : 0); + + HiddenCursorPosition pos = cursorPos; + int index = pos.getRegionIndex(); + int hiddenCount = pos.getHiddenSoFar(); + + if (column < firstColumn) + { + pos = new HiddenCursorPosition(0, 0); + } + + // column is after current region + else if ((index < hiddenColumns.size()) + && (hiddenColumns.get(index)[0] <= column + + offset * hiddenCount)) + { + // iterate from where we are now, if we're lucky we'll be close by + // (but still better than iterating from 0) + // stop when we find the region *before* column + // i.e. the next region starts after column or if not, ends after column + pos = searchForward(pos, column, useVisible); + } + + // column is before current region + else + { + pos = searchBackward(pos, column, useVisible); + } + cursorPos = pos; + return pos; + } + + /** + * Search forwards through the hidden columns collection to find the hidden + * region immediately before a column + * + * @param pos + * current position + * @param column + * column to locate + * @param useVisible + * whether using visible or absolute coordinates + * @return position of region before column + */ + private HiddenCursorPosition searchForward(HiddenCursorPosition pos, + int column, boolean useVisible) + { + HiddenCursorPosition p = pos; + if (useVisible) + { + while ((p.getRegionIndex() < hiddenColumns.size()) + && hiddenColumns.get(p.getRegionIndex())[0] <= column + + p.getHiddenSoFar()) + { + p = stepForward(p); + } + } + else + { + while ((p.getRegionIndex() < hiddenColumns.size()) + && hiddenColumns.get(p.getRegionIndex())[1] < column) + { + p = stepForward(p); + } + } + return p; + } + + /** + * Move to the next (rightwards) hidden region after a given cursor position + * + * @param p + * current position of cursor + * @return new position of cursor at next region + */ + private HiddenCursorPosition stepForward(HiddenCursorPosition p) + { + int[] region = hiddenColumns.get(p.getRegionIndex()); + + // increment the index, and add this region's hidden columns to the hidden + // column count + return new HiddenCursorPosition(p.getRegionIndex() + 1, + p.getHiddenSoFar() + region[1] - region[0] + 1); + } + + /** + * Search backwards through the hidden columns collection to find the hidden + * region immediately before (left of) a given column + * + * @param pos + * current position + * @param column + * column to locate + * @param useVisible + * whether using visible or absolute coordinates + * @return position of region immediately to left of column + */ + private HiddenCursorPosition searchBackward(HiddenCursorPosition p, + int column, boolean useVisible) + { + int i = p.getRegionIndex(); + int h = p.getHiddenSoFar(); + + // used to add in hiddenColumns offset when working with visible columns + int offset = (useVisible ? 1 : 0); + + while ((i > 0) && (hiddenColumns.get(i - 1)[1] >= column + offset * h)) + { + i--; + int[] region = hiddenColumns.get(i); + h -= region[1] - region[0] + 1; + } + return new HiddenCursorPosition(i, h); + } + +} diff --git a/src/jalview/datamodel/HiddenCursorPosition.java b/src/jalview/datamodel/HiddenCursorPosition.java new file mode 100644 index 0000000..160ed71 --- /dev/null +++ b/src/jalview/datamodel/HiddenCursorPosition.java @@ -0,0 +1,26 @@ +package jalview.datamodel; + +public final class HiddenCursorPosition +{ + // index of last visited region + private final int regionIndex; + + // number of hidden columns before last visited region + private final int hiddenSoFar; + + public HiddenCursorPosition(int index, int hiddencount) + { + regionIndex = index; + hiddenSoFar = hiddencount; + } + + public int getRegionIndex() + { + return regionIndex; + } + + public int getHiddenSoFar() + { + return hiddenSoFar; + } +} diff --git a/src/jalview/datamodel/HiddenMarkovModel.java b/src/jalview/datamodel/HiddenMarkovModel.java new file mode 100644 index 0000000..a4270cd --- /dev/null +++ b/src/jalview/datamodel/HiddenMarkovModel.java @@ -0,0 +1,612 @@ +package jalview.datamodel; + +import jalview.io.HMMFile; +import jalview.schemes.ResidueProperties; +import jalview.util.Comparison; +import jalview.util.MapList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Data structure which stores a hidden Markov model + * + * @author TZVanaalten + * + */ +public class HiddenMarkovModel +{ + private static final char GAP_DASH = '-'; + + public final static String YES = "yes"; + + public final static String NO = "no"; + + public static final int MATCHTOMATCH = 0; + + public static final int MATCHTOINSERT = 1; + + public static final int MATCHTODELETE = 2; + + public static final int INSERTTOMATCH = 3; + + public static final int INSERTTOINSERT = 4; + + public static final int DELETETOMATCH = 5; + + public static final int DELETETODELETE = 6; + + private static final double LOG2 = Math.log(2); + + /* + * properties read from HMM file header lines + */ + private Map fileProperties = new HashMap<>(); + + private String fileHeader; + + /* + * the symbols used in this model e.g. "ACGT" + */ + private String alphabet; + + /* + * symbol lookup index into the alphabet for 'A' to 'Z' + */ + private int[] symbolIndexLookup = new int['Z' - 'A' + 1]; + + /* + * Nodes in the model. The begin node is at index 0, and contains + * average emission probabilities for each symbol. + */ + private List nodes = new ArrayList<>(); + + /* + * the aligned HMM consensus sequence extracted from the HMM profile + */ + private SequenceI hmmSeq; + + /* + * mapping from HMM nodes to residues of the hmm consensus sequence + */ + private Mapping mapToHmmConsensus; + + /** + * Constructor + */ + public HiddenMarkovModel() + { + } + + /** + * Copy constructor + * + * @param hmm + */ + public HiddenMarkovModel(HiddenMarkovModel hmm) + { + super(); + this.fileProperties = new HashMap<>(hmm.fileProperties); + this.alphabet = hmm.alphabet; + this.nodes = new ArrayList<>(hmm.nodes); + this.symbolIndexLookup = hmm.symbolIndexLookup; + this.fileHeader = new String(hmm.fileHeader); + } + + /** + * Returns the information content at a specified column, calculated as the + * sum (over possible symbols) of the log ratio + * + *
    +   *  log(emission probability / background probability) / log(2)
    +   * 
    + * + * @param column + * column position (base 0) + * @return + */ + public float getInformationContent(int column) + { + float informationContent = 0f; + + for (char symbol : getSymbols().toCharArray()) + { + float freq = ResidueProperties.backgroundFrequencies + .get(getAlphabetType()).get(symbol); + float prob = (float) getMatchEmissionProbability(column, symbol); + informationContent += prob * Math.log(prob / freq); + } + + informationContent = informationContent / (float) LOG2; + + return informationContent; + } + + /** + * Gets the file header of the .hmm file this model came from + * + * @return + */ + public String getFileHeader() + { + return fileHeader; + } + + /** + * Sets the file header of this model. + * + * @param header + */ + public void setFileHeader(String header) + { + fileHeader = header; + } + + /** + * Returns the symbols used in this hidden Markov model + * + * @return + */ + public String getSymbols() + { + return alphabet; + } + + /** + * Gets the node in the hidden Markov model at the specified position. + * + * @param nodeIndex + * The index of the node requested. Node 0 optionally contains the + * average match emission probabilities across the entire model, and + * always contains the insert emission probabilities and state + * transition probabilities for the begin node. Node 1 contains the + * first node in the HMM that can correspond to a column in the + * alignment. + * @return + */ + public HMMNode getNode(int nodeIndex) + { + return nodes.get(nodeIndex); + } + + /** + * Returns the name of the sequence alignment on which the HMM is based. + * + * @return + */ + public String getName() + { + return fileProperties.get(HMMFile.NAME); + } + + /** + * Answers the string value of the property (parsed from an HMM file) for the + * given key, or null if the property is not present + * + * @param key + * @return + */ + public String getProperty(String key) + { + return fileProperties.get(key); + } + + /** + * Answers true if the property with the given key is present with a value of + * "yes" (not case-sensitive), else false + * + * @param key + * @return + */ + public boolean getBooleanProperty(String key) + { + return YES.equalsIgnoreCase(fileProperties.get(key)); + } + + /** + * Returns the length of the hidden Markov model. The value returned is the + * LENG property if specified, else the number of nodes, excluding the begin + * node (which should be the same thing). + * + * @return + */ + public int getLength() + { + if (fileProperties.get(HMMFile.LENGTH) == null) + { + return nodes.size() - 1; // not counting BEGIN node + } + return Integer.parseInt(fileProperties.get(HMMFile.LENGTH)); + } + + /** + * Returns the value of mandatory property "ALPH" - "amino", "DNA", "RNA" are + * the options. Other alphabets may be added. + * + * @return + */ + public String getAlphabetType() + { + return fileProperties.get(HMMFile.ALPHABET); + } + + /** + * Sets the model alphabet to the symbols in the given string (ignoring any + * whitespace), and returns the number of symbols + * + * @param symbols + */ + public int setAlphabet(String symbols) + { + String trimmed = symbols.toUpperCase().replaceAll("\\s", ""); + int count = trimmed.length(); + alphabet = trimmed; + symbolIndexLookup = new int['Z' - 'A' + 1]; + Arrays.fill(symbolIndexLookup, -1); + int ignored = 0; + + /* + * save the symbols in order, and a quick lookup of symbol position + */ + for (short i = 0; i < count; i++) + { + char symbol = trimmed.charAt(i); + if (symbol >= 'A' && symbol <= 'Z' + && symbolIndexLookup[symbol - 'A'] == -1) + { + symbolIndexLookup[symbol - 'A'] = i; + } + else + { + System.err + .println( + "Unexpected or duplicated character in HMM ALPHabet: " + + symbol); + ignored++; + } + } + return count - ignored; + } + + /** + * Answers the node of the model corresponding to an aligned column position + * (0...), or null if there is no such node + * + * @param column + * @return + */ + HMMNode getNodeForColumn(int column) + { + /* + * if the hmm consensus is gapped at the column, + * there is no corresponding node + */ + if (Comparison.isGap(hmmSeq.getCharAt(column))) + { + return null; + } + + /* + * find the node (if any) that is mapped to the + * consensus sequence residue position at the column + */ + int seqPos = hmmSeq.findPosition(column); + int[] nodeNo = mapToHmmConsensus.getMap().locateInFrom(seqPos, seqPos); + if (nodeNo != null) + { + return getNode(nodeNo[0]); + } + return null; + } + + /** + * Gets the match emission probability for a given symbol at a column in the + * alignment. + * + * @param alignColumn + * The index of the alignment column, starting at index 0. Index 0 + * usually corresponds to index 1 in the HMM. + * @param symbol + * The symbol for which the desired probability is being requested. + * @return + * + */ + public double getMatchEmissionProbability(int alignColumn, char symbol) + { + HMMNode node = getNodeForColumn(alignColumn); + int symbolIndex = getSymbolIndex(symbol); + if (node != null && symbolIndex != -1) + { + return node.getMatchEmission(symbolIndex); + } + return 0D; + } + + /** + * Gets the insert emission probability for a given symbol at a column in the + * alignment. + * + * @param alignColumn + * The index of the alignment column, starting at index 0. Index 0 + * usually corresponds to index 1 in the HMM. + * @param symbol + * The symbol for which the desired probability is being requested. + * @return + * + */ + public double getInsertEmissionProbability(int alignColumn, char symbol) + { + HMMNode node = getNodeForColumn(alignColumn); + int symbolIndex = getSymbolIndex(symbol); + if (node != null && symbolIndex != -1) + { + return node.getInsertEmission(symbolIndex); + } + return 0D; + } + + /** + * Gets the state transition probability for a given symbol at a column in the + * alignment. + * + * @param alignColumn + * The index of the alignment column, starting at index 0. Index 0 + * usually corresponds to index 1 in the HMM. + * @param symbol + * The symbol for which the desired probability is being requested. + * @return + * + */ + public double getStateTransitionProbability(int alignColumn, + int transition) + { + HMMNode node = getNodeForColumn(alignColumn); + if (node != null) + { + return node.getStateTransition(transition); + } + return 0D; + } + + /** + * Returns the sequence position linked to the node at the given index. This + * corresponds to an aligned column position (counting from 1). + * + * @param nodeIndex + * The index of the node, starting from index 1. Index 0 is the begin + * node, which does not correspond to a column in the alignment. + * @return + */ + public int getNodeMapPosition(int nodeIndex) + { + return nodes.get(nodeIndex).getResidueNumber(); + } + + /** + * Returns the consensus residue at the specified node. + * + * @param nodeIndex + * The index of the specified node. + * @return + */ + public char getConsensusResidue(int nodeIndex) + { + char value = nodes.get(nodeIndex).getConsensusResidue(); + return value; + } + + /** + * Returns the reference annotation at the specified node. + * + * @param nodeIndex + * The index of the specified node. + * @return + */ + public char getReferenceAnnotation(int nodeIndex) + { + char value = nodes.get(nodeIndex).getReferenceAnnotation(); + return value; + } + + /** + * Returns the mask value at the specified node. + * + * @param nodeIndex + * The index of the specified node. + * @return + */ + public char getMaskedValue(int nodeIndex) + { + char value = nodes.get(nodeIndex).getMaskValue(); + return value; + } + + /** + * Returns the consensus structure at the specified node. + * + * @param nodeIndex + * The index of the specified node. + * @return + */ + public char getConsensusStructure(int nodeIndex) + { + char value = nodes.get(nodeIndex).getConsensusStructure(); + return value; + } + + /** + * Sets a property read from an HMM file + * + * @param key + * @param value + */ + public void setProperty(String key, String value) + { + fileProperties.put(key, value); + } + + /** + * Temporary implementation, should not be used. + * + * @return + */ + public String getViterbi() + { + String value; + value = fileProperties.get(HMMFile.VITERBI); + return value; + } + + /** + * Temporary implementation, should not be used. + * + * @return + */ + public String getMSV() + { + String value; + value = fileProperties.get(HMMFile.MSV); + return value; + } + + /** + * Temporary implementation, should not be used. + * + * @return + */ + public String getForward() + { + String value; + value = fileProperties.get(HMMFile.FORWARD); + return value; + } + + /** + * Constructs the consensus sequence based on the most probable symbol at each + * position. Gap characters are inserted for discontinuities in the node map + * numbering (if provided), else an ungapped sequence is generated. + *

    + * A mapping between the HMM nodes and residue positions of the sequence is + * also built and saved. + * + * @return + */ + void buildConsensusSequence() + { + List toResidues = new ArrayList<>(); + + /* + * if the HMM provided a map to sequence, use those start/end values, + * else just treat it as for a contiguous sequence numbered from 1 + */ + boolean hasMap = getBooleanProperty(HMMFile.MAP); + int start = hasMap ? getNode(1).getResidueNumber() : 1; + int endResNo = hasMap ? getNode(nodes.size() - 1).getResidueNumber() + : (start + getLength() - 1); + char[] sequence = new char[endResNo - start + 1]; + + int lastResNo = start - 1; + int seqOffset = 0; + int gapCount = 0; + + for (int nodeNo = 1; nodeNo < nodes.size(); nodeNo++) + { + HMMNode node = nodes.get(nodeNo); + final int resNo = hasMap ? node.getResidueNumber() : lastResNo + 1; + + /* + * insert gaps if map numbering is not continuous + */ + while (resNo > lastResNo + 1) + { + sequence[seqOffset++] = '-'; + lastResNo++; + gapCount++; + } + char consensusResidue = node.getConsensusResidue(); + if (GAP_DASH == consensusResidue) + { + /* + * no residue annotation in HMM - scan for the symbol + * with the highest match emission probability + */ + int symbolIndex = node.getMaxMatchEmissionIndex(); + consensusResidue = alphabet.charAt(symbolIndex); + if (node.getMatchEmission(symbolIndex) < 0.5D) + { + // follow convention of lower case if match emission prob < 0.5 + consensusResidue = Character.toLowerCase(consensusResidue); + } + } + sequence[seqOffset++] = consensusResidue; + lastResNo = resNo; + } + + Sequence seq = new Sequence(getName(), sequence, start, + lastResNo - gapCount); + seq.createDatasetSequence(); + seq.setHMM(this); + seq.setIsHMMConsensusSequence(true); + + this.hmmSeq = seq; + + /* + * construct and store Mapping of nodes to residues + * note as constructed this is just an identity mapping, + * but it allows for greater flexibility in future + */ + List fromNodes = new ArrayList<>(); + fromNodes.add(new int[] { 1, getLength() }); + toResidues.add(new int[] { seq.getStart(), seq.getEnd() }); + MapList mapList = new MapList(fromNodes, toResidues, 1, 1); + mapToHmmConsensus = new Mapping(seq.getDatasetSequence(), mapList); + } + + + /** + * Answers the aligned consensus sequence for the profile. Note this will + * return null if called before setNodes has been called. + * + * @return + */ + public SequenceI getConsensusSequence() + { + return hmmSeq; + } + + /** + * Answers the index position (0...) of the given symbol, or -1 if not a valid + * symbol for this HMM + * + * @param symbol + * @return + */ + private int getSymbolIndex(char symbol) + { + /* + * symbolIndexLookup holds the index for 'A' to 'Z' + */ + char c = Character.toUpperCase(symbol); + if ('A' <= c && c <= 'Z') + { + return symbolIndexLookup[c - 'A']; + } + return -1; + } + + /** + * Sets the nodes of this HMM, and also extracts the HMM consensus sequence + * and a mapping between node numbers and sequence positions + * + * @param nodeList + */ + public void setNodes(List nodeList) + { + nodes = nodeList; + buildConsensusSequence(); + } +} + diff --git a/src/jalview/datamodel/RangeElementsIterator.java b/src/jalview/datamodel/RangeElementsIterator.java new file mode 100644 index 0000000..85272f2 --- /dev/null +++ b/src/jalview/datamodel/RangeElementsIterator.java @@ -0,0 +1,88 @@ +package jalview.datamodel; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Iterator over each element in a set of ranges i.e. if ranges is {[3,6], + * [12,15]} it will iterate over {3,4,5,6,12,13,14,15}. Uses a local copy of the + * set of ranges. + * + * @author kmourao + * + */ +public class RangeElementsIterator implements Iterator +{ + private int last; + + private int current; + + private int next; + + private Iterator rangeIterator; + + private int[] nextRange = null; + + RangeElementsIterator(Iterator it) + { + rangeIterator = it; + if (rangeIterator.hasNext()) + { + nextRange = rangeIterator.next(); + next = nextRange[0]; + last = nextRange[1]; + } + } + + @Override + public boolean hasNext() + { + return rangeIterator.hasNext() || next <= last; + } + + @Override + public Integer next() + { + if (!hasNext()) + { + throw new NoSuchElementException(); + } + + current = next; + + // recalculate next + next++; + + // if there are more ranges need to check if next is in a range + checkNextRange(); + return current; + } + + /** + * Check how next position relates to next range, and update next position if + * necessary + */ + private void checkNextRange() + { + if (nextRange != null && next > nextRange[1]) + { + if (rangeIterator.hasNext()) + { + nextRange = rangeIterator.next(); + next = nextRange[0]; + last = nextRange[1]; + } + else + { + nextRange = null; + } + + } + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } +} diff --git a/src/jalview/datamodel/RangeIterator.java b/src/jalview/datamodel/RangeIterator.java new file mode 100644 index 0000000..7a69ac6 --- /dev/null +++ b/src/jalview/datamodel/RangeIterator.java @@ -0,0 +1,114 @@ +package jalview.datamodel; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * An iterator which iterates over a list of ranges. Works with a copy of the + * collection of ranges. + */ +public class RangeIterator implements Iterator +{ + // current index in rangeList + private int currentPosition = 0; + + // current range in rangeList + private int[] currentRange; + + // local copy or reference to rangeList + private List localRanges; + + /** + * Unbounded constructor + * + * @param rangeList + * list of ranges to iterate over + */ + RangeIterator(List rangeList) + { + if (!rangeList.isEmpty()) + { + int last = rangeList.get(rangeList.size() - 1)[1]; + init(0, last, rangeList); + } + else + { + init(0, 0, rangeList); + } + } + + /** + * Construct an iterator over rangeList bounded at [lowerBound,upperBound] + * + * @param lowerBound + * lower bound to iterate from + * @param upperBound + * upper bound to iterate to + * @param rangeList + * list of ranges to iterate over + */ + RangeIterator(int lowerBound, int upperBound, + List rangeList) + { + init(lowerBound, upperBound, rangeList); + } + + /** + * Construct an iterator over rangeList bounded at [lowerBound,upperBound] + * + * @param lowerBound + * lower bound to iterate from + * @param upperBound + * upper bound to iterate to + */ + private void init(int lowerBound, int upperBound, + List rangeList) + { + int start = lowerBound; + int end = upperBound; + + if (rangeList != null) + { + localRanges = new ArrayList<>(); + + // iterate until a range overlaps with [start,end] + int i = 0; + while ((i < rangeList.size()) && (rangeList.get(i)[1] < start)) + { + i++; + } + + // iterate from start to end, adding each range. Positions are + // absolute, and all ranges which *overlap* [start,end] are added. + while (i < rangeList.size() && (rangeList.get(i)[0] <= end)) + { + int[] rh = rangeList.get(i); + int[] cp = new int[2]; + System.arraycopy(rh, 0, cp, 0, rh.length); + localRanges.add(cp); + i++; + } + } + } + + @Override + public boolean hasNext() + { + return (localRanges != null) && (currentPosition < localRanges.size()); + } + + @Override + public int[] next() + { + currentRange = localRanges.get(currentPosition); + currentPosition++; + return currentRange; + } + + @Override + public void remove() + { + localRanges.remove(--currentPosition); + } +} diff --git a/src/jalview/datamodel/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java index 74eb887..047b7e7 100644 --- a/src/jalview/datamodel/ResidueCount.java +++ b/src/jalview/datamodel/ResidueCount.java @@ -25,6 +25,8 @@ import jalview.util.Format; import jalview.util.QuickSort; import jalview.util.SparseCount; +import java.util.List; + /** * A class to count occurrences of residues in a profile, optimised for speed * and memory footprint. @@ -148,6 +150,24 @@ public class ResidueCount } /** + * A constructor that counts frequency of all symbols (including gaps) in the + * sequences (not case-sensitive) + * + * @param sequences + */ + public ResidueCount(List sequences) + { + this(); + for (SequenceI seq : sequences) + { + for (int i = 0; i < seq.getLength(); i++) + { + add(seq.getCharAt(i)); + } + } + } + + /** * Increments the count for the given character. The supplied character may be * upper or lower case but counts are for the upper case only. Gap characters * (space, ., -) are all counted together. @@ -640,4 +660,19 @@ public class ResidueCount sb.append("]"); return sb.toString(); } + + /** + * Answers the total count for all symbols (excluding gaps) + * + * @return + */ + public int getTotalResidueCount() + { + int total = 0; + for (char symbol : this.getSymbolCounts().symbols) + { + total += getCount(symbol); + } + return total; + } } diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index 441d8d0..755abbb 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -28,12 +28,14 @@ import jalview.util.Comparison; import jalview.util.DBRefUtils; import jalview.util.MapList; import jalview.util.StringUtils; +import jalview.workers.InformationThread; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collections; import java.util.Enumeration; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Vector; @@ -61,6 +63,10 @@ public class Sequence extends ASequence implements SequenceI int end; + HiddenMarkovModel hmm; + + boolean isHMMConsensusSequence = false; + Vector pdbIds; String vamsasId; @@ -337,6 +343,15 @@ public class Sequence extends ASequence implements SequenceI this.addPDBId(new PDBEntry(pdb)); } } + if (seq.isHMMConsensusSequence()) + { + this.isHMMConsensusSequence = true; + } + if (seq.getHMM() != null) + { + this.hmm = new HiddenMarkovModel(seq.getHMM()); + } + } @Override @@ -408,7 +423,7 @@ public class Sequence extends ASequence implements SequenceI { if (pdbIds == null) { - pdbIds = new Vector(); + pdbIds = new Vector<>(); pdbIds.add(entry); return true; } @@ -444,7 +459,7 @@ public class Sequence extends ASequence implements SequenceI @Override public Vector getAllPDBEntries() { - return pdbIds == null ? new Vector() : pdbIds; + return pdbIds == null ? new Vector<>() : pdbIds; } /** @@ -1128,6 +1143,27 @@ public class Sequence extends ASequence implements SequenceI return map; } + /** + * Build a bitset corresponding to sequence gaps + * + * @return a BitSet where set values correspond to gaps in the sequence + */ + @Override + public BitSet gapBitset() + { + BitSet gaps = new BitSet(sequence.length); + int j = 0; + while (j < sequence.length) + { + if (jalview.util.Comparison.isGap(sequence[j])) + { + gaps.set(j); + } + j++; + } + return gaps; + } + @Override public int[] findPositionMap() { @@ -1151,7 +1187,7 @@ public class Sequence extends ASequence implements SequenceI @Override public List getInsertions() { - ArrayList map = new ArrayList(); + ArrayList map = new ArrayList<>(); int lastj = -1, j = 0; int pos = start; int seqlen = sequence.length; @@ -1462,7 +1498,7 @@ public class Sequence extends ASequence implements SequenceI { if (this.annotation == null) { - this.annotation = new Vector(); + this.annotation = new Vector<>(); } if (!this.annotation.contains(annotation)) { @@ -1629,7 +1665,7 @@ public class Sequence extends ASequence implements SequenceI return null; } - Vector subset = new Vector(); + Vector subset = new Vector<>(); Enumeration e = annotation.elements(); while (e.hasMoreElements()) { @@ -1763,12 +1799,13 @@ public class Sequence extends ASequence implements SequenceI public List getAlignmentAnnotations(String calcId, String label) { - List result = new ArrayList(); + List result = new ArrayList<>(); if (this.annotation != null) { for (AlignmentAnnotation ann : annotation) { - if (ann.calcId != null && ann.calcId.equals(calcId) + String id = ann.getCalcId(); + if (id != null && id.equals(calcId) && ann.label != null && ann.label.equals(label)) { result.add(ann); @@ -1819,7 +1856,7 @@ public class Sequence extends ASequence implements SequenceI } synchronized (dbrefs) { - List primaries = new ArrayList(); + List primaries = new ArrayList<>(); DBRefEntry[] tmp = new DBRefEntry[1]; for (DBRefEntry ref : dbrefs) { @@ -1866,6 +1903,46 @@ public class Sequence extends ASequence implements SequenceI } } + @Override + public HiddenMarkovModel getHMM() + { + return hmm; + } + + @Override + public void setHMM(HiddenMarkovModel hmm) + { + this.hmm = hmm; + } + + @Override + public boolean isHMMConsensusSequence() + { + return isHMMConsensusSequence; + } + + @Override + public void setIsHMMConsensusSequence(boolean value) + { + this.isHMMConsensusSequence = value; + } + + @Override + public boolean hasHMMAnnotation() + { + if (this.annotation == null) { + return false; + } + for (AlignmentAnnotation ann : annotation) + { + if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId())) + { + return true; + } + } + return false; + } + /** * {@inheritDoc} */ @@ -1961,4 +2038,73 @@ public class Sequence extends ASequence implements SequenceI return count; } + + @Override + public String getSequenceStringFromIterator(Iterator it) + { + StringBuilder newSequence = new StringBuilder(); + while (it.hasNext()) + { + int[] block = it.next(); + if (it.hasNext()) + { + newSequence.append(getSequence(block[0], block[1] + 1)); + } + else + { + newSequence.append(getSequence(block[0], block[1])); + } + } + + return newSequence.toString(); + } + + @Override + public int firstResidueOutsideIterator(Iterator regions) + { + int start = 0; + + if (!regions.hasNext()) + { + return findIndex(getStart()) - 1; + } + + // Simply walk along the sequence whilst watching for region + // boundaries + int hideStart = getLength(); + int hideEnd = -1; + boolean foundStart = false; + + // step through the non-gapped positions of the sequence + for (int i = getStart(); i <= getEnd() && (!foundStart); i++) + { + // get alignment position of this residue in the sequence + int p = findIndex(i) - 1; + + // update region start/end + while (hideEnd < p && regions.hasNext()) + { + int[] region = regions.next(); + hideStart = region[0]; + hideEnd = region[1]; + } + if (hideEnd < p) + { + hideStart = getLength(); + } + // update boundary for sequence + if (p < hideStart) + { + start = p; + foundStart = true; + } + } + + if (foundStart) + { + return start; + } + // otherwise, sequence was completely hidden + return 0; + } } diff --git a/src/jalview/datamodel/SequenceCollectionI.java b/src/jalview/datamodel/SequenceCollectionI.java index f681f11..ee4b844 100644 --- a/src/jalview/datamodel/SequenceCollectionI.java +++ b/src/jalview/datamodel/SequenceCollectionI.java @@ -70,4 +70,16 @@ public interface SequenceCollectionI * @return */ boolean isNucleotide(); + + /** + * Returns the HMM consensus sequence (if any) for the collection, or null + * + * @return + */ + SequenceI getHmmConsensus(); + + /** + * Sets the HMM consensus sequence for the collection + */ + void setHmmConsensus(SequenceI hmmSeq); } diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java index 6b797d7..aebcbb3 100755 --- a/src/jalview/datamodel/SequenceGroup.java +++ b/src/jalview/datamodel/SequenceGroup.java @@ -25,6 +25,8 @@ import jalview.analysis.Conservation; import jalview.renderer.ResidueShader; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; +import jalview.util.MessageManager; +import jalview.workers.InformationThread; import java.awt.Color; import java.beans.PropertyChangeListener; @@ -43,116 +45,120 @@ import java.util.Map; public class SequenceGroup implements AnnotatedCollectionI { // TODO ideally this event notification functionality should be separated into - // a - // subclass of ViewportProperties similarly to ViewportRanges. Done here as - // quick fix for JAL-2665 + // a subclass of ViewportProperties similarly to ViewportRanges. + // Done here as a quick fix for JAL-2665 public static final String SEQ_GROUP_CHANGED = "Sequence group changed"; - protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( - this); + private String groupName; - public void addPropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.addPropertyChangeListener(listener); - } + private String description; - public void removePropertyChangeListener(PropertyChangeListener listener) - { - changeSupport.removePropertyChangeListener(listener); - } - // end of event notification functionality initialisation + private AnnotatedCollectionI context; - String groupName; + private Conservation conservationData; - String description; + private ProfilesI consensusProfiles; - Conservation conserve; + private ProfilesI hmmProfiles; - boolean displayBoxes = true; + private boolean displayBoxes = true; - boolean displayText = true; + private boolean displayText = true; - boolean colourText = false; + private boolean colourText = false; - /** - * True if the group is defined as a group on the alignment, false if it is - * just a selection. + /* + * true if the group is defined as a group on the alignment, false if it is + * just a selection */ - boolean isDefined = false; + private boolean isDefined; - /** + /* * after Olivier's non-conserved only character display */ - boolean showNonconserved = false; + private boolean showNonconserved; - /** - * group members + /* + * sequences in the group */ private List sequences = new ArrayList<>(); - /** + /* * representative sequence for this group (if any) */ - private SequenceI seqrep = null; + private SequenceI seqrep; + + /* + * HMM consensus sequence for group (if any) + */ + private SequenceI hmmConsensus; - int width = -1; + private int width = -1; - /** - * Colourscheme applied to group if any + /* + * colour scheme applied to group if any */ public ResidueShaderI cs; // start column (base 0) - int startRes = 0; + private int startRes; // end column (base 0) - int endRes = 0; + private int endRes; public Color outlineColour = Color.black; - public Color idColour = null; + public Color idColour; - public int thresholdTextColour = 0; + public int thresholdTextColour; public Color textColour = Color.black; public Color textColour2 = Color.white; - /** - * consensus calculation property + /* + * properties for consensus annotation */ private boolean ignoreGapsInConsensus = true; - /** - * consensus calculation property - */ - private boolean showSequenceLogo = false; + private boolean showSequenceLogo; - /** - * flag indicating if logo should be rendered normalised - */ private boolean normaliseSequenceLogo; + private boolean showConsensusHistogram; + + /* + * properties for HMM information annotation + */ + private boolean hmmIgnoreBelowBackground = true; + + private boolean hmmUseInfoLetterHeight; + + private boolean hmmShowSequenceLogo; + + private boolean hmmNormaliseSequenceLogo; + + private boolean hmmShowHistogram; + /* * visibility of rows or represented rows covered by group */ - private boolean hidereps = false; + private boolean hidereps; /* * visibility of columns intersecting this group */ - private boolean hidecols = false; - - AlignmentAnnotation consensus = null; + private boolean hidecols; - AlignmentAnnotation conservation = null; + private AlignmentAnnotation consensus; - private boolean showConsensusHistogram; + private AlignmentAnnotation conservation; - private AnnotatedCollectionI context; + private AlignmentAnnotation hmmInformation; /** - * Creates a new SequenceGroup object. + * Constructor, assigning a generated default name of "JGroup:" with object + * hashcode appended */ public SequenceGroup() { @@ -222,6 +228,9 @@ public class SequenceGroup implements AnnotatedCollectionI showSequenceLogo = seqsel.showSequenceLogo; normaliseSequenceLogo = seqsel.normaliseSequenceLogo; showConsensusHistogram = seqsel.showConsensusHistogram; + hmmShowSequenceLogo = seqsel.hmmShowSequenceLogo; + hmmNormaliseSequenceLogo = seqsel.hmmNormaliseSequenceLogo; + hmmShowHistogram = seqsel.hmmShowHistogram; idColour = seqsel.idColour; outlineColour = seqsel.outlineColour; seqrep = seqsel.seqrep; @@ -230,7 +239,9 @@ public class SequenceGroup implements AnnotatedCollectionI thresholdTextColour = seqsel.thresholdTextColour; width = seqsel.width; ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus; - if (seqsel.conserve != null) + hmmIgnoreBelowBackground = seqsel.hmmIgnoreBelowBackground; + hmmUseInfoLetterHeight = seqsel.hmmUseInfoLetterHeight; + if (seqsel.conservationData != null) { recalcConservation(); // safer than // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ?? @@ -238,6 +249,19 @@ public class SequenceGroup implements AnnotatedCollectionI } } + protected PropertyChangeSupport changeSupport = new PropertyChangeSupport( + this); + + public void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + public void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + public boolean isShowSequenceLogo() { return showSequenceLogo; @@ -259,6 +283,7 @@ public class SequenceGroup implements AnnotatedCollectionI seqs[ipos].setDescription(seq.getDescription()); seqs[ipos].setDBRefs(seq.getDBRefs()); seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures()); + seqs[ipos].setIsHMMConsensusSequence(seq.isHMMConsensusSequence()); if (seq.getDatasetSequence() != null) { seqs[ipos].setDatasetSequence(seq.getDatasetSequence()); @@ -488,7 +513,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public Conservation getConservation() { - return conserve; + return conservationData; } /** @@ -499,7 +524,7 @@ public class SequenceGroup implements AnnotatedCollectionI */ public void setConservation(Conservation c) { - conserve = c; + conservationData = c; } /** @@ -560,20 +585,22 @@ public class SequenceGroup implements AnnotatedCollectionI */ public boolean recalcConservation() { - return recalcConservation(false); + return recalcAnnotations(false); } /** - * calculate residue conservation for group - but only if necessary. returns - * true if the calculation resulted in a visible change to group + * Recalculates column consensus, conservation, and HMM annotation for the + * group (as applicable). Returns true if the calculation resulted in a + * visible change to group. * * @param defer * when set, colourschemes for this group are not refreshed after * recalculation */ - public boolean recalcConservation(boolean defer) + public boolean recalcAnnotations(boolean defer) { - if (cs == null && consensus == null && conservation == null) + if (cs == null && consensus == null && conservation == null + && hmmInformation == null) { return false; } @@ -584,6 +611,16 @@ public class SequenceGroup implements AnnotatedCollectionI { ProfilesI cnsns = AAFrequency.calculate(sequences, startRes, endRes + 1, showSequenceLogo); + if (hmmInformation != null) + { + HiddenMarkovModel hmm = hmmInformation.sequenceRef.getHMM(); + + ProfilesI info = AAFrequency.calculateHMMProfiles(hmm, + (endRes + 1) - startRes, startRes, endRes + 1, + hmmIgnoreBelowBackground, hmmUseInfoLetterHeight); + _updateInformationRow(info); + upd = true; + } if (consensus != null) { _updateConsensusRow(cnsns, sequences.size()); @@ -656,8 +693,6 @@ public class SequenceGroup implements AnnotatedCollectionI c.completeAnnotations(conservation, null, startRes, endRes + 1); } - public ProfilesI consensusData = null; - private void _updateConsensusRow(ProfilesI cnsns, long nseq) { if (consensus == null) @@ -666,7 +701,7 @@ public class SequenceGroup implements AnnotatedCollectionI } consensus.label = "Consensus for " + getName(); consensus.description = "Percent Identity"; - consensusData = cnsns; + consensusProfiles = cnsns; // preserve width if already set int aWidth = (consensus.annotations != null) ? (endRes < consensus.annotations.length @@ -684,6 +719,33 @@ public class SequenceGroup implements AnnotatedCollectionI } /** + * Recalculates the information content on the HMM annotation + * + * @param cnsns + */ + private void _updateInformationRow(ProfilesI cnsns) + { + if (hmmInformation == null) + { + createInformationAnnotation(); + } + hmmInformation.description = MessageManager + .getString("label.information_description"); + setHmmProfiles(cnsns); + // preserve width if already set + int aWidth = (hmmInformation.annotations != null) + ? (endRes < hmmInformation.annotations.length + ? hmmInformation.annotations.length : endRes + 1) + : endRes + 1; + hmmInformation.annotations = null; + hmmInformation.annotations = new Annotation[aWidth]; // should be alignment + // width + hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); + AAFrequency.completeInformation(hmmInformation, cnsns, startRes, + endRes + 1); + } + + /** * @param s * sequence to either add or remove from group * @param recalc @@ -1137,6 +1199,22 @@ public class SequenceGroup implements AnnotatedCollectionI } /** + * Creates the Hidden Markov Model annotation for this group + */ + void createInformationAnnotation() + { + hmmInformation = new AlignmentAnnotation("", "", new Annotation[1], 0f, + 6.25f, AlignmentAnnotation.BAR_GRAPH); + hmmInformation.hasText = true; + hmmInformation.autoCalculated = false; + hmmInformation.groupRef = this; + hmmInformation.label = getName(); + hmmInformation.description = MessageManager + .getString("label.information_description"); + hmmInformation.setCalcId(InformationThread.HMM_CALC_ID); + } + + /** * set this alignmentAnnotation object as the one used to render consensus * annotation * @@ -1189,9 +1267,10 @@ public class SequenceGroup implements AnnotatedCollectionI { if (consensus.annotations[i] != null) { - if (consensus.annotations[i].description.charAt(0) == '[') + String desc = consensus.annotations[i].description; + if (desc.length() > 1 && desc.charAt(0) == '[') { - seqs.append(consensus.annotations[i].description.charAt(1)); + seqs.append(desc.charAt(1)); } else { @@ -1217,11 +1296,31 @@ public class SequenceGroup implements AnnotatedCollectionI ignoreGapsInConsensus = state; } - public boolean getIgnoreGapsConsensus() + public boolean isIgnoreGapsConsensus() { return ignoreGapsInConsensus; } + public void setIgnoreBelowBackground(boolean state) + { + hmmIgnoreBelowBackground = state; + } + + public boolean isIgnoreBelowBackground() + { + return hmmIgnoreBelowBackground; + } + + public void setInfoLetterHeight(boolean state) + { + hmmUseInfoLetterHeight = state; + } + + public boolean isUseInfoLetterHeight() + { + return hmmUseInfoLetterHeight; + } + /** * @param showSequenceLogo * indicates if a sequence logo is shown for consensus annotation @@ -1465,4 +1564,67 @@ public class SequenceGroup implements AnnotatedCollectionI { return (startRes <= apos && endRes >= apos) && sequences.contains(seq); } + + public boolean isShowInformationHistogram() + { + return hmmShowHistogram; + } + + public void setShowInformationHistogram(boolean state) + { + if (hmmShowHistogram != state && hmmInformation != null) + { + this.hmmShowHistogram = state; + // recalcConservation(); TODO don't know what to do here next + } + this.hmmShowHistogram = state; + } + + public boolean isShowHMMSequenceLogo() + { + return hmmShowSequenceLogo; + } + + public void setShowHMMSequenceLogo(boolean state) + { + hmmShowSequenceLogo = state; + } + + public boolean isNormaliseHMMSequenceLogo() + { + return hmmNormaliseSequenceLogo; + } + + public void setNormaliseHMMSequenceLogo(boolean state) + { + hmmNormaliseSequenceLogo = state; + } + + @Override + public SequenceI getHmmConsensus() + { + return hmmConsensus; + } + + @Override + public void setHmmConsensus(SequenceI hmmSeq) + { + this.hmmConsensus = hmmSeq; + } + + public ProfilesI getConsensusData() + { + return consensusProfiles; + } + + public ProfilesI getHmmProfiles() + { + return hmmProfiles; + } + + public void setHmmProfiles(ProfilesI hmmProfiles) + { + this.hmmProfiles = hmmProfiles; + } + } diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index fb723e6..5b3d782 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -24,6 +24,7 @@ import jalview.datamodel.features.SequenceFeaturesI; import jalview.util.MapList; import java.util.BitSet; +import java.util.Iterator; import java.util.List; import java.util.Vector; @@ -45,6 +46,10 @@ public interface SequenceI extends ASequenceI */ public void setName(String name); + public HiddenMarkovModel getHMM(); + + public void setHMM(HiddenMarkovModel hmm); + /** * Get the display name */ @@ -224,6 +229,13 @@ public interface SequenceI extends ASequenceI public int[] gapMap(); /** + * Build a bitset corresponding to sequence gaps + * + * @return a BitSet where set values correspond to gaps in the sequence + */ + public BitSet gapBitset(); + + /** * Returns an int array where indices correspond to each position in sequence * char array and the element value gives the result of findPosition for that * index in the sequence. @@ -487,6 +499,16 @@ public interface SequenceI extends ASequenceI */ public List getPrimaryDBRefs(); + boolean isHMMConsensusSequence(); + + void setIsHMMConsensusSequence(boolean isHMMConsensusSequence); + + /** + * Answers true if the sequence has annotation for Hidden Markov Model + * information content, else false + */ + boolean hasHMMAnnotation(); + /** * Returns a (possibly empty) list of sequence features that overlap the given * alignment column range, optionally restricted to one or more specified @@ -524,7 +546,7 @@ public interface SequenceI extends ASequenceI * @param c1 * @param c2 */ - public int replace(char c1, char c2); + int replace(char c1, char c2); /** * Answers the GeneLociI, or null if not known @@ -543,4 +565,26 @@ public interface SequenceI extends ASequenceI */ void setGeneLoci(String speciesId, String assemblyId, String chromosomeId, MapList map); + + + /** + * Returns the sequence string constructed from the substrings of a sequence + * defined by the int[] ranges provided by an iterator. E.g. the iterator + * could iterate over all visible regions of the alignment + * + * @param it + * the iterator to use + * @return a String corresponding to the sequence + */ + public String getSequenceStringFromIterator(Iterator it); + + /** + * Locate the first position in this sequence which is not contained in an + * iterator region. If no such position exists, return 0 + * + * @param it + * iterator over regions + * @return first residue not contained in regions + */ + public int firstResidueOutsideIterator(Iterator it); } diff --git a/src/jalview/datamodel/StartRegionIterator.java b/src/jalview/datamodel/StartRegionIterator.java new file mode 100644 index 0000000..bd036e4 --- /dev/null +++ b/src/jalview/datamodel/StartRegionIterator.java @@ -0,0 +1,123 @@ +package jalview.datamodel; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * An iterator which iterates over visible start positions of hidden column + * regions in a range. + */ +public class StartRegionIterator implements Iterator +{ + // start position to iterate from + private int start; + + // end position to iterate to + private int end; + + // current index in hiddenColumns + private int currentPosition = 0; + + // local copy or reference to hiddenColumns + private List positions = null; + + /** + * Construct an iterator over hiddenColums bounded at [lowerBound,upperBound] + * + * @param lowerBound + * lower bound to iterate from + * @param upperBound + * upper bound to iterate to + * @param useCopyCols + * whether to make a local copy of hiddenColumns for iteration (set + * to true if calling from outwith the HiddenColumns class) + */ + StartRegionIterator(int lowerBound, int upperBound, + List hiddenColumns) + { + this(null, lowerBound, upperBound, hiddenColumns); + } + + /** + * Construct an iterator over hiddenColums bounded at [lowerBound,upperBound] + * + * @param pos + * a hidden cursor position to start from - may be null + * @param lowerBound + * lower bound to iterate from - will be ignored if pos != null + * @param upperBound + * upper bound to iterate to + * @param hiddenColumns + * the hidden columns collection to use + */ + StartRegionIterator(HiddenCursorPosition pos, int lowerBound, + int upperBound, List hiddenColumns) + { + start = lowerBound; + end = upperBound; + + if (hiddenColumns != null) + { + positions = new ArrayList<>(hiddenColumns.size()); + + // navigate to start, keeping count of hidden columns + int i = 0; + int hiddenSoFar = 0; + + if (pos != null) + { + // use the cursor position provided + i = pos.getRegionIndex(); + hiddenSoFar = pos.getHiddenSoFar(); + } + else + { + // navigate to start + while ((i < hiddenColumns.size()) + && (hiddenColumns.get(i)[0] < start + hiddenSoFar)) + { + int[] region = hiddenColumns.get(i); + hiddenSoFar += region[1] - region[0] + 1; + i++; + } + } + + // iterate from start to end, adding start positions of each + // hidden region. Positions are visible columns count, not absolute + while (i < hiddenColumns.size() + && (hiddenColumns.get(i)[0] <= end + hiddenSoFar)) + { + int[] region = hiddenColumns.get(i); + positions.add(region[0] - hiddenSoFar); + hiddenSoFar += region[1] - region[0] + 1; + i++; + } + } + else + { + positions = new ArrayList<>(); + } + + } + + @Override + public boolean hasNext() + { + return (currentPosition < positions.size()); + } + + /** + * Get next hidden region start position + * + * @return the start position in *visible* coordinates + */ + @Override + public Integer next() + { + int result = positions.get(currentPosition); + currentPosition++; + return result; + } +} + diff --git a/src/jalview/datamodel/VisibleColsCollection.java b/src/jalview/datamodel/VisibleColsCollection.java index e9437a7..4ca51b5 100644 --- a/src/jalview/datamodel/VisibleColsCollection.java +++ b/src/jalview/datamodel/VisibleColsCollection.java @@ -32,17 +32,17 @@ public class VisibleColsCollection implements AlignmentColsCollectionI HiddenColumns hidden; - public VisibleColsCollection(int s, int e, AlignmentI al) + public VisibleColsCollection(int s, int e, HiddenColumns h) { start = s; end = e; - hidden = al.getHiddenColumns(); + hidden = h; } @Override public Iterator iterator() { - return new VisibleColsIterator(start, end, hidden); + return hidden.getVisibleColsIterator(start, end); } @Override diff --git a/src/jalview/datamodel/VisibleColsIterator.java b/src/jalview/datamodel/VisibleColsIterator.java deleted file mode 100644 index 9de468d..0000000 --- a/src/jalview/datamodel/VisibleColsIterator.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) - * Copyright (C) $$Year-Rel$$ The Jalview Authors - * - * This file is part of Jalview. - * - * Jalview is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 - * of the License, or (at your option) any later version. - * - * Jalview is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Jalview. If not, see . - * The Jalview Authors are detailed in the 'AUTHORS' file. - */ -package jalview.datamodel; - -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * An iterator which iterates over all visible columns in an alignment - * - * @author kmourao - * - */ -public class VisibleColsIterator implements Iterator -{ - private int last; - - private int current; - - private int next; - - private List hidden; - - private int lasthiddenregion; - - public VisibleColsIterator(int firstcol, int lastcol, - HiddenColumns hiddenCols) - { - last = lastcol; - current = firstcol; - next = firstcol; - hidden = hiddenCols.getHiddenColumnsCopy(); - lasthiddenregion = -1; - - if (hidden != null) - { - int i = 0; - for (i = 0; i < hidden.size(); ++i) - { - if (current >= hidden.get(i)[0] && current <= hidden.get(i)[1]) - { - // current is hidden, move to right - current = hidden.get(i)[1] + 1; - next = current; - } - if (current < hidden.get(i)[0]) - { - break; - } - } - lasthiddenregion = i - 1; - - for (i = hidden.size() - 1; i >= 0; --i) - { - if (last >= hidden.get(i)[0] && last <= hidden.get(i)[1]) - { - // last is hidden, move to left - last = hidden.get(i)[0] - 1; - } - if (last > hidden.get(i)[1]) - { - break; - } - } - } - } - - @Override - public boolean hasNext() - { - return next <= last; - } - - @Override - public Integer next() - { - if (next > last) - { - throw new NoSuchElementException(); - } - current = next; - if ((hidden != null) && (lasthiddenregion + 1 < hidden.size())) - { - // still some more hidden regions - if (next + 1 < hidden.get(lasthiddenregion + 1)[0]) - { - // next+1 is still before the next hidden region - next++; - } - else if ((next + 1 >= hidden.get(lasthiddenregion + 1)[0]) - && (next + 1 <= hidden.get(lasthiddenregion + 1)[1])) - { - // next + 1 is in the next hidden region - next = hidden.get(lasthiddenregion + 1)[1] + 1; - lasthiddenregion++; - } - } - else - { - // finished with hidden regions, just increment normally - next++; - } - return current; - } - - @Override - public void remove() - { - throw new UnsupportedOperationException(); - } -} diff --git a/src/jalview/datamodel/VisibleContigsIterator.java b/src/jalview/datamodel/VisibleContigsIterator.java new file mode 100644 index 0000000..6d3f43d --- /dev/null +++ b/src/jalview/datamodel/VisibleContigsIterator.java @@ -0,0 +1,96 @@ +package jalview.datamodel; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * An iterator which iterates over visible regions in a range. Provides a + * special "endsAtHidden" indicator to allow callers to determine if the final + * visible column is adjacent to a hidden region. + */ +public class VisibleContigsIterator implements Iterator +{ + private List vcontigs = new ArrayList<>(); + + private int currentPosition = 0; + + private boolean endsAtHidden = false; + + VisibleContigsIterator(int start, int end, + List hiddenColumns) + { + if (hiddenColumns != null && hiddenColumns.size() > 0) + { + int vstart = start; + int hideStart; + int hideEnd; + + for (int[] region : hiddenColumns) + { + endsAtHidden = false; + hideStart = region[0]; + hideEnd = region[1]; + + // navigate to start + if (hideEnd < vstart) + { + continue; + } + if (hideStart > vstart) + { + if (end - 1 > hideStart - 1) + { + int[] contig = new int[] { vstart, hideStart - 1 }; + vcontigs.add(contig); + endsAtHidden = true; + } + else + { + int[] contig = new int[] { vstart, end - 1 }; + vcontigs.add(contig); + } + } + vstart = hideEnd + 1; + + // exit if we're past the end + if (vstart >= end) + { + break; + } + } + + if (vstart < end) + { + int[] contig = new int[] { vstart, end - 1 }; + vcontigs.add(contig); + endsAtHidden = false; + } + } + else + { + int[] contig = new int[] { start, end - 1 }; + vcontigs.add(contig); + } + } + + @Override + public boolean hasNext() + { + return (currentPosition < vcontigs.size()); + } + + @Override + public int[] next() + { + int[] result = vcontigs.get(currentPosition); + currentPosition++; + return result; + } + + public boolean endsAtHidden() + { + return endsAtHidden; + } +} + diff --git a/src/jalview/ext/ensembl/EnsemblGenomes.java b/src/jalview/ext/ensembl/EnsemblGenomes.java index bbd1f26..9fc6a53 100644 --- a/src/jalview/ext/ensembl/EnsemblGenomes.java +++ b/src/jalview/ext/ensembl/EnsemblGenomes.java @@ -20,6 +20,9 @@ */ package jalview.ext.ensembl; +import jalview.bin.Cache; +import jalview.datamodel.DBRefSource; + /** * A class to behave much like EnsemblGene but referencing the ensemblgenomes * domain and data @@ -35,13 +38,15 @@ public class EnsemblGenomes extends EnsemblGene */ public EnsemblGenomes() { - super(ENSEMBL_GENOMES_REST); + super(); + setDomain(Cache.getDefault(ENSEMBL_GENOMES_BASEURL, + DEFAULT_ENSEMBL_GENOMES_BASEURL)); } @Override public String getDbName() { - return "EnsemblGenomes"; + return DBRefSource.ENSEMBLGENOMES; } @Override @@ -56,7 +61,7 @@ public class EnsemblGenomes extends EnsemblGene @Override public String getDbSource() { - return "EnsemblGenomes"; + return DBRefSource.ENSEMBLGENOMES; } } diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java index de55a53..37dff51 100644 --- a/src/jalview/ext/ensembl/EnsemblInfo.java +++ b/src/jalview/ext/ensembl/EnsemblInfo.java @@ -101,17 +101,17 @@ public class EnsemblInfo extends EnsemblRestClient /* * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL" */ - divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ENSEMBL_REST); + divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain); BufferedReader br = null; try { - URL url = getDivisionsUrl(ENSEMBL_GENOMES_REST); + URL url = getDivisionsUrl(ensemblGenomesDomain); if (url != null) { br = getHttpResponse(url, null); } - parseResponse(br, ENSEMBL_GENOMES_REST); + parseResponse(br, ensemblGenomesDomain); } catch (IOException e) { // ignore diff --git a/src/jalview/ext/ensembl/EnsemblLookup.java b/src/jalview/ext/ensembl/EnsemblLookup.java index f6b3a47..5f353f8 100644 --- a/src/jalview/ext/ensembl/EnsemblLookup.java +++ b/src/jalview/ext/ensembl/EnsemblLookup.java @@ -138,7 +138,53 @@ public class EnsemblLookup extends EnsemblRestClient */ public String getGeneId(String identifier) { - return parseGeneId(getResult(identifier, null)); + return getGeneId(identifier, null); + } + + /** + * Returns the gene id related to the given identifier (which may be for a + * gene, transcript or protein) + * + * @param identifier + * @param objectType + * @return + */ + public String getGeneId(String identifier, String objectType) + { + return parseGeneId(getResult(identifier, objectType)); + } + + /** + * Parses the JSON response and returns the gene identifier, or null if not + * found. If the returned object_type is Gene, returns the id, if Transcript + * returns the Parent. If it is Translation (peptide identifier), then the + * Parent is the transcript identifier, so we redo the search with this value. + * + * @param br + * @return + */ + protected String parseGeneId(JSONObject val) + { + String geneId = null; + String type = val.get(OBJECT_TYPE).toString(); + if (OBJECT_TYPE_GENE.equalsIgnoreCase(type)) + { + // got the gene - just returns its id + geneId = val.get(JSON_ID).toString(); + } + else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type)) + { + // got the transcript - return its (Gene) Parent + geneId = val.get(PARENT).toString(); + } + else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type)) + { + // got the protein - get its Parent, restricted to type Transcript + String transcriptId = val.get(PARENT).toString(); + geneId = getGeneId(transcriptId, OBJECT_TYPE_TRANSCRIPT); + } + + return geneId; } /** @@ -180,6 +226,7 @@ public class EnsemblLookup extends EnsemblRestClient try { URL url = getUrl(identifier, objectType); + if (url != null) { br = getHttpResponse(url, ids); @@ -206,46 +253,6 @@ public class EnsemblLookup extends EnsemblRestClient } /** - * Parses the JSON response and returns the gene identifier, or null if not - * found. If the returned object_type is Gene, returns the id, if Transcript - * returns the Parent. If it is Translation (peptide identifier), then the - * Parent is the transcript identifier, so we redo the search with this value, - * specifying that object_type should be Transcript. - * - * @param jsonObject - * @return - */ - protected String parseGeneId(JSONObject json) - { - if (json == null) - { - // e.g. lookup failed with 404 not found - return null; - } - - String geneId = null; - String type = json.get(OBJECT_TYPE).toString(); - if (OBJECT_TYPE_GENE.equalsIgnoreCase(type)) - { - // got the gene - just returns its id - geneId = json.get(JSON_ID).toString(); - } - else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type)) - { - // got the transcript - return its (Gene) Parent - geneId = json.get(PARENT).toString(); - } - else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type)) - { - // got the protein - look up its Parent, restricted to type Transcript - String transcriptId = json.get(PARENT).toString(); - geneId = parseGeneId(getResult(transcriptId, OBJECT_TYPE_TRANSCRIPT)); - } - - return geneId; - } - - /** * Calls the /lookup/id rest service for the given id, and if successful, * parses and returns the gene's chromosomal coordinates * diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java index e3d1215..9dea886 100644 --- a/src/jalview/ext/ensembl/EnsemblRestClient.java +++ b/src/jalview/ext/ensembl/EnsemblRestClient.java @@ -86,10 +86,10 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher static { domainData = new HashMap<>(); - domainData.put(ENSEMBL_REST, - new EnsemblData(ENSEMBL_REST, LATEST_ENSEMBL_REST_VERSION)); - domainData.put(ENSEMBL_GENOMES_REST, new EnsemblData( - ENSEMBL_GENOMES_REST, LATEST_ENSEMBLGENOMES_REST_VERSION)); + domainData.put(DEFAULT_ENSEMBL_BASEURL, + new EnsemblData(DEFAULT_ENSEMBL_BASEURL, LATEST_ENSEMBL_REST_VERSION)); + domainData.put(DEFAULT_ENSEMBL_GENOMES_BASEURL, new EnsemblData( + DEFAULT_ENSEMBL_GENOMES_BASEURL, LATEST_ENSEMBLGENOMES_REST_VERSION)); } protected volatile boolean inProgress = false; @@ -99,7 +99,21 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher */ public EnsemblRestClient() { - this(ENSEMBL_REST); + super(); + + /* + * initialise domain info lazily + */ + if (!domainData.containsKey(ensemblDomain)) + { + domainData.put(ensemblDomain, + new EnsemblData(ensemblDomain, LATEST_ENSEMBL_REST_VERSION)); + } + if (!domainData.containsKey(ensemblGenomesDomain)) + { + domainData.put(ensemblGenomesDomain, new EnsemblData( + ensemblGenomesDomain, LATEST_ENSEMBLGENOMES_REST_VERSION)); + } } /** @@ -169,11 +183,12 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher boolean checkEnsembl() { BufferedReader br = null; + String pingUrl = getDomain() + "/info/ping" + CONTENT_TYPE_JSON; try { // note this format works for both ensembl and ensemblgenomes // info/ping.json works for ensembl only (March 2016) - URL ping = new URL(getDomain() + "/info/ping" + CONTENT_TYPE_JSON); + URL ping = new URL(pingUrl); /* * expect {"ping":1} if ok @@ -192,7 +207,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher } catch (Throwable t) { System.err.println( - "Error connecting to " + PING_URL + ": " + t.getMessage()); + "Error connecting to " + pingUrl + ": " + t.getMessage()); } finally { if (br != null) diff --git a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java index cfb3c6d..9e3fef4 100644 --- a/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java +++ b/src/jalview/ext/ensembl/EnsemblSequenceFetcher.java @@ -20,6 +20,7 @@ */ package jalview.ext.ensembl; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import jalview.ws.seqfetcher.DbSourceProxyImpl; @@ -32,6 +33,16 @@ import com.stevesoft.pat.Regex; */ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl { + // domain properties lookup keys: + protected static final String ENSEMBL_BASEURL = "ENSEMBL_BASEURL"; + + protected static final String ENSEMBL_GENOMES_BASEURL = "ENSEMBL_GENOMES_BASEURL"; + + // domain properties default values: + protected static final String DEFAULT_ENSEMBL_BASEURL = "https://rest.ensembl.org"; + + protected static final String DEFAULT_ENSEMBL_GENOMES_BASEURL = "https://rest.ensemblgenomes.org"; + /* * accepts ENSG/T/E/P with 11 digits * or ENSMUSP or similar for other species @@ -41,9 +52,9 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl "(ENS([A-Z]{3}|)[GTEP]{1}[0-9]{11}$)" + "|" + "(CCDS[0-9.]{3,}$)"); - protected static final String ENSEMBL_GENOMES_REST = "http://rest.ensemblgenomes.org"; + protected final String ensemblGenomesDomain; - protected static final String ENSEMBL_REST = "http://rest.ensembl.org"; + protected final String ensemblDomain; protected static final String OBJECT_TYPE_TRANSLATION = "Translation"; @@ -68,13 +79,29 @@ abstract class EnsemblSequenceFetcher extends DbSourceProxyImpl constrained, regulatory } - private String domain = ENSEMBL_REST; + private String domain; + + /** + * Constructor + */ + public EnsemblSequenceFetcher() + { + /* + * the default domain names may be overridden in .jalview_properties; + * this allows an easy change from http to https in future if needed + */ + ensemblDomain = Cache.getDefault(ENSEMBL_BASEURL, + DEFAULT_ENSEMBL_BASEURL); + ensemblGenomesDomain = Cache.getDefault(ENSEMBL_GENOMES_BASEURL, + DEFAULT_ENSEMBL_GENOMES_BASEURL); + domain = ensemblDomain; + } @Override public String getDbSource() { // NB ensure Uniprot xrefs are canonicalised from "Ensembl" to "ENSEMBL" - if (ENSEMBL_GENOMES_REST.equals(getDomain())) + if (ensemblGenomesDomain.equals(getDomain())) { return DBRefSource.ENSEMBLGENOMES; } diff --git a/src/jalview/ext/jmol/JmolCommands.java b/src/jalview/ext/jmol/JmolCommands.java index 6bf7010..8fb0de6 100644 --- a/src/jalview/ext/jmol/JmolCommands.java +++ b/src/jalview/ext/jmol/JmolCommands.java @@ -77,7 +77,6 @@ public class JmolCommands continue; } - int lastPos = -1; for (int s = 0; s < sequence[pdbfnum].length; s++) { for (int sp, m = 0; m < mapping.length; m++) @@ -85,6 +84,7 @@ public class JmolCommands if (mapping[m].getSequence() == sequence[pdbfnum][s] && (sp = al.findIndex(sequence[pdbfnum][s])) > -1) { + int lastPos = StructureMapping.UNASSIGNED_VALUE; SequenceI asp = al.getSequenceAt(sp); for (int r = 0; r < asp.getLength(); r++) { @@ -95,10 +95,22 @@ public class JmolCommands } int pos = mapping[m].getPDBResNum(asp.findPosition(r)); - if (pos < 1 || pos == lastPos) + if (pos == lastPos) { continue; } + if (pos == StructureMapping.UNASSIGNED_VALUE) + { + // terminate current colour op + if (command.length() > 0 + && command.charAt(command.length() - 1) != ';') + { + command.append(";"); + } + // reset lastPos + lastPos = StructureMapping.UNASSIGNED_VALUE; + continue; + } lastPos = pos; @@ -128,7 +140,12 @@ public class JmolCommands // TODO: deal with case when buffer is too large for Jmol to parse // - execute command and flush - command.append(";"); + if (command.length() > 0 + && command.charAt(command.length() - 1) != ';') + { + command.append(";"); + } + if (command.length() > 51200) { // add another chunk diff --git a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java index 250fba0..262ed86 100644 --- a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java +++ b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java @@ -21,6 +21,7 @@ package jalview.fts.service.uniprot; +import jalview.bin.Cache; import jalview.fts.api.FTSData; import jalview.fts.api.FTSDataColumnI; import jalview.fts.api.FTSRestClientI; @@ -44,9 +45,18 @@ import com.sun.jersey.api.client.config.DefaultClientConfig; public class UniProtFTSRestClient extends FTSRestClient { + private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org"; + private static FTSRestClientI instance = null; - public static final String UNIPROT_SEARCH_ENDPOINT = "http://www.uniprot.org/uniprot/?"; + public final String uniprotSearchEndpoint; + + public UniProtFTSRestClient() + { + super(); + uniprotSearchEndpoint = Cache.getDefault("UNIPROT_DOMAIN", + DEFAULT_UNIPROT_DOMAIN) + "/uniprot/?"; + } @Override public FTSRestResponse executeRequest(FTSRestRequest uniportRestRequest) @@ -81,7 +91,7 @@ public class UniProtFTSRestClient extends FTSRestClient } WebResource webResource = null; - webResource = client.resource(UNIPROT_SEARCH_ENDPOINT) + webResource = client.resource(uniprotSearchEndpoint) .queryParam("format", "tab") .queryParam("columns", wantedFields) .queryParam("limit", String.valueOf(responseSize)) @@ -158,7 +168,7 @@ public class UniProtFTSRestClient extends FTSRestClient String[] foundDataRow = uniProtTabDelimittedResponseString.split("\n"); if (foundDataRow != null && foundDataRow.length > 0) { - result = new ArrayList(); + result = new ArrayList<>(); boolean firstRow = true; for (String dataRow : foundDataRow) { diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 4c9360e..009d946 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -54,6 +54,7 @@ import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; import jalview.datamodel.SeqCigar; @@ -62,6 +63,12 @@ import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.gui.ColourMenuHelper.ColourChangeListener; import jalview.gui.ViewSelectionMenu.ViewSetProvider; +import jalview.hmmer.HMMAlign; +import jalview.hmmer.HMMBuild; +import jalview.hmmer.HMMERParamStore; +import jalview.hmmer.HMMERPreset; +import jalview.hmmer.HMMSearch; +import jalview.hmmer.HmmerCommand; import jalview.io.AlignmentProperties; import jalview.io.AnnotationFile; import jalview.io.BioJsHTMLOutput; @@ -88,6 +95,7 @@ import jalview.schemes.ColourSchemes; import jalview.schemes.ResidueColourScheme; import jalview.schemes.TCoffeeColourScheme; import jalview.util.MessageManager; +import jalview.util.StringUtils; import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import jalview.ws.DBRefFetcher; @@ -95,6 +103,10 @@ import jalview.ws.DBRefFetcher.FetchFinishedListenerI; import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.jws2.jabaws2.Jws2Instance; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; +import jalview.ws.params.WsParamSetI; +import jalview.ws.params.simple.Option; import jalview.ws.seqfetcher.DbSourceProxy; import java.awt.BorderLayout; @@ -124,22 +136,29 @@ import java.awt.print.PrinterJob; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.FileWriter; +import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Deque; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; +import java.util.Scanner; import java.util.Vector; import javax.swing.JCheckBoxMenuItem; import javax.swing.JEditorPane; +import javax.swing.JFileChooser; +import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.JLayeredPane; import javax.swing.JMenu; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; @@ -153,6 +172,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener { + Map distribution = new HashMap<>(); // temporary + public static final int DEFAULT_WIDTH = 700; public static final int DEFAULT_HEIGHT = 500; @@ -165,6 +186,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, AlignViewport viewport; public AlignViewControllerI avc; + /* + * The selected HMM for this align frame + */ + SequenceI selectedHMMSequence; List alignPanels = new ArrayList<>(); @@ -178,6 +203,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, */ String fileName = null; + /** * Creates a new AlignFrame object with specific width and height. * @@ -762,6 +788,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, ap.av.updateConservation(ap); ap.av.updateConsensus(ap); ap.av.updateStrucConsensus(ap); + ap.av.initInformationWorker(ap); } } @@ -904,6 +931,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, showConsensusHistogram.setSelected(av.isShowConsensusHistogram()); showSequenceLogo.setSelected(av.isShowSequenceLogo()); normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo()); + showInformationHistogram.setSelected(av.isShowInformationHistogram()); + showHMMSequenceLogo.setSelected(av.isShowHMMSequenceLogo()); + normaliseHMMSequenceLogo.setSelected(av.isNormaliseHMMSequenceLogo()); ColourMenuHelper.setColourSelected(colourMenu, av.getGlobalColourScheme()); @@ -995,6 +1025,198 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } @Override + public void hmmBuild_actionPerformed(boolean withDefaults) + { + if (!alignmentIsSufficient(1)) + { + return; + } + List args = new ArrayList<>(); + if (withDefaults) + { + // todo: construct this in HMMERPreset? + String argName = MessageManager.getString("label.hmmbuild_for"); + String argValue = MessageManager.getString("label.alignment"); + args.add( + new Option(argName, null, false, null, argValue, null, null)); + } + else + { + WsParamSetI set = new HMMERPreset(); + ParamDatastoreI store = HMMERParamStore.forBuild(); + WsJobParameters params = new WsJobParameters(new JFrame(), store, set, + args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMBuild(this, args)).start(); + } + + @Override + public void hmmAlign_actionPerformed(boolean withDefaults) + { + if (!(checkForHMM() && alignmentIsSufficient(2))) + { + return; + } + List args = new ArrayList<>(); + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + ParamDatastoreI store = HMMERParamStore.forAlign(); + WsJobParameters params = new WsJobParameters(new JFrame(), store, set, + args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMAlign(this, args)).start(); + } + + @Override + public void hmmSearch_actionPerformed(boolean withDefaults) + { + if (!checkForHMM()) + { + return; + } + List args = new ArrayList<>(); + if (!withDefaults) + { + WsParamSetI set = new HMMERPreset(); + ParamDatastoreI store = HMMERParamStore.forSearch(); + WsJobParameters params = new WsJobParameters(new JFrame(), store, set, + args); + if (params.showRunDialog()) + { + args = params.getJobParams(); + } + else + { + return; // user cancelled + } + } + new Thread(new HMMSearch(this, args)).start(); + alignPanel.repaint(); + } + + /** + * Checks if the frame has a selected hidden Markov model + * + * @return + */ + private boolean checkForHMM() + { + if (getSelectedHMM() == null) + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.no_selected_hmm")); + return false; + } + return true; + } + + /** + * Checks if the alignment contains the required number of sequences. + * + * @param required + * @return + */ + public boolean alignmentIsSufficient(int required) + { + if (getViewport().getAlignment().getSequences().size() < required) + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.not_enough_sequences")); + return false; + } + return true; + } + + @Override + public void addDatabase_actionPerformed() throws IOException + { + if (Cache.getProperty(Preferences.HMMSEARCH_DB_PATHS) == null) + { + Cache.setProperty(Preferences.HMMSEARCH_DBS, ""); + Cache.setProperty(Preferences.HMMSEARCH_DB_PATHS, ""); + } + + String path = openFileChooser(false); + if (new File(path).exists()) + { + IdentifyFile identifier = new IdentifyFile(); + FileFormatI format = identifier.identify(path, DataSourceType.FILE); + if (format == FileFormat.Fasta || format == FileFormat.Stockholm + || format == FileFormat.Pfam) + { + String currentDbs = Cache.getProperty(Preferences.HMMSEARCH_DBS); + String currentDbPaths = Cache + .getProperty(Preferences.HMMSEARCH_DB_PATHS); + currentDbPaths += " " + path; + + String fileName = StringUtils.getLastToken(path, File.separator); + Scanner scanner = new Scanner(fileName).useDelimiter("."); + String name = scanner.next(); + scanner.close(); + currentDbs += " " + path; // TODO remove path from file name + scanner.close(); + + Cache.setProperty(Preferences.HMMSEARCH_DB_PATHS, currentDbPaths); + Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths); + } + else + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.invalid_format")); + } + } + else + { + JOptionPane.showMessageDialog(this, + MessageManager.getString("warn.not_enough_sequences")); + } + } + + /** + * Opens a file chooser + * + * @param forFolder + * @return + */ + protected String openFileChooser(boolean forFolder) + { + String choice = null; + JFileChooser chooser = new JFileChooser(); + if (forFolder) + { + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } + chooser.setDialogTitle( + MessageManager.getString("label.open_local_file")); + chooser.setToolTipText(MessageManager.getString("action.open")); + + int value = chooser.showOpenDialog(this); + + if (value == JFileChooser.APPROVE_OPTION) + { + choice = chooser.getSelectedFile().getPath(); + } + return choice; + } + + @Override public void reload_actionPerformed(ActionEvent e) { if (fileName != null) @@ -1403,6 +1625,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void associatedData_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { // Pick the tree file JalviewFileChooser chooser = new JalviewFileChooser( @@ -1828,7 +2051,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override protected void copy_actionPerformed(ActionEvent e) { - System.gc(); if (viewport.getSelectionGroup() == null) { return; @@ -1864,23 +2086,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, return; } - ArrayList hiddenColumns = null; + HiddenColumns hiddenColumns = null; if (viewport.hasHiddenColumns()) { - hiddenColumns = new ArrayList<>(); int hiddenOffset = viewport.getSelectionGroup().getStartRes(); int hiddenCutoff = viewport.getSelectionGroup().getEndRes(); - ArrayList hiddenRegions = viewport.getAlignment() - .getHiddenColumns().getHiddenColumnsCopy(); - for (int[] region : hiddenRegions) - { - if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff) - { - hiddenColumns - .add(new int[] - { region[0] - hiddenOffset, region[1] - hiddenOffset }); - } - } + + // create new HiddenColumns object with copy of hidden regions + // between startRes and endRes, offset by startRes + hiddenColumns = new HiddenColumns( + viewport.getAlignment().getHiddenColumns(), hiddenOffset, + hiddenCutoff, hiddenOffset); } Desktop.jalviewClipboard = new Object[] { seqs, @@ -1895,9 +2111,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param e * DOCUMENT ME! + * @throws InterruptedException + * @throws IOException */ @Override protected void pasteNew_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { paste(true); } @@ -1907,9 +2126,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param e * DOCUMENT ME! + * @throws InterruptedException + * @throws IOException */ @Override protected void pasteThis_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { paste(false); } @@ -1919,8 +2141,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param newAlignment * true to paste to a new alignment, otherwise add to this. + * @throws InterruptedException + * @throws IOException */ - void paste(boolean newAlignment) + void paste(boolean newAlignment) throws IOException, InterruptedException { boolean externalPaste = true; try @@ -2209,11 +2433,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Desktop.jalviewClipboard != null && Desktop.jalviewClipboard[2] != null) { - List hc = (List) Desktop.jalviewClipboard[2]; - for (int[] region : hc) - { - af.viewport.hideColumns(region[0], region[1]); - } + HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + af.viewport.setHiddenColumns(hc); } // >>>This is a fix for the moment, until a better solution is @@ -2251,7 +2472,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, System.out.println("Exception whilst pasting: " + ex); // could be anything being pasted in here } - } @Override @@ -2268,11 +2488,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, if (Desktop.jalviewClipboard != null && Desktop.jalviewClipboard[2] != null) { - List hc = (List) Desktop.jalviewClipboard[2]; - for (int region[] : hc) - { - af.viewport.hideColumns(region[0], region[1]); - } + HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2]; + af.viewport.setHiddenColumns(hc); } // >>>This is a fix for the moment, until a better solution is @@ -4554,6 +4771,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, * * @param file * either a filename or a URL string. + * @throws InterruptedException + * @throws IOException */ public void loadJalviewDataFile(String file, DataSourceType sourceType, FileFormatI format, SequenceI assocSeq) @@ -4641,11 +4860,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new JnetAnnotationMaker(); JnetAnnotationMaker.add_annotation(predictions, viewport.getAlignment(), 0, false); - SequenceI repseq = viewport.getAlignment().getSequenceAt(0); - viewport.getAlignment().setSeqrep(repseq); - HiddenColumns cs = new HiddenColumns(); - cs.hideInsertionsFor(repseq); - viewport.getAlignment().setHiddenColumns(cs); + viewport.getAlignment().setupJPredAlignment(); isAnnotation = true; } // else if (IdentifyFile.FeaturesFile.equals(format)) @@ -4664,7 +4879,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } if (isAnnotation) { - alignPanel.adjustAnnotationHeight(); viewport.updateSequenceIdColours(); buildSortByAnnotationScoresMenu(); @@ -4867,14 +5081,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, MessageManager.getString("option.trim_retrieved_seqs")); trimrs.setToolTipText( MessageManager.getString("label.trim_retrieved_sequences")); - trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true)); + trimrs.setSelected( + Cache.getDefault(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true)); trimrs.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { trimrs.setSelected(trimrs.isSelected()); - Cache.setProperty("TRIM_FETCHED_DATASET_SEQS", + Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, Boolean.valueOf(trimrs.isSelected()).toString()); }; }); @@ -5588,6 +5803,68 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } + /** + * Sets the status of the HMMER menu + */ + public void updateHMMERStatus() + { + hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable()); + } + + /** + * Returns the selected hidden Markov model. + * + * @return + */ + public HiddenMarkovModel getSelectedHMM() + { + if (selectedHMMSequence == null) + { + return null; + } + return selectedHMMSequence.getHMM(); + } + + /** + * Returns the selected hidden Markov model. + * + * @return + */ + public SequenceI getSelectedHMMSequence() + { + return selectedHMMSequence; + } + + /** + * Sets the selected hidden Markov model + * + * @param selectedHMM + */ + public void setSelectedHMMSequence(SequenceI selectedHMM) + { + this.selectedHMMSequence = selectedHMM; + hmmAlign.setText(MessageManager.getString("label.hmmalign") + " to " + + selectedHMM.getHMM().getName()); + hmmSearch.setText(MessageManager.getString("label.hmmsearch") + " with " + + selectedHMM.getHMM().getName()); + } + + @Override + public void hmmerMenu_actionPerformed(ActionEvent e) + { + SequenceGroup grp = getViewport().getSelectionGroup(); + if (grp != null) + { + hmmBuild.setText(MessageManager.getString("label.hmmbuild") + " from " + + grp.getName()); + } + else + { + hmmBuild.setText(MessageManager.getString("label.hmmbuild") + + " from Alignment"); + } + } + @Override protected void loadVcf_actionPerformed() { diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java index 4d09084..862c4fb 100644 --- a/src/jalview/gui/AlignViewport.java +++ b/src/jalview/gui/AlignViewport.java @@ -22,7 +22,6 @@ package jalview.gui; import jalview.analysis.AlignmentUtils; import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; -import jalview.analysis.TreeModel; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureColourI; @@ -36,7 +35,6 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; -import jalview.datamodel.PDBEntry; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; @@ -58,10 +56,9 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Rectangle; -import java.util.ArrayList; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; -import java.util.Vector; import javax.swing.JInternalFrame; @@ -95,6 +92,12 @@ public class AlignViewport extends AlignmentViewport private AnnotationColumnChooser annotationColumnSelectionState; + boolean validCharWidth; + + public boolean followSelection = true; + + private Hashtable calcIdParams = new Hashtable<>(); + /** * Creates a new AlignViewport object. * @@ -257,14 +260,14 @@ public class AlignViewport extends AlignmentViewport setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true); - alignment - .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0)); + AlignmentI al = getAlignment(); + al.setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0)); // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done - if (hconsensus == null && !isDataset) + if (consensusProfiles == null && !isDataset) { - if (!alignment.isNucleotide()) + if (!al.isNucleotide()) { showConservation = Cache.getDefault("SHOW_CONSERVATION", true); showQuality = Cache.getDefault("SHOW_QUALITY", true); @@ -276,13 +279,19 @@ public class AlignViewport extends AlignmentViewport showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false); normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO", false); + // for now, use consensus options for Information till it gets its own + setShowHMMSequenceLogo(showSequenceLogo); + setNormaliseHMMSequenceLogo(normaliseSequenceLogo); + setShowInformationHistogram(showConsensusHistogram); showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false); showConsensus = Cache.getDefault("SHOW_IDENTITY", true); showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true); } initAutoAnnotation(); - String colourProperty = alignment.isNucleotide() + // initInformation(); + + String colourProperty = al.isNucleotide() ? Preferences.DEFAULT_COLOUR_NUC : Preferences.DEFAULT_COLOUR_PROT; String schemeName = Cache.getProperty(colourProperty); @@ -293,7 +302,7 @@ public class AlignViewport extends AlignmentViewport ResidueColourScheme.NONE); } ColourSchemeI colourScheme = ColourSchemeProperty - .getColourScheme(alignment, schemeName); + .getColourScheme(al, schemeName); residueShading = new ResidueShader(colourScheme); if (colourScheme instanceof UserColourScheme) @@ -305,12 +314,10 @@ public class AlignViewport extends AlignmentViewport if (residueShading != null) { - residueShading.setConsensus(hconsensus); + residueShading.setConsensus(consensusProfiles); } } - boolean validCharWidth; - /** * {@inheritDoc} */ @@ -393,9 +400,9 @@ public class AlignViewport extends AlignmentViewport /* * replace mappings on our alignment */ - if (alignment != null && align != null) + if (getAlignment() != null && align != null) { - alignment.setCodonFrames(align.getCodonFrames()); + getAlignment().setCodonFrames(align.getCodonFrames()); } } @@ -446,17 +453,17 @@ public class AlignViewport extends AlignmentViewport } /** - * returns the visible column regions of the alignment + * Returns an iterator over the visible column regions of the alignment * * @param selectedRegionOnly * true to just return the contigs intersecting with the selected * area * @return */ - public int[] getViewAsVisibleContigs(boolean selectedRegionOnly) + public Iterator getViewAsVisibleContigs(boolean selectedRegionOnly) { - int[] viscontigs = null; - int start = 0, end = 0; + int start = 0; + int end = 0; if (selectedRegionOnly && selectionGroup != null) { start = selectionGroup.getStartRes(); @@ -464,10 +471,11 @@ public class AlignViewport extends AlignmentViewport } else { - end = alignment.getWidth(); + end = getAlignment().getWidth(); } - viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end); - return viscontigs; + + return getAlignment().getHiddenColumns().getVisContigsIterator(start, + end, false); } /** @@ -516,8 +524,6 @@ public class AlignViewport extends AlignmentViewport return false; } - public boolean followSelection = true; - /** * @return true if view selection should always follow the selections * broadcast by other selection sources @@ -583,17 +589,6 @@ public class AlignViewport extends AlignmentViewport .getStructureSelectionManager(Desktop.instance); } - @Override - public boolean isNormaliseSequenceLogo() - { - return normaliseSequenceLogo; - } - - public void setNormaliseSequenceLogo(boolean state) - { - normaliseSequenceLogo = state; - } - /** * * @return true if alignment characters should be displayed @@ -604,8 +599,6 @@ public class AlignViewport extends AlignmentViewport return validCharWidth; } - private Hashtable calcIdParams = new Hashtable(); - public AutoCalcSetting getCalcIdSettingsFor(String calcId) { return calcIdParams.get(calcId); @@ -1035,4 +1028,5 @@ public class AlignViewport extends AlignmentViewport } fr.setTransparency(featureSettings.getTransparency()); } + } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 3a1dbe8..f5634d2 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -419,8 +419,8 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - start = hidden.findColumnPosition(start); - end = hidden.findColumnPosition(end); + start = hidden.absoluteToVisibleColumn(start); + end = hidden.absoluteToVisibleColumn(end); if (start == end) { if (!hidden.isVisible(r[0])) @@ -678,7 +678,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { // reset the width to exclude hidden columns width = av.getAlignment().getHiddenColumns() - .findColumnPosition(width); + .absoluteToVisibleColumn(width); } hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); @@ -874,15 +874,17 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void paintComponent(Graphics g) { - invalidate(); + invalidate(); // needed so that the id width adjuster works correctly Dimension d = getIdPanel().getIdCanvas().getPreferredSize(); idPanelHolder.setPreferredSize(d); hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12)); - validate(); + + validate(); // needed so that the id width adjuster works correctly /* - * set scroll bar positions + * set scroll bar positions - tried to remove but necessary for split panel to resize correctly + * though I still think this call should be elsewhere. */ ViewportRanges ranges = av.getRanges(); setScrollValues(ranges.getStartRes(), ranges.getStartSeq()); @@ -1174,7 +1176,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int resWidth = getSeqPanel().seqCanvas @@ -1366,7 +1368,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight()) @@ -1584,7 +1586,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int height = ((maxwidth / chunkWidth) + 1) * cHeight; @@ -1813,35 +1815,6 @@ public class AlignmentPanel extends GAlignmentPanel implements */ protected void scrollToCentre(SearchResultsI sr, int verticalOffset) { - /* - * To avoid jumpy vertical scrolling (if some sequences are gapped or not - * mapped), we can make the scroll-to location a sequence above the one - * actually mapped. - */ - SequenceI mappedTo = sr.getResults().get(0).getSequence(); - List seqs = av.getAlignment().getSequences(); - - /* - * This is like AlignmentI.findIndex(seq) but here we are matching the - * dataset sequence not the aligned sequence - */ - boolean matched = false; - for (SequenceI seq : seqs) - { - if (mappedTo == seq.getDatasetSequence()) - { - matched = true; - break; - } - } - if (!matched) - { - return; // failsafe, shouldn't happen - } - - /* - * Scroll to position but centring the target residue. - */ scrollToPosition(sr, verticalOffset, true, true); } diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index 4e181b3..b1a8aff 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -25,6 +25,7 @@ import jalview.analysis.AlignmentUtils; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -33,6 +34,7 @@ import jalview.io.FormatAdapter; import jalview.util.Comparison; import jalview.util.MessageManager; import jalview.util.Platform; +import jalview.workers.InformationThread; import java.awt.Color; import java.awt.Cursor; @@ -41,8 +43,6 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.MediaTracker; import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; @@ -52,10 +52,9 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.regex.Pattern; import javax.swing.JCheckBoxMenuItem; @@ -73,9 +72,16 @@ import javax.swing.ToolTipManager; public class AnnotationLabels extends JPanel implements MouseListener, MouseMotionListener, ActionListener { - // width in pixels within which height adjuster arrows are shown and active + /** + * width in pixels within which height adjuster arrows are shown and active + */ private static final int HEIGHT_ADJUSTER_WIDTH = 50; + /** + * height in pixels for allowing height adjuster to be active + */ + private static int HEIGHT_ADJUSTER_HEIGHT = 10; + private static final Pattern LEFT_ANGLE_BRACKET_PATTERN = Pattern .compile("<"); @@ -105,10 +111,6 @@ public class AnnotationLabels extends JPanel private static final String COPYCONS_SEQ = MessageManager .getString("label.copy_consensus_sequence"); - private static Image adjusterImage; - - private static int adjusterImageHeight; - private final boolean debugRedraw = false; private AlignmentPanel ap; @@ -138,11 +140,6 @@ public class AnnotationLabels extends JPanel av = ap.av; ToolTipManager.sharedInstance().registerComponent(this); - if (adjusterImage == null) - { - loadAdjusterImage(); - } - addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(ap.getAnnotationPanel()); @@ -154,37 +151,6 @@ public class AnnotationLabels extends JPanel } /** - * Loads the gif for the panel height adjustment - */ - protected void loadAdjusterImage() - { - java.net.URL url = getClass().getResource("/images/idwidth.gif"); - Image temp = null; - - if (url != null) - { - temp = Toolkit.getDefaultToolkit().createImage(url); - } - - try - { - MediaTracker mt = new MediaTracker(this); - mt.addImage(temp, 0); - mt.waitForID(0); - } catch (Exception ex) - { - } - - BufferedImage bi = new BufferedImage(temp.getHeight(this), - temp.getWidth(this), BufferedImage.TYPE_INT_RGB); - Graphics2D g = (Graphics2D) bi.getGraphics(); - g.rotate(Math.toRadians(90)); - g.drawImage(temp, 0, -bi.getWidth(this), this); - adjusterImage = bi; - adjusterImageHeight = bi.getHeight(); - } - - /** * DOCUMENT ME! * * @param y @@ -387,6 +353,10 @@ public class AnnotationLabels extends JPanel pop.show(this, evt.getX(), evt.getY()); return; } + + final AlignmentAnnotation ann = aa[selectedRow]; + final boolean isSequenceAnnotation = ann.sequenceRef != null; + item = new JMenuItem(EDITNAME); item.addActionListener(this); pop.add(item); @@ -396,9 +366,9 @@ public class AnnotationLabels extends JPanel // JAL-1264 hide all sequence-specific annotations of this type if (selectedRow < aa.length) { - if (aa[selectedRow].sequenceRef != null) + if (isSequenceAnnotation) { - final String label = aa[selectedRow].label; + final String label = ann.label; JMenuItem hideType = new JMenuItem(); String text = MessageManager.getString("label.hide_all") + " " + label; @@ -411,15 +381,6 @@ public class AnnotationLabels extends JPanel AlignmentUtils.showOrHideSequenceAnnotations( ap.av.getAlignment(), Collections.singleton(label), null, false, false); - // for (AlignmentAnnotation ann : ap.av.getAlignment() - // .getAlignmentAnnotation()) - // { - // if (ann.sequenceRef != null && ann.label != null - // && ann.label.equals(label)) - // { - // ann.visible = false; - // } - // } ap.refresh(true); } }); @@ -442,190 +403,317 @@ public class AnnotationLabels extends JPanel // property methods if (selectedRow < aa.length) { - final String label = aa[selectedRow].label; - if (!aa[selectedRow].autoCalculated) + final String label = ann.label; + if (!(ann.autoCalculated) + && !(InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))) { - if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH) + if (ann.graph == AlignmentAnnotation.NO_GRAPH) { // display formatting settings for this row. pop.addSeparator(); // av and sequencegroup need to implement same interface for item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE, - aa[selectedRow].scaleColLabel); + ann.scaleColLabel); item.addActionListener(this); pop.add(item); } } else if (label.indexOf("Consensus") > -1) { - pop.addSeparator(); - // av and sequencegroup need to implement same interface for - final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( - MessageManager.getString("label.ignore_gaps_consensus"), - (aa[selectedRow].groupRef != null) - ? aa[selectedRow].groupRef.getIgnoreGapsConsensus() - : ap.av.isIgnoreGapsConsensus()); - final AlignmentAnnotation aaa = aa[selectedRow]; - cbmi.addActionListener(new ActionListener() + addConsensusMenu(pop, ann); + } + else if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId())) + { + addHmmerMenu(pop, ann); + } + } + pop.show(this, evt.getX(), evt.getY()); + } + + /** + * Adds context menu options for (alignment or group) Hmmer annotation + * + * @param pop + * @param ann + */ + protected void addHmmerMenu(JPopupMenu pop, final AlignmentAnnotation ann) + { + final boolean isGroupAnnotation = ann.groupRef != null; + pop.addSeparator(); + final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( + MessageManager.getString( + "label.ignore_below_background_frequency"), + isGroupAnnotation + ? ann.groupRef + .isIgnoreBelowBackground() + : ap.av.isIgnoreBelowBackground()); + cbmi.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) { - @Override - public void actionPerformed(ActionEvent e) + if (!ann.groupRef.isUseInfoLetterHeight()) { - if (aaa.groupRef != null) - { - // TODO: pass on reference to ap so the view can be updated. - aaa.groupRef.setIgnoreGapsConsensus(cbmi.getState()); - ap.getAnnotationPanel() - .paint(ap.getAnnotationPanel().getGraphics()); - } - else - { - ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap); - } - ap.alignmentChanged(); + ann.groupRef.setIgnoreBelowBackground(cbmi.getState()); + // todo and recompute group annotation } - }); - pop.add(cbmi); - // av and sequencegroup need to implement same interface for - if (aaa.groupRef != null) + } + else if (!ap.av.isInfoLetterHeight()) { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_histogram"), - aa[selectedRow].groupRef.isShowConsensusHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setShowConsensusHistogram(chist.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( - MessageManager.getString("label.show_group_logo"), - aa[selectedRow].groupRef.isShowSequenceLogo()); - cprofl.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setshowSequenceLogo(cprofl.getState()); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofl); - final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_group_logo"), - aa[selectedRow].groupRef.isNormaliseSequenceLogo()); - cproflnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { + ap.av.setIgnoreBelowBackground(cbmi.getState(), ap); + // todo and recompute annotation + } + ap.alignmentChanged(); // todo not like this + } + }); + pop.add(cbmi); + final JCheckBoxMenuItem letterHeight = new JCheckBoxMenuItem( + MessageManager.getString("label.use_info_for_height"), + isGroupAnnotation ? ann.groupRef.isUseInfoLetterHeight() + : ap.av.isInfoLetterHeight()); + letterHeight.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) + { + ann.groupRef.setInfoLetterHeight((letterHeight.getState())); + ann.groupRef.setIgnoreBelowBackground(true); + // todo and recompute group annotation + } + else + { + ap.av.setInfoLetterHeight(letterHeight.getState(), ap); + ap.av.setIgnoreBelowBackground(true, ap); + // todo and recompute annotation + } + ap.alignmentChanged(); + } + }); + pop.add(letterHeight); + if (isGroupAnnotation) + { + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_histogram"), + ann.groupRef.isShowInformationHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setShowInformationHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_logo"), + ann.groupRef.isShowHMMSequenceLogo()); + cprofl.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setShowHMMSequenceLogo(cprofl.getState()); + ap.repaint(); + } + }); + pop.add(cprofl); + final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_group_logo"), + ann.groupRef.isNormaliseHMMSequenceLogo()); + cproflnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef + .setNormaliseHMMSequenceLogo(cproflnorm.getState()); + // automatically enable logo display if we're clicked + ann.groupRef.setShowHMMSequenceLogo(true); + ap.repaint(); + } + }); + pop.add(cproflnorm); + } + else + { + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_histogram"), + av.isShowInformationHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowInformationHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( + MessageManager.getString("label.show_logo"), + av.isShowHMMSequenceLogo()); + cprof.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowHMMSequenceLogo(cprof.getState()); + ap.repaint(); + } + }); + pop.add(cprof); + final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_logo"), + av.isNormaliseHMMSequenceLogo()); + cprofnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowHMMSequenceLogo(true); + av.setNormaliseHMMSequenceLogo(cprofnorm.getState()); + ap.repaint(); + } + }); + pop.add(cprofnorm); + } + } - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - aaa.groupRef.setNormaliseSequenceLogo(cproflnorm.getState()); - // automatically enable logo display if we're clicked - aaa.groupRef.setshowSequenceLogo(true); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cproflnorm); + /** + * Adds context menu options for (alignment or group) Consensus annotation + * + * @param pop + * @param ann + */ + protected void addConsensusMenu(JPopupMenu pop, + final AlignmentAnnotation ann) + { + final boolean isGroupAnnotation = ann.groupRef != null; + pop.addSeparator(); + + final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem( + MessageManager.getString("label.ignore_gaps_consensus"), + (ann.groupRef != null) + ? ann.groupRef.isIgnoreGapsConsensus() + : ap.av.isIgnoreGapsConsensus()); + cbmi.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + if (isGroupAnnotation) + { + ann.groupRef.setIgnoreGapsConsensus(cbmi.getState()); } else { - final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( - MessageManager.getString("label.show_histogram"), - av.isShowConsensusHistogram()); - chist.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowConsensusHistogram(chist.getState()); - ap.alignFrame.setMenusForViewport(); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(chist); - final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( - MessageManager.getString("label.show_logo"), - av.isShowSequenceLogo()); - cprof.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowSequenceLogo(cprof.getState()); - ap.alignFrame.setMenusForViewport(); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprof); - final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( - MessageManager.getString("label.normalise_logo"), - av.isNormaliseSequenceLogo()); - cprofnorm.addActionListener(new ActionListener() - { - @Override - public void actionPerformed(ActionEvent e) - { - // TODO: pass on reference - // to ap - // so the - // view - // can be - // updated. - av.setShowSequenceLogo(true); - av.setNormaliseSequenceLogo(cprofnorm.getState()); - ap.alignFrame.setMenusForViewport(); - ap.repaint(); - // ap.annotationPanel.paint(ap.annotationPanel.getGraphics()); - } - }); - pop.add(cprofnorm); + ap.av.setIgnoreGapsConsensus(cbmi.getState(), ap); } - final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ); - consclipbrd.addActionListener(this); - pop.add(consclipbrd); + ap.alignmentChanged(); } + }); + pop.add(cbmi); + if (isGroupAnnotation) + { + /* + * group consensus options + */ + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_histogram"), + ann.groupRef.isShowConsensusHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setShowConsensusHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem( + MessageManager.getString("label.show_group_logo"), + ann.groupRef.isShowSequenceLogo()); + cprofl.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setshowSequenceLogo(cprofl.getState()); + ap.repaint(); + } + }); + pop.add(cprofl); + final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_group_logo"), + ann.groupRef.isNormaliseSequenceLogo()); + cproflnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + ann.groupRef.setNormaliseSequenceLogo(cproflnorm.getState()); + // automatically enable logo display if we're clicked + ann.groupRef.setshowSequenceLogo(true); + ap.repaint(); + } + }); + pop.add(cproflnorm); } - pop.show(this, evt.getX(), evt.getY()); + else + { + /* + * alignment consensus options + */ + final JCheckBoxMenuItem chist = new JCheckBoxMenuItem( + MessageManager.getString("label.show_histogram"), + av.isShowConsensusHistogram()); + chist.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowConsensusHistogram(chist.getState()); + ap.repaint(); + } + }); + pop.add(chist); + final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem( + MessageManager.getString("label.show_logo"), + av.isShowSequenceLogo()); + cprof.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowSequenceLogo(cprof.getState()); + ap.repaint(); + } + }); + pop.add(cprof); + final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem( + MessageManager.getString("label.normalise_logo"), + av.isNormaliseSequenceLogo()); + cprofnorm.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + av.setShowSequenceLogo(true); + av.setNormaliseSequenceLogo(cprofnorm.getState()); + ap.repaint(); + } + }); + pop.add(cprofnorm); + } + final JMenuItem consclipbrd = new JMenuItem(COPYCONS_SEQ); + consclipbrd.addActionListener(this); + pop.add(consclipbrd); } /** @@ -816,7 +904,7 @@ public class AnnotationLabels extends JPanel protected void showOrHideAdjuster(MouseEvent evt) { boolean was = resizePanel; - resizePanel = evt.getY() < adjusterImageHeight && evt.getX() < HEIGHT_ADJUSTER_WIDTH; + resizePanel = evt.getY() < HEIGHT_ADJUSTER_HEIGHT && evt.getX() < HEIGHT_ADJUSTER_WIDTH; if (resizePanel != was) { @@ -939,7 +1027,6 @@ public class AnnotationLabels extends JPanel PaintRefresher.Refresh(ap, ap.av.getSequenceSetId()); ap.av.sendSelection(); } - } } return; @@ -968,8 +1055,9 @@ public class AnnotationLabels extends JPanel Alignment ds = new Alignment(dseqs); if (av.hasHiddenColumns()) { - omitHidden = av.getAlignment().getHiddenColumns() - .getVisibleSequenceStrings(0, sq.getLength(), seqs); + Iterator it = av.getAlignment().getHiddenColumns() + .getVisContigsIterator(0, sq.getLength(), false); + omitHidden = new String[] { sq.getSequenceStringFromIterator(it) }; } int[] alignmentStartEnd = new int[] { 0, ds.getWidth() - 1 }; @@ -985,12 +1073,12 @@ public class AnnotationLabels extends JPanel Toolkit.getDefaultToolkit().getSystemClipboard() .setContents(new StringSelection(output), Desktop.instance); - ArrayList hiddenColumns = null; + HiddenColumns hiddenColumns = null; if (av.hasHiddenColumns()) { - hiddenColumns = av.getAlignment().getHiddenColumns() - .getHiddenColumnsCopy(); + hiddenColumns = new HiddenColumns( + av.getAlignment().getHiddenColumns()); } Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset @@ -1010,7 +1098,6 @@ public class AnnotationLabels extends JPanel @Override public void paintComponent(Graphics g) { - int width = getWidth(); if (width == 0) { @@ -1025,7 +1112,6 @@ public class AnnotationLabels extends JPanel } drawComponent(g2, true, width); - } /** @@ -1225,11 +1311,7 @@ public class AnnotationLabels extends JPanel } } - if (resizePanel) - { - // g.drawImage(adjusterImage, 2, 0 - getScrollOffset(), this); - } - else if (dragEvent != null && aa != null) + if (!resizePanel && dragEvent != null && aa != null) { g.setColor(Color.lightGray); g.drawString(aa[selectedRow].label, dragEvent.getX(), diff --git a/src/jalview/gui/AnnotationPanel.java b/src/jalview/gui/AnnotationPanel.java index 438e81b..dee56b0 100755 --- a/src/jalview/gui/AnnotationPanel.java +++ b/src/jalview/gui/AnnotationPanel.java @@ -175,11 +175,12 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (e.isShiftDown()) { e.consume(); - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { av.getRanges().scrollRight(true); } - else + else if (wheelRotation < 0) { av.getRanges().scrollRight(false); } @@ -724,7 +725,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, if (av.hasHiddenColumns()) { column = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(column); + .visibleToAbsoluteColumn(column); } AlignmentAnnotation ann = aa[row]; @@ -782,6 +783,10 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, { this.setToolTipText(JvSwingUtils.wrapTooltip(true, description)); } + else + { + this.setToolTipText(null); // no tooltip if null or empty description + } } else { @@ -904,6 +909,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, @Override public void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); @@ -959,7 +966,7 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, gg.fillRect(0, 0, imgWidth, image.getHeight()); imageFresh = true; } - + drawComponent(gg, av.getRanges().getStartRes(), av.getRanges().getEndRes() + 1); imageFresh = false; @@ -992,10 +999,8 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, int er = av.getRanges().getEndRes() + 1; int transX = 0; - long stime = System.currentTimeMillis(); gg.copyArea(0, 0, imgWidth, getHeight(), -horizontal * av.getCharWidth(), 0); - long mtime = System.currentTimeMillis(); if (horizontal > 0) // scrollbar pulled right, image to the left { @@ -1012,17 +1017,13 @@ public class AnnotationPanel extends JPanel implements AwtRenderPanelI, drawComponent(gg, sr, er); gg.translate(-transX, 0); - long dtime = System.currentTimeMillis(); + fastPaint = true; - repaint(); - long rtime = System.currentTimeMillis(); - if (debugRedraw) - { - System.err.println("Scroll:\t" + horizontal + "\tCopyArea:\t" - + (mtime - stime) + "\tDraw component:\t" + (dtime - mtime) - + "\tRepaint call:\t" + (rtime - dtime)); - } + // Call repaint on alignment panel so that repaints from other alignment + // panel components can be aggregated. Otherwise performance of the overview + // window and others may be adversely affected. + av.getAlignPanel().repaint(); } private volatile boolean lastImageGood = false; diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java index f674c7e..eaaf0a5 100644 --- a/src/jalview/gui/CalculationChooser.java +++ b/src/jalview/gui/CalculationChooser.java @@ -23,10 +23,12 @@ package jalview.gui; import jalview.analysis.TreeBuilder; import jalview.analysis.scoremodels.ScoreModels; import jalview.analysis.scoremodels.SimilarityParams; +import jalview.api.AlignViewportI; import jalview.api.analysis.ScoreModelI; import jalview.api.analysis.SimilarityParamsI; import jalview.datamodel.SequenceGroup; import jalview.util.MessageManager; +import jalview.viewmodel.AlignmentViewport; import java.awt.BorderLayout; import java.awt.Color; @@ -103,7 +105,7 @@ public class CalculationChooser extends JPanel final ComboBoxTooltipRenderer renderer = new ComboBoxTooltipRenderer(); - List tips = new ArrayList(); + List tips = new ArrayList<>(); /* * the most recently opened PCA results panel @@ -375,7 +377,7 @@ public class CalculationChooser extends JPanel */ protected JComboBox buildModelOptionsList() { - final JComboBox scoreModelsCombo = new JComboBox(); + final JComboBox scoreModelsCombo = new JComboBox<>(); scoreModelsCombo.setRenderer(renderer); /* @@ -418,7 +420,7 @@ public class CalculationChooser extends JPanel { Object curSel = comboBox.getSelectedItem(); toolTips.clear(); - DefaultComboBoxModel model = new DefaultComboBoxModel(); + DefaultComboBoxModel model = new DefaultComboBoxModel<>(); /* * now we can actually add entries to the combobox, @@ -492,7 +494,7 @@ public class CalculationChooser extends JPanel * gui validation shouldn't allow insufficient sequences here, but leave * this check in in case this method gets exposed programmatically in future */ - AlignViewport viewport = af.getViewport(); + AlignViewportI viewport = af.getViewport(); SequenceGroup sg = viewport.getSelectionGroup(); if (sg != null && sg.getSize() < MIN_TREE_SELECTION) { @@ -519,7 +521,7 @@ public class CalculationChooser extends JPanel */ protected void openPcaPanel(String modelName, SimilarityParamsI params) { - AlignViewport viewport = af.getViewport(); + AlignViewportI viewport = af.getViewport(); /* * gui validation shouldn't allow insufficient sequences here, but leave diff --git a/src/jalview/gui/ColourMenuHelper.java b/src/jalview/gui/ColourMenuHelper.java index 8f0b88c..9479ea6 100644 --- a/src/jalview/gui/ColourMenuHelper.java +++ b/src/jalview/gui/ColourMenuHelper.java @@ -121,8 +121,7 @@ public class ColourMenuHelper */ final String name = scheme.getSchemeName(); String label = MessageManager.getStringOrReturn( - "label.colourScheme_" + name.toLowerCase().replace(" ", "_"), - name); + "label.colourScheme_", name.toLowerCase().replace(" ", "_")); final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem( label); radioItem.setName(name); diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java index 128481c..b26a8af 100644 --- a/src/jalview/gui/Desktop.java +++ b/src/jalview/gui/Desktop.java @@ -849,6 +849,7 @@ public class Desktop extends jalview.jbgui.GDesktop frame.setResizable(resizable); frame.setMaximizable(resizable); frame.setIconifiable(resizable); + frame.setOpaque(false); if (frame.getX() < 1 && frame.getY() < 1) { @@ -899,8 +900,6 @@ public class Desktop extends jalview.jbgui.GDesktop menuItem.removeActionListener(menuItem.getActionListeners()[0]); } windowMenu.remove(menuItem); - - System.gc(); }; }); @@ -1388,7 +1387,6 @@ public class Desktop extends jalview.jbgui.GDesktop { ssm.resetAll(); } - System.gc(); } @Override @@ -1473,7 +1471,8 @@ public class Desktop extends jalview.jbgui.GDesktop return; } - AlignmentViewport source = null, target = null; + AlignViewportI source = null; + AlignViewportI target = null; if (frames[0] instanceof AlignFrame) { source = ((AlignFrame) frames[0]).getCurrentView(); diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java index 1dbc9b8..821454f 100644 --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@ -1028,12 +1028,13 @@ public class FeatureSettings extends JPanel public void invertSelection() { - for (int i = 0; i < table.getRowCount(); i++) + Object[][] data = ((FeatureTableModel) table.getModel()).getData(); + for (int i = 0; i < data.length; i++) { - Boolean value = (Boolean) table.getValueAt(i, SHOW_COLUMN); - - table.setValueAt(new Boolean(!value.booleanValue()), i, SHOW_COLUMN); + data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN]; } + updateFeatureRenderer(data, true); + table.repaint(); } public void orderByAvWidth() diff --git a/src/jalview/gui/IdCanvas.java b/src/jalview/gui/IdCanvas.java index 085b259..cd7b0b7 100755 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@ -83,7 +83,7 @@ public class IdCanvas extends JPanel implements ViewportListenerI this.av = av; PaintRefresher.Register(this, av.getSequenceSetId()); av.getRanges().addPropertyChangeListener(this); - } + } /** * DOCUMENT ME! @@ -204,7 +204,11 @@ public class IdCanvas extends JPanel implements ViewportListenerI gg.translate(0, -transY); fastPaint = true; - repaint(); + + // Call repaint on alignment panel so that repaints from other alignment + // panel components can be aggregated. Otherwise performance of the overview + // window and others may be adversely affected. + av.getAlignPanel().repaint(); } /** @@ -216,41 +220,43 @@ public class IdCanvas extends JPanel implements ViewportListenerI @Override public void paintComponent(Graphics g) { + super.paintComponent(g); + g.setColor(Color.white); g.fillRect(0, 0, getWidth(), getHeight()); - + if (fastPaint) { fastPaint = false; g.drawImage(image, 0, 0, this); - + return; } - + int oldHeight = imgHeight; - + imgHeight = getHeight(); imgHeight -= (imgHeight % av.getCharHeight()); - + if (imgHeight < 1) { return; } - + if (oldHeight != imgHeight || image.getWidth(this) != getWidth()) { - image = new BufferedImage(getWidth(), imgHeight, - BufferedImage.TYPE_INT_RGB); + image = new BufferedImage(getWidth(), imgHeight, + BufferedImage.TYPE_INT_RGB); } - + gg = (Graphics2D) image.getGraphics(); - + // Fill in the background gg.setColor(Color.white); gg.fillRect(0, 0, getWidth(), imgHeight); - + drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq()); - + g.drawImage(image, 0, 0, this); } @@ -374,7 +380,7 @@ public class IdCanvas extends JPanel implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth) - 1; + .absoluteToVisibleColumn(maxwidth) - 1; } int annotationHeight = 0; diff --git a/src/jalview/gui/IdPanel.java b/src/jalview/gui/IdPanel.java index a1726f1..a183144 100755 --- a/src/jalview/gui/IdPanel.java +++ b/src/jalview/gui/IdPanel.java @@ -147,7 +147,8 @@ public class IdPanel extends JPanel public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { if (e.isShiftDown()) { @@ -158,7 +159,7 @@ public class IdPanel extends JPanel av.getRanges().scrollUp(false); } } - else + else if (wheelRotation < 0) { if (e.isShiftDown()) { diff --git a/src/jalview/gui/IdwidthAdjuster.java b/src/jalview/gui/IdwidthAdjuster.java index 99792c6..0cffc3b 100755 --- a/src/jalview/gui/IdwidthAdjuster.java +++ b/src/jalview/gui/IdwidthAdjuster.java @@ -25,7 +25,6 @@ import jalview.api.AlignViewportI; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; -import java.awt.Image; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; @@ -45,8 +44,6 @@ public class IdwidthAdjuster extends JPanel int oldX = 0; - Image image; - AlignmentPanel ap; /** @@ -58,14 +55,7 @@ public class IdwidthAdjuster extends JPanel public IdwidthAdjuster(AlignmentPanel ap) { this.ap = ap; - - java.net.URL url = getClass().getResource("/images/idwidth.gif"); - - if (url != null) - { - image = java.awt.Toolkit.getDefaultToolkit().createImage(url); - } - + setBackground(Color.white); addMouseListener(this); addMouseMotionListener(this); } @@ -197,15 +187,7 @@ public class IdwidthAdjuster extends JPanel if (active) { - if (image != null) - { - // g.drawImage(image, getWidth() - 20, 2, this); setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)); - } - else - { - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } } } } diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index fdc2847..3840597 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -1223,7 +1223,7 @@ public class Jalview2XML jGroup.setTextCol2(sg.textColour2.getRGB()); jGroup.setTextColThreshold(sg.thresholdTextColour); jGroup.setShowUnconserved(sg.getShowNonconserved()); - jGroup.setIgnoreGapsinConsensus(sg.getIgnoreGapsConsensus()); + jGroup.setIgnoreGapsinConsensus(sg.isIgnoreGapsConsensus()); jGroup.setShowConsensusHistogram(sg.isShowConsensusHistogram()); jGroup.setShowSequenceLogo(sg.isShowSequenceLogo()); jGroup.setNormaliseSequenceLogo(sg.isNormaliseSequenceLogo()); @@ -1450,9 +1450,10 @@ public class Jalview2XML } else { - ArrayList hiddenRegions = hidden.getHiddenColumnsCopy(); - for (int[] region : hiddenRegions) + Iterator hiddenRegions = hidden.iterator(); + while (hiddenRegions.hasNext()) { + int[] region = hiddenRegions.next(); HiddenColumns hc = new HiddenColumns(); hc.setStart(region[0]); hc.setEnd(region[1]); @@ -4560,7 +4561,7 @@ public class Jalview2XML af.viewport.getResidueShading().setThreshold(view.getPidThreshold(), view.getIgnoreGapsinConsensus()); af.viewport.getResidueShading() - .setConsensus(af.viewport.getSequenceConsensusHash()); + .setConsensus(af.viewport.getConsensusProfiles()); af.viewport.setColourAppliesToAllGroups(false); if (view.getConservationSelected() && cs != null) diff --git a/src/jalview/gui/Jalview2XML_V1.java b/src/jalview/gui/Jalview2XML_V1.java index 331e738..5cbf228 100755 --- a/src/jalview/gui/Jalview2XML_V1.java +++ b/src/jalview/gui/Jalview2XML_V1.java @@ -413,7 +413,7 @@ public class Jalview2XML_V1 af.viewport.getResidueShading().setThreshold(view.getPidThreshold(), true); af.viewport.getResidueShading() - .setConsensus(af.viewport.getSequenceConsensusHash()); + .setConsensus(af.viewport.getConsensusProfiles()); af.viewport.setColourAppliesToAllGroups(false); af.alignPanel.updateLayout(); af.changeColour(cs); diff --git a/src/jalview/gui/OptsAndParamsPage.java b/src/jalview/gui/OptsAndParamsPage.java index 5342c90..1505df8 100644 --- a/src/jalview/gui/OptsAndParamsPage.java +++ b/src/jalview/gui/OptsAndParamsPage.java @@ -26,6 +26,7 @@ import jalview.ws.params.OptionI; import jalview.ws.params.ParameterI; import jalview.ws.params.ValueConstrainI; import jalview.ws.params.ValueConstrainI.ValueType; +import jalview.ws.params.simple.LogarithmicParameter; import java.awt.BorderLayout; import java.awt.Component; @@ -273,6 +274,9 @@ public class OptsAndParamsPage public class ParamBox extends JPanel implements ChangeListener, ActionListener, MouseListener { + + boolean isLogarithmic; + boolean adjusting = false; boolean choice = false; @@ -325,6 +329,10 @@ public class OptsAndParamsPage choice = true; } } + if (parm instanceof LogarithmicParameter) + { + isLogarithmic = true; + } if (!compact) { @@ -571,13 +579,34 @@ public class OptsAndParamsPage { if (!adjusting) { - valueField.setText("" + ((integ) ? ("" + slider.getValue()) - : ("" + slider.getValue() / 1000f))); + if (!isLogarithmic) + { + valueField.setText("" + ((integ) ? ("" + slider.getValue()) + : ("" + slider.getValue() / 1000f))); + } + else + { + Double base = ((LogarithmicParameter) parameter).getBase(); + Double value = Math.pow( + base, + slider.getValue() / 1000000f); + valueField.setText(formatDouble(value)); + } checkIfModified(); } } + public String formatDouble(Double value) + { + String string = String.format("%3.3f", value); + if (value < 0.001) + { + string = String.format("%3.3e", value); + } + return string; + } + public void updateControls(ParameterI parm) { adjusting = true; @@ -648,7 +677,17 @@ public class OptsAndParamsPage } else { - valueField.setText(parm.getValue()); + if (parm instanceof LogarithmicParameter) + { + Double base = ((LogarithmicParameter) parm).getBase(); + Double value = Math.pow(base, + Double.parseDouble(parm.getValue()) / 1000000); + valueField.setText(formatDouble(value)); + } + else + { + valueField.setText(parm.getValue()); + } } } lastVal = updateSliderFromValueField(); @@ -659,6 +698,7 @@ public class OptsAndParamsPage { int iVal; float fVal; + double dVal; if (validator != null) { if (integ) @@ -700,6 +740,54 @@ public class OptsAndParamsPage } return new int[] { iVal }; } + else if (isLogarithmic) + { + double eValue; + dVal = 0d; + try + { + valueField.setText(valueField.getText().trim()); + eValue = Double.valueOf(valueField.getText()); + + dVal = Math.log(eValue) / Math + .log(((LogarithmicParameter) parameter).getBase()) + * 1000000; + + if (validator.getMin() != null + && validator.getMin().doubleValue() > dVal) + { + dVal = validator.getMin().doubleValue(); + // TODO: provide visual indication that hard limit was reached for + // this parameter + // update value field to reflect any bound checking we performed. + valueField.setText("" + formatDouble(eValue)); + } + if (validator.getMax() != null + && validator.getMax().doubleValue() < dVal) + { + dVal = validator.getMax().doubleValue(); + // TODO: provide visual indication that hard limit was reached for + // this parameter + // update value field to reflect any bound checking we performed. + valueField.setText("" + formatDouble(eValue)); + } + } catch (Exception e) + { + } + ; + if (validator.getMin() != null && validator.getMax() != null) + { + slider.getModel().setRangeProperties((int) (dVal), 1, + (int) (validator.getMin().doubleValue()), + 1 + (int) (validator.getMax().doubleValue()), + true); + } + else + { + slider.setVisible(false); + } + return new double[] { dVal }; + } else { fVal = 0f; @@ -801,9 +889,9 @@ public class OptsAndParamsPage URL linkImageURL = getClass().getResource("/images/link.gif"); - Map optSet = new java.util.LinkedHashMap(); + Map optSet = new java.util.LinkedHashMap<>(); - Map paramSet = new java.util.LinkedHashMap(); + Map paramSet = new java.util.LinkedHashMap<>(); public Map getOptSet() { @@ -904,7 +992,7 @@ public class OptsAndParamsPage */ public List getCurrentSettings() { - List argSet = new ArrayList(); + List argSet = new ArrayList<>(); for (OptionBox opts : getOptSet().values()) { OptionI opt = opts.getOptionIfEnabled(); diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java index 2991889..7994bf2 100644 --- a/src/jalview/gui/OverviewCanvas.java +++ b/src/jalview/gui/OverviewCanvas.java @@ -161,7 +161,6 @@ public class OverviewCanvas extends JComponent od.getColumns(av.getAlignment())); mg.translate(0, -od.getSequencesHeight()); } - System.gc(); or.removePropertyChangeListener(progressPanel); or = null; @@ -183,7 +182,7 @@ public class OverviewCanvas extends JComponent @Override public void paintComponent(Graphics g) { - // super.paintComponent(g); + super.paintComponent(g); if (restart) { diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java index 43b4310..ffedede 100755 --- a/src/jalview/gui/OverviewPanel.java +++ b/src/jalview/gui/OverviewPanel.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import jalview.api.AlignViewportI; import jalview.bin.Cache; import jalview.renderer.OverviewRenderer; import jalview.util.MessageManager; @@ -62,7 +63,7 @@ public class OverviewPanel extends JPanel private OverviewCanvas oviewCanvas; - private AlignViewport av; + private AlignViewportI av; private AlignmentPanel ap; @@ -170,15 +171,20 @@ public class OverviewPanel extends JPanel @Override public void mouseMoved(MouseEvent evt) { - if (od.isPositionInBox(evt.getX(), evt.getY())) + if (!draggingBox) + // don't bother changing the cursor if we're dragging the box + // as we can't have moved inside or out of the box in that case { - // display drag cursor at mouse position - setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); - } - else - { - // reset cursor - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + if (od.isPositionInBox(evt.getX(), evt.getY())) + { + // display drag cursor at mouse position + setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + } + else + { + // reset cursor + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } } } }); @@ -203,6 +209,10 @@ public class OverviewPanel extends JPanel if (!od.isPositionInBox(evt.getX(), evt.getY())) { draggingBox = false; + + // display drag cursor at mouse position + setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + od.updateViewportFromMouse(evt.getX(), evt.getY(), av.getAlignment().getHiddenSequences(), av.getAlignment().getHiddenColumns()); @@ -225,6 +235,13 @@ public class OverviewPanel extends JPanel showPopupMenu(evt); } } + + @Override + public void mouseReleased(MouseEvent evt) + { + draggingBox = false; + } + }); } diff --git a/src/jalview/gui/PairwiseAlignPanel.java b/src/jalview/gui/PairwiseAlignPanel.java index d081794..e736a11 100755 --- a/src/jalview/gui/PairwiseAlignPanel.java +++ b/src/jalview/gui/PairwiseAlignPanel.java @@ -21,13 +21,13 @@ package jalview.gui; import jalview.analysis.AlignSeq; +import jalview.api.AlignViewportI; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentView; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.jbgui.GPairwiseAlignPanel; import jalview.util.MessageManager; -import jalview.viewmodel.AlignmentViewport; import java.awt.event.ActionEvent; import java.util.Vector; @@ -43,7 +43,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel private static final String DASHES = "---------------------\n"; - AlignmentViewport av; + AlignViewportI av; Vector sequences; @@ -51,14 +51,13 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel * Creates a new PairwiseAlignPanel object. * * @param viewport - * DOCUMENT ME! */ - public PairwiseAlignPanel(AlignmentViewport viewport) + public PairwiseAlignPanel(AlignViewportI viewport) { super(); this.av = viewport; - sequences = new Vector(); + sequences = new Vector<>(); SequenceGroup selectionGroup = viewport.getSelectionGroup(); boolean isSelection = selectionGroup != null diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java index 0cf7ef4..e3becf6 100644 --- a/src/jalview/gui/PopupMenu.java +++ b/src/jalview/gui/PopupMenu.java @@ -158,6 +158,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener JMenuItem sequenceFeature = new JMenuItem(); + JMenuItem textColour = new JMenuItem(); JMenu jMenu1 = new JMenu(); @@ -233,8 +234,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener * currently selected sequence (if there is one): */ final List selectedSequence = (seq == null - ? Collections. emptyList() - : Arrays.asList(seq)); + ? Collections. emptyList() : Arrays.asList(seq)); + buildAnnotationTypesMenus(seqShowAnnotationsMenu, seqHideAnnotationsMenu, selectedSequence); configureReferenceAnnotationsMenu(seqAddReferenceAnnotations, @@ -359,6 +360,21 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener }); add(menuItem); + if (sequence.isHMMConsensusSequence()) + { + JMenuItem selectHMM = new JCheckBoxMenuItem(); + selectHMM.setText(MessageManager.getString("label.select_hmm")); + selectHMM.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + selectHMM_actionPerformed(sequence); + } + }); + add(selectHMM); + } + if (alignPanel.av.getSelectionGroup() != null && alignPanel.av.getSelectionGroup().getSize() > 1) { @@ -461,7 +477,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener buildGroupURLMenu(sg, groupLinks); } // Add a 'show all structures' for the current selection - Hashtable pdbe = new Hashtable<>(), reppdb = new Hashtable<>(); + Hashtable pdbe = new Hashtable<>(); + Hashtable reppdb = new Hashtable<>(); SequenceI sqass = null; for (SequenceI sq : alignPanel.av.getSequenceSelection()) @@ -1351,6 +1368,15 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener jMenu1.add(displayNonconserved); } + protected void selectHMM_actionPerformed(SequenceI seq) + { + // TODO move this to Viewport + if (seq.isHMMConsensusSequence()) + { + ap.alignFrame.setSelectedHMMSequence(seq); + } + } + /** * Constructs the entries for the colour menu */ @@ -1561,15 +1587,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener protected void hideInsertions_actionPerformed(ActionEvent actionEvent) { - - HiddenColumns hidden = new HiddenColumns(); - BitSet inserts = new BitSet(), mask = new BitSet(); - - // set mask to preserve existing hidden columns outside selected group - if (ap.av.hasHiddenColumns()) - { - ap.av.getAlignment().getHiddenColumns().markHiddenRegions(mask); - } + HiddenColumns hidden = ap.av.getAlignment().getHiddenColumns(); + BitSet inserts = new BitSet(); boolean markedPopup = false; // mark inserts in current selection @@ -1577,10 +1596,7 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener { // mark just the columns in the selection group to be hidden inserts.set(ap.av.getSelectionGroup().getStartRes(), - ap.av.getSelectionGroup().getEndRes() + 1); - - // and clear that part of the mask - mask.andNot(inserts); + ap.av.getSelectionGroup().getEndRes() + 1); // TODO why +1? // now clear columns without gaps for (SequenceI sq : ap.av.getSelectionGroup().getSequences()) @@ -1591,29 +1607,18 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener } inserts.and(sq.getInsertionsAsBits()); } - } - else - { - // initially, mark all columns to be hidden - inserts.set(0, ap.av.getAlignment().getWidth()); - - // and clear out old hidden regions completely - mask.clear(); + hidden.clearAndHideColumns(inserts, ap.av.getSelectionGroup().getStartRes(), + ap.av.getSelectionGroup().getEndRes()); } // now mark for sequence under popup if we haven't already done it - if (!markedPopup && sequence != null) + else if (!markedPopup && sequence != null) { - inserts.and(sequence.getInsertionsAsBits()); - } + inserts.or(sequence.getInsertionsAsBits()); - // finally, preserve hidden regions outside selection - inserts.or(mask); - - // and set hidden columns accordingly - hidden.hideMarkedBits(inserts); - - ap.av.getAlignment().setHiddenColumns(hidden); + // and set hidden columns accordingly + hidden.hideColumns(inserts); + } refresh(); } diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java index aa8369a..df35b5e 100755 --- a/src/jalview/gui/Preferences.java +++ b/src/jalview/gui/Preferences.java @@ -24,6 +24,7 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; import jalview.bin.Cache; import jalview.gui.Help.HelpId; import jalview.gui.StructureViewer.ViewerType; +import jalview.hmmer.HmmerCommand; import jalview.io.FileFormatI; import jalview.io.JalviewFileChooser; import jalview.io.JalviewFileView; @@ -48,6 +49,8 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; @@ -102,6 +105,12 @@ public class Preferences extends GPreferences public static final String STRUCTURE_DISPLAY = "STRUCTURE_DISPLAY"; public static final String CHIMERA_PATH = "CHIMERA_PATH"; + + public static final String HMMER_PATH = "HMMER_PATH"; + + public static final String HMMSEARCH_DB_PATHS = "HMMSEARCH_DB_PATHS"; + + public static final String HMMSEARCH_DBS = "HMMSEARCH_DBS"; public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS"; @@ -207,6 +216,38 @@ public class Preferences extends GPreferences frame.setMinimumSize(new Dimension(width, height)); /* + * Set HMMER tab defaults + */ + hmmrTrimTermini.setSelected(Cache.getDefault("TRIM_TERMINI", false)); + if (Cache.getDefault("USE_UNIPROT", false)) + { + hmmerBackgroundUniprot.setSelected(true); + } + else + { + hmmerBackgroundAlignment.setSelected(true); + } + hmmerSequenceCount + .setText(Cache.getProperty("SEQUENCES_TO_KEEP")); + hmmerPath.setText(Cache.getProperty(HMMER_PATH)); + hmmerPath.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + validateHMMERPath(true); + } + }); + hmmerPath.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + validateHMMERPath(true); + } + }); + + /* * Set Visual tab defaults */ seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true)); @@ -229,6 +270,9 @@ public class Preferences extends GPreferences Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true)); showConsensLogo .setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO", false)); + showInformationHistogram.setSelected( + Cache.getDefault("SHOW_INFORMATION_HISTOGRAM", true)); + showHMMLogo.setSelected(Cache.getDefault("SHOW_HMM_LOGO", false)); showNpTooltip .setSelected(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true)); showDbRefTooltip @@ -525,7 +569,7 @@ public class Preferences extends GPreferences autoIdWidth.setSelected(Cache.getDefault("FIGURE_AUTOIDWIDTH", false)); userIdWidth.setEnabled(!autoIdWidth.isSelected()); userIdWidthlabel.setEnabled(!autoIdWidth.isSelected()); - Integer wi = Cache.getIntegerProperty("FIGURE_USERIDWIDTH"); + Integer wi = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH"); userIdWidth.setText(wi == null ? "" : wi.toString()); // TODO: refactor to use common enum via FormatAdapter and allow extension // for new flat file formats @@ -610,6 +654,10 @@ public class Preferences extends GPreferences Boolean.toString(showConsensHistogram.isSelected())); Cache.applicationProperties.setProperty("SHOW_CONSENSUS_LOGO", Boolean.toString(showConsensLogo.isSelected())); + Cache.applicationProperties.setProperty("SHOW_INFORMATION_HISTOGRAM", + Boolean.toString(showConsensHistogram.isSelected())); + Cache.applicationProperties.setProperty("SHOW_HMM_LOGO", + Boolean.toString(showHMMLogo.isSelected())); Cache.applicationProperties.setProperty("ANTI_ALIAS", Boolean.toString(smoothFont.isSelected())); Cache.applicationProperties.setProperty(SCALE_PROTEIN_TO_CDNA, @@ -656,6 +704,39 @@ public class Preferences extends GPreferences maxColour.getBackground()); /* + * Save HMMER settings + */ + Cache.applicationProperties.setProperty("TRIM_TERMINI", + Boolean.toString(hmmrTrimTermini.isSelected())); + Cache.applicationProperties.setProperty("USE_UNIPROT", + Boolean.toString(hmmerBackgroundUniprot.isSelected())); + Cache.applicationProperties.setProperty("SEQUENCES_TO_KEEP", + hmmerSequenceCount.getText()); + Cache.applicationProperties.setProperty(HMMER_PATH, + hmmerPath.getText()); + AlignFrame[] frames = Desktop.getAlignFrames(); + if (frames != null && frames.length > 0) + { + for (AlignFrame f : frames) + { + f.updateHMMERStatus(); + } + } + + hmmrTrimTermini.setSelected(Cache.getDefault("TRIM_TERMINI", false)); + if (Cache.getDefault("USE_UNIPROT", false)) + { + hmmerBackgroundUniprot.setSelected(true); + } + else + { + hmmerBackgroundAlignment.setSelected(true); + } + hmmerSequenceCount + .setText(Cache.getProperty("SEQUENCES_TO_KEEP")); + hmmerPath.setText(Cache.getProperty(HMMER_PATH)); + + /* * Save Overview settings */ Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground()); @@ -784,7 +865,7 @@ public class Preferences extends GPreferences Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH", Boolean.toString(autoIdWidth.isSelected())); userIdWidth_actionPerformed(); - Cache.applicationProperties.setProperty("FIGURE_USERIDWIDTH", + Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH", userIdWidth.getText()); /* @@ -898,6 +979,8 @@ public class Preferences extends GPreferences && (identity.isSelected() || showGroupConsensus.isSelected())); showConsensLogo.setEnabled(annotations.isSelected() && (identity.isSelected() || showGroupConsensus.isSelected())); + showInformationHistogram.setEnabled(annotations.isSelected()); + showHMMLogo.setEnabled(annotations.isSelected()); } @Override @@ -1179,6 +1262,53 @@ public class Preferences extends GPreferences } return true; } + + /** + * Returns true if hmmer path is to a folder that contains an executable + * hmmbuild or hmmbuild.exe, else false (optionally after showing a warning + * dialog) + */ + @Override + protected boolean validateHMMERPath(boolean showWarning) + { + String folder = hmmerPath.getText().trim(); + + if (HmmerCommand.getExecutable(HmmerCommand.HMMBUILD, folder) != null) + { + return true; + } + if (showWarning && folder.length() > 0) + { + JvOptionPane.showInternalMessageDialog(Desktop.desktop, + MessageManager.getString("label.hmmbuild_not_found"), + MessageManager.getString("label.invalid_folder"), + JvOptionPane.ERROR_MESSAGE); + } + return false; + } + + /** + * Checks if a file can be executed + * + * @param path + * the path to the file + * @return + */ + public boolean canExecute(String path) + { + File file = new File(path); + if (!file.canExecute()) + { + file = new File(path + ".exe"); + { + if (!file.canExecute()) + { + return false; + } + } + } + return true; + } /** * If Chimera is selected, check it can be found on default or user-specified diff --git a/src/jalview/gui/RotatableCanvas.java b/src/jalview/gui/RotatableCanvas.java index 4ef18d4..02368df 100755 --- a/src/jalview/gui/RotatableCanvas.java +++ b/src/jalview/gui/RotatableCanvas.java @@ -128,7 +128,6 @@ public class RotatableCanvas extends JPanel implements MouseListener, boolean applyToAllViews = false; - // Controller controller; public RotatableCanvas(AlignmentPanel ap) { this.av = ap.av; @@ -136,16 +135,23 @@ public class RotatableCanvas extends JPanel implements MouseListener, addMouseWheelListener(new MouseWheelListener() { + @Override public void mouseWheelMoved(MouseWheelEvent e) { - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { + /* + * zoom in + */ scale = (float) (scale * 1.1); repaint(); } - - else + else if (wheelRotation < 0) { + /* + * zoom out + */ scale = (float) (scale * 0.9); repaint(); } @@ -162,6 +168,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, boolean first = true; + @Override public void setPoints(Vector points, int npoint) { this.points = points; @@ -327,7 +334,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, dim = height; } - return (float) ((dim * scalefactor) / (2 * maxwidth)); + return (dim * scalefactor) / (2 * maxwidth); } /** @@ -352,6 +359,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return DOCUMENT ME! */ + @Override public Dimension getPreferredSize() { if (prefsize != null) @@ -369,6 +377,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * * @return DOCUMENT ME! */ + @Override public Dimension getMinimumSize() { return getPreferredSize(); @@ -380,6 +389,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param g * DOCUMENT ME! */ + @Override public void paintComponent(Graphics g1) { @@ -475,8 +485,8 @@ public class RotatableCanvas extends JPanel implements MouseListener, for (int i = 0; i < npoint; i++) { SequencePoint sp = (SequencePoint) points.elementAt(i); - int x = (int) ((float) (sp.coord[0] - centre[0]) * scale) + halfwidth; - int y = (int) ((float) (sp.coord[1] - centre[1]) * scale) + int x = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth; + int y = (int) ((sp.coord[1] - centre[1]) * scale) + halfheight; float z = sp.coord[1] - centre[2]; @@ -547,6 +557,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyTyped(KeyEvent evt) { } @@ -557,6 +568,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyReleased(KeyEvent evt) { } @@ -567,6 +579,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void keyPressed(KeyEvent evt) { if (evt.getKeyCode() == KeyEvent.VK_UP) @@ -598,6 +611,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseClicked(MouseEvent evt) { } @@ -608,6 +622,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseEntered(MouseEvent evt) { } @@ -618,6 +633,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseExited(MouseEvent evt) { } @@ -628,6 +644,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseReleased(MouseEvent evt) { } @@ -638,6 +655,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mousePressed(MouseEvent evt) { int x = evt.getX(); @@ -690,6 +708,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, // controller.handleSequenceSelectionEvent(new // SequenceSelectionEvent(this,sel)); // } + @Override public void mouseMoved(MouseEvent evt) { SequenceI found = findPoint(evt.getX(), evt.getY()); @@ -710,6 +729,7 @@ public class RotatableCanvas extends JPanel implements MouseListener, * @param evt * DOCUMENT ME! */ + @Override public void mouseDragged(MouseEvent evt) { mx = evt.getX(); @@ -725,8 +745,8 @@ public class RotatableCanvas extends JPanel implements MouseListener, { rotmat.setIdentity(); - rotmat.rotate((float) (my - omy), 'x'); - rotmat.rotate((float) (mx - omx), 'y'); + rotmat.rotate(my - omy, 'x'); + rotmat.rotate(mx - omx, 'y'); for (int i = 0; i < npoint; i++) { @@ -774,9 +794,9 @@ public class RotatableCanvas extends JPanel implements MouseListener, { SequencePoint sp = (SequencePoint) points.elementAt(i); int tmp1 = (int) (((sp.coord[0] - centre[0]) * scale) - + ((float) getWidth() / 2.0)); + + (getWidth() / 2.0)); int tmp2 = (int) (((sp.coord[1] - centre[1]) * scale) - + ((float) getHeight() / 2.0)); + + (getHeight() / 2.0)); if ((tmp1 > x1) && (tmp1 < x2) && (tmp2 > y1) && (tmp2 < y2)) { @@ -816,9 +836,9 @@ public class RotatableCanvas extends JPanel implements MouseListener, for (int i = 0; i < npoint; i++) { SequencePoint sp = (SequencePoint) points.elementAt(i); - int px = (int) ((float) (sp.coord[0] - centre[0]) * scale) + int px = (int) ((sp.coord[0] - centre[0]) * scale) + halfwidth; - int py = (int) ((float) (sp.coord[1] - centre[1]) * scale) + int py = (int) ((sp.coord[1] - centre[1]) * scale) + halfheight; if ((Math.abs(px - x) < 3) && (Math.abs(py - y) < 3)) diff --git a/src/jalview/gui/ScalePanel.java b/src/jalview/gui/ScalePanel.java index 798c833..e6bba02 100755 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@ -42,6 +42,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; +import java.util.Iterator; import java.util.List; import javax.swing.JMenuItem; @@ -112,7 +113,7 @@ public class ScalePanel extends JPanel if (av.hasHiddenColumns()) { - x = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(x); + x = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x); } if (x >= av.getAlignment().getWidth()) @@ -174,7 +175,7 @@ public class ScalePanel extends JPanel }); pop.add(item); - if (av.getAlignment().getHiddenColumns().hasHiddenColumns()) + if (av.getAlignment().getHiddenColumns().hasMultiHiddenColumnRegions()) { item = new JMenuItem(MessageManager.getString("action.reveal_all")); item.addActionListener(new ActionListener() @@ -281,7 +282,7 @@ public class ScalePanel extends JPanel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } if (res >= av.getAlignment().getWidth()) @@ -336,7 +337,7 @@ public class ScalePanel extends JPanel int res = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes(); res = Math.max(0, res); - res = hidden.adjustForHiddenColumns(res); + res = hidden.visibleToAbsoluteColumn(res); res = Math.min(res, av.getAlignment().getWidth() - 1); min = Math.min(res, min); max = Math.max(res, max); @@ -392,7 +393,7 @@ public class ScalePanel extends JPanel reveal = av.getAlignment().getHiddenColumns() .getRegionWithEdgeAtRes(res); - res = av.getAlignment().getHiddenColumns().adjustForHiddenColumns(res); + res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res); ToolTipManager.sharedInstance().registerComponent(this); this.setToolTipText( @@ -409,6 +410,8 @@ public class ScalePanel extends JPanel @Override public void paintComponent(Graphics g) { + super.paintComponent(g); + /* * shouldn't get called in wrapped mode as the scale above is * drawn instead by SeqCanvas.drawNorthScale @@ -457,7 +460,7 @@ public class ScalePanel extends JPanel { if (hidden.isVisible(sel)) { - sel = hidden.findColumnPosition(sel); + sel = hidden.absoluteToVisibleColumn(sel); } else { @@ -487,23 +490,18 @@ public class ScalePanel extends JPanel if (av.getShowHiddenMarkers()) { - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + Iterator it = hidden.getStartRegionIterator(startx, + startx + widthx + 1); + while (it.hasNext()) { - res = pos - startx; - - if (res < 0 || res > widthx) - { - continue; - } + res = it.next() - startx; gg.fillPolygon( new int[] - { -1 + res * avCharWidth - avCharHeight / 4, - -1 + res * avCharWidth + avCharHeight / 4, - -1 + res * avCharWidth }, - new int[] - { y, y, y + 2 * yOf }, 3); + { -1 + res * avCharWidth - avCharHeight / 4, + -1 + res * avCharWidth + avCharHeight / 4, + -1 + res * avCharWidth }, new int[] + { y, y, y + 2 * yOf }, 3); } } } @@ -554,7 +552,11 @@ public class ScalePanel extends JPanel || evt.getPropertyName().equals(ViewportRanges.MOVE_VIEWPORT)) { // scroll event, repaint panel - repaint(); + + // Call repaint on alignment panel so that repaints from other alignment + // panel components can be aggregated. Otherwise performance of the overview + // window and others may be adversely affected. + av.getAlignPanel().repaint(); } } diff --git a/src/jalview/gui/SeqCanvas.java b/src/jalview/gui/SeqCanvas.java index 1e1105f..2d8eb7d 100755 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@ -25,6 +25,7 @@ import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.datamodel.VisibleContigsIterator; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.util.Comparison; @@ -42,6 +43,7 @@ import java.awt.RenderingHints; import java.awt.Shape; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; +import java.util.Iterator; import java.util.List; import javax.swing.JComponent; @@ -198,8 +200,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { HiddenColumns hiddenColumns = av.getAlignment().getHiddenColumns(); - startX = hiddenColumns.adjustForHiddenColumns(startx); - endX = hiddenColumns.adjustForHiddenColumns(endx); + startX = hiddenColumns.visibleToAbsoluteColumn(startx); + endX = hiddenColumns.visibleToAbsoluteColumn(endx); } FontMetrics fm = getFontMetrics(av.getFont()); @@ -295,7 +297,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int endSeq = ranges.getEndSeq(); int transX = 0; int transY = 0; - + gg.copyArea(horizontal * charWidth, vertical * charHeight, img.getWidth(), img.getHeight(), -horizontal * charWidth, -vertical * charHeight); @@ -337,7 +339,10 @@ public class SeqCanvas extends JComponent implements ViewportListenerI drawPanel(gg, startRes, endRes, startSeq, endSeq, 0); gg.translate(-transX, -transY); - repaint(); + // Call repaint on alignment panel so that repaints from other alignment + // panel components can be aggregated. Otherwise performance of the + // overview window and others may be adversely affected. + av.getAlignPanel().repaint(); } finally { fastpainting = false; @@ -351,20 +356,20 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charHeight = av.getCharHeight(); int charWidth = av.getCharWidth(); - + ViewportRanges ranges = av.getRanges(); - + int width = getWidth(); int height = getHeight(); - + width -= (width % charWidth); height -= (height % charHeight); - + // selectImage is the selection group outline image BufferedImage selectImage = drawSelectionGroup( ranges.getStartRes(), ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); - + if ((img != null) && (fastPaint || (getVisibleRect().width != g.getClipBounds().width) || (getVisibleRect().height != g.getClipBounds().height))) @@ -388,16 +393,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI gg = (Graphics2D) img.getGraphics(); gg.setFont(av.getFont()); } - + if (av.antiAlias) { gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } - + gg.setColor(Color.white); gg.fillRect(0, 0, img.getWidth(), img.getHeight()); - + if (av.getWrapAlignment()) { drawWrappedPanel(gg, getWidth(), getHeight(), ranges.getStartRes()); @@ -407,7 +412,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq(), 0); } - + // lcimg is a local *copy* of img which we'll draw selectImage on top of BufferedImage lcimg = buildLocalImage(selectImage); g.drawImage(lcimg, 0, 0, this); @@ -504,8 +509,11 @@ public class SeqCanvas extends JComponent implements ViewportListenerI private BufferedImage buildLocalImage(BufferedImage selectImage) { // clone the cached image - BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), - img.getType()); + BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), + img.getType()); + + // BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), + // img.getType()); Graphics2D g2d = lcimg.createGraphics(); g2d.drawImage(img, 0, 0, null); @@ -545,8 +553,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI try { - lcimg = new BufferedImage(width, height, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works + lcimg = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works } catch (OutOfMemoryError er) { System.gc(); @@ -890,11 +898,14 @@ public class SeqCanvas extends JComponent implements ViewportListenerI int charWidth = av.getCharWidth(); g.setColor(Color.blue); + int res; HiddenColumns hidden = av.getAlignment().getHiddenColumns(); - List positions = hidden.findHiddenRegionPositions(); - for (int pos : positions) + + Iterator it = hidden.getStartRegionIterator(startColumn, + endColumn); + while (it.hasNext()) { - int res = pos - startColumn; + res = it.next() - startColumn; if (res < 0 || res > endColumn - startColumn + 1) { @@ -943,7 +954,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { maxwidth = av.getAlignment().getHiddenColumns() - .findColumnPosition(maxwidth); + .absoluteToVisibleColumn(maxwidth); } // chop the wrapped alignment extent up into panel-sized blocks and treat @@ -1021,29 +1032,23 @@ public class SeqCanvas extends JComponent implements ViewportListenerI else { int screenY = 0; - final int screenYMax = endRes - startRes; - int blockStart = startRes; - int blockEnd = endRes; + int blockStart; + int blockEnd; - for (int[] region : av.getAlignment().getHiddenColumns() - .getHiddenColumnsCopy()) - { - int hideStart = region[0]; - int hideEnd = region[1]; + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + VisibleContigsIterator regions = hidden + .getVisContigsIterator(startRes, endRes + 1, true); - if (hideStart <= blockStart) - { - blockStart += (hideEnd - hideStart) + 1; - continue; - } + while (regions.hasNext()) + { + int[] region = regions.next(); + blockEnd = region[1]; + blockStart = region[0]; /* * draw up to just before the next hidden region, or the end of * the visible region, whichever comes first */ - blockEnd = Math.min(hideStart - 1, blockStart + screenYMax - - screenY); - g1.translate(screenY * charWidth, 0); draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset); @@ -1052,7 +1057,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI * draw the downline of the hidden column marker (ScalePanel draws the * triangle on top) if we reached it */ - if (av.getShowHiddenMarkers() && blockEnd == hideStart - 1) + if (av.getShowHiddenMarkers() + && (regions.hasNext() || regions.endsAtHidden())) { g1.setColor(Color.blue); @@ -1063,23 +1069,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g1.translate(-screenY * charWidth, 0); screenY += blockEnd - blockStart + 1; - blockStart = hideEnd + 1; - - if (screenY > screenYMax) - { - // already rendered last block - return; - } - } - - if (screenY <= screenYMax) - { - // remaining visible region to render - blockEnd = blockStart + screenYMax - screenY; - g1.translate(screenY * charWidth, 0); - draw(g1, blockStart, blockEnd, startSeq, endSeq, yOffset); - - g1.translate(-screenY * charWidth, 0); } } @@ -1137,16 +1126,16 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasSearchResults()) { SearchResultsI searchResults = av.getSearchResults(); - int[] visibleResults = searchResults.getResults(nextSeq, - startRes, endRes); + int[] visibleResults = searchResults.getResults(nextSeq, startRes, + endRes); if (visibleResults != null) { for (int r = 0; r < visibleResults.length; r += 2) { seqRdr.drawHighlightedText(nextSeq, visibleResults[r], - visibleResults[r + 1], (visibleResults[r] - startRes) - * charWidth, offset - + ((i - startSeq) * charHeight)); + visibleResults[r + 1], + (visibleResults[r] - startRes) * charWidth, + offset + ((i - startSeq) * charHeight)); } } } @@ -1278,7 +1267,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI // convert the cursorX into a position on the visible alignment int cursor_xpos = av.getAlignment().getHiddenColumns() - .findColumnPosition(cursorX); + .absoluteToVisibleColumn(cursorX); if (av.getAlignment().getHiddenColumns().isVisible(cursorX)) { @@ -1377,22 +1366,17 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { // package into blocks of visible columns int screenY = 0; - int blockStart = startRes; - int blockEnd = endRes; + int blockStart; + int blockEnd; - for (int[] region : av.getAlignment().getHiddenColumns() - .getHiddenColumnsCopy()) + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + VisibleContigsIterator regions = hidden + .getVisContigsIterator(startRes, endRes + 1, true); + while (regions.hasNext()) { - int hideStart = region[0]; - int hideEnd = region[1]; - - if (hideStart <= blockStart) - { - blockStart += (hideEnd - hideStart) + 1; - continue; - } - - blockEnd = hideStart - 1; + int[] region = regions.next(); + blockEnd = region[1]; + blockStart = region[0]; g.translate(screenY * charWidth, 0); drawPartialGroupOutline(g, group, @@ -1400,24 +1384,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI g.translate(-screenY * charWidth, 0); screenY += blockEnd - blockStart + 1; - blockStart = hideEnd + 1; - - if (screenY > (endRes - startRes)) - { - // already rendered last block - break; - } - } - - if (screenY <= (endRes - startRes)) - { - // remaining visible region to render - blockEnd = blockStart + (endRes - startRes) - screenY; - g.translate(screenY * charWidth, 0); - drawPartialGroupOutline(g, group, - blockStart, blockEnd, startSeq, endSeq, offset); - - g.translate(-screenY * charWidth, 0); } } } @@ -1681,9 +1647,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } for (int seqNo = ranges.getStartSeq(); seqNo <= ranges @@ -1726,8 +1692,8 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstCol = alignment.getHiddenColumns() - .findColumnPosition(firstCol); - lastCol = alignment.getHiddenColumns().findColumnPosition(lastCol); + .absoluteToVisibleColumn(firstCol); + lastCol = alignment.getHiddenColumns().absoluteToVisibleColumn(lastCol); } int transX = (firstCol - ranges.getStartRes()) * av.getCharWidth(); int transY = (firstSeq - ranges.getStartSeq()) * av.getCharHeight(); @@ -1784,14 +1750,30 @@ public class SeqCanvas extends JComponent implements ViewportListenerI scrollX = -range; } } - // Both scrolling and resizing change viewport ranges: scrolling changes - // both start and end points, but resize only changes end values. - // Here we only want to fastpaint on a scroll, with resize using a normal - // paint, so scroll events are identified as changes to the horizontal or - // vertical start value. - if (eventName.equals(ViewportRanges.STARTRES)) - { - if (av.getWrapAlignment()) + // Both scrolling and resizing change viewport ranges: scrolling changes + // both start and end points, but resize only changes end values. + // Here we only want to fastpaint on a scroll, with resize using a normal + // paint, so scroll events are identified as changes to the horizontal or + // vertical start value. + if (eventName.equals(ViewportRanges.STARTRES)) + { + if (av.getWrapAlignment()) + { + fastPaintWrapped(scrollX); + } + else + { + fastPaint(scrollX, 0); + } + } + else if (eventName.equals(ViewportRanges.STARTSEQ)) + { + // scroll + fastPaint(0, (int) evt.getNewValue() - (int) evt.getOldValue()); + } + else if (eventName.equals(ViewportRanges.STARTRESANDSEQ)) + { + if (av.getWrapAlignment()) { fastPaintWrapped(scrollX); } @@ -1811,14 +1793,6 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { fastPaintWrapped(scrollX); } - else - { - fastPaint(scrollX, 0); - } - // bizarrely, we only need to scroll on the x value here as fastpaint - // copies the full height of the image anyway. Passing in the y value - // causes nasty repaint artefacts, which only disappear on a full - // repaint. } } @@ -1835,9 +1809,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI { ViewportRanges ranges = av.getRanges(); - // if (Math.abs(scrollX) > ranges.getViewportWidth()) - // JAL-2836, 2836 temporarily removed wrapped fastpaint for release 2.10.3 - if (true) + if (Math.abs(scrollX) > ranges.getViewportWidth()) { /* * shift of more than one view width is @@ -2115,9 +2087,9 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { firstVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(firstVisibleColumn); + .visibleToAbsoluteColumn(firstVisibleColumn); lastVisibleColumn = alignment.getHiddenColumns() - .adjustForHiddenColumns(lastVisibleColumn); + .visibleToAbsoluteColumn(lastVisibleColumn); } int gapHeight = charHeight * (av.getScaleAboveWrapped() ? 2 : 1); @@ -2156,7 +2128,7 @@ public class SeqCanvas extends JComponent implements ViewportListenerI if (av.hasHiddenColumns()) { displayColumn = alignment.getHiddenColumns() - .findColumnPosition(displayColumn); + .absoluteToVisibleColumn(displayColumn); } /* diff --git a/src/jalview/gui/SeqPanel.java b/src/jalview/gui/SeqPanel.java index fb6efe5..193d0ee 100644 --- a/src/jalview/gui/SeqPanel.java +++ b/src/jalview/gui/SeqPanel.java @@ -246,7 +246,7 @@ public class SeqPanel extends JPanel if (av.hasHiddenColumns()) { res = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(res); + .visibleToAbsoluteColumn(res); } return res; @@ -359,13 +359,25 @@ public class SeqPanel extends JPanel int original = seqCanvas.cursorX - dx; int maxWidth = av.getAlignment().getWidth(); - // TODO: once JAL-2759 is ready, change this loop to something more - // efficient - while (!hidden.isVisible(seqCanvas.cursorX) - && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0 - && dx != 0) + if (!hidden.isVisible(seqCanvas.cursorX)) { - seqCanvas.cursorX += dx; + int visx = hidden.absoluteToVisibleColumn(seqCanvas.cursorX - dx); + int[] region = hidden.getRegionWithEdgeAtRes(visx); + + if (region != null) // just in case + { + if (dx == 1) + { + // moving right + seqCanvas.cursorX = region[1] + 1; + } + else if (dx == -1) + { + // moving left + seqCanvas.cursorX = region[0] - 1; + } + } + seqCanvas.cursorX = (seqCanvas.cursorX < 0) ? 0 : seqCanvas.cursorX; } if (seqCanvas.cursorX >= maxWidth @@ -420,7 +432,7 @@ public class SeqPanel extends JPanel { // scrollToWrappedVisible expects x-value to have hidden cols subtracted int x = av.getAlignment().getHiddenColumns() - .findColumnPosition(seqCanvas.cursorX); + .absoluteToVisibleColumn(seqCanvas.cursorX); av.getRanges().scrollToWrappedVisible(x); } else @@ -1260,9 +1272,9 @@ public class SeqPanel extends JPanel { fixedColumns = true; int y1 = av.getAlignment().getHiddenColumns() - .getHiddenBoundaryLeft(startres); + .getNextHiddenBoundary(true, startres); int y2 = av.getAlignment().getHiddenColumns() - .getHiddenBoundaryRight(startres); + .getNextHiddenBoundary(false, startres); if ((insertGap && startres > y1 && lastres < y1) || (!insertGap && startres < y2 && lastres > y2)) @@ -1338,7 +1350,8 @@ public class SeqPanel extends JPanel if (sg.getSize() == av.getAlignment().getHeight()) { if ((av.hasHiddenColumns() && startres < av.getAlignment() - .getHiddenColumns().getHiddenBoundaryRight(startres))) + .getHiddenColumns() + .getNextHiddenBoundary(false, startres))) { endEditing(); return; @@ -1657,7 +1670,8 @@ public class SeqPanel extends JPanel public void mouseWheelMoved(MouseWheelEvent e) { e.consume(); - if (e.getWheelRotation() > 0) + double wheelRotation = e.getPreciseWheelRotation(); + if (wheelRotation > 0) { if (e.isShiftDown()) { @@ -1669,7 +1683,7 @@ public class SeqPanel extends JPanel av.getRanges().scrollUp(false); } } - else + else if (wheelRotation < 0) { if (e.isShiftDown()) { @@ -1853,7 +1867,7 @@ public class SeqPanel extends JPanel // always do this - annotation has own state // but defer colourscheme update until hidden sequences are passed in - boolean vischange = stretchGroup.recalcConservation(true); + boolean vischange = stretchGroup.recalcAnnotations(true); updateOverviewAndStructs |= vischange && av.isSelectionDefinedGroup() && afterDrag; if (stretchGroup.cs != null) diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 5bff407..56d1fac 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import jalview.api.AlignViewportI; import jalview.api.SplitContainerI; import jalview.datamodel.AlignmentI; import jalview.jbgui.GAlignFrame; @@ -215,8 +216,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI topFrame.alignPanel.adjustAnnotationHeight(); bottomFrame.alignPanel.adjustAnnotationHeight(); - final AlignViewport topViewport = topFrame.viewport; - final AlignViewport bottomViewport = bottomFrame.viewport; + final AlignViewportI topViewport = topFrame.viewport; + final AlignViewportI bottomViewport = bottomFrame.viewport; final AlignmentI topAlignment = topViewport.getAlignment(); final AlignmentI bottomAlignment = bottomViewport.getAlignment(); boolean topAnnotations = topViewport.isShowAnnotation(); diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 217f653..198aa62 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -21,6 +21,7 @@ package jalview.gui; +import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Jalview; import jalview.datamodel.DBRefEntry; import jalview.datamodel.DBRefSource; @@ -53,6 +54,8 @@ import java.util.Vector; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; import javax.swing.table.AbstractTableModel; /** @@ -728,16 +731,65 @@ public class StructureChooser extends GStructureChooser } /** + * select structures for viewing by their PDB IDs + * + * @param pdbids + * @return true if structures were found and marked as selected + */ + public boolean selectStructure(String... pdbids) + { + boolean found = false; + + FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption + .getSelectedItem()); + String currentView = selectedFilterOpt.getView(); + JTable restable = (currentView == VIEWS_FILTER) ? getResultTable() + : (currentView == VIEWS_LOCAL_PDB) ? tbl_local_pdb : null; + + if (restable == null) + { + // can't select (enter PDB ID, or load file - need to also select which + // sequence to associate with) + return false; + } + + int pdbIdColIndex = restable.getColumn("PDB Id").getModelIndex(); + for (int r = 0; r < restable.getRowCount(); r++) + { + for (int p = 0; p < pdbids.length; p++) + { + if (String.valueOf(restable.getValueAt(r, pdbIdColIndex)) + .equalsIgnoreCase(pdbids[p])) + { + restable.setRowSelectionInterval(r, r); + found = true; + } + } + } + return found; + } + /** * Handles action event for btn_ok */ @Override public void ok_ActionPerformed() { + showStructures(false); + } + + /** + * structure viewer opened by this dialog, or null + */ + private StructureViewer sViewer = null; + + public void showStructures(boolean waitUntilFinished) + { + final StructureSelectionManager ssm = ap.getStructureSelectionManager(); final int preferredHeight = pnl_filter.getHeight(); - new Thread(new Runnable() + Runnable viewStruc = new Runnable() { @Override public void run() @@ -745,21 +797,24 @@ public class StructureChooser extends GStructureChooser FilterOption selectedFilterOpt = ((FilterOption) cmb_filterOption .getSelectedItem()); String currentView = selectedFilterOpt.getView(); + JTable restable = (currentView == VIEWS_FILTER) ? getResultTable() + : tbl_local_pdb; + if (currentView == VIEWS_FILTER) { - int pdbIdColIndex = getResultTable().getColumn("PDB Id") + int pdbIdColIndex = restable.getColumn("PDB Id") .getModelIndex(); - int refSeqColIndex = getResultTable().getColumn("Ref Sequence") + int refSeqColIndex = restable.getColumn("Ref Sequence") .getModelIndex(); - int[] selectedRows = getResultTable().getSelectedRows(); + int[] selectedRows = restable.getSelectedRows(); PDBEntry[] pdbEntriesToView = new PDBEntry[selectedRows.length]; int count = 0; List selectedSeqsToView = new ArrayList<>(); for (int row : selectedRows) { - String pdbIdStr = getResultTable() + String pdbIdStr = restable .getValueAt(row, pdbIdColIndex).toString(); - SequenceI selectedSeq = (SequenceI) getResultTable() + SequenceI selectedSeq = (SequenceI) restable .getValueAt(row, refSeqColIndex); selectedSeqsToView.add(selectedSeq); PDBEntry pdbEntry = selectedSeq.getPDBEntry(pdbIdStr); @@ -780,7 +835,8 @@ public class StructureChooser extends GStructureChooser } SequenceI[] selectedSeqs = selectedSeqsToView .toArray(new SequenceI[selectedSeqsToView.size()]); - launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs); + sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, + selectedSeqs); } else if (currentView == VIEWS_LOCAL_PDB) { @@ -803,7 +859,8 @@ public class StructureChooser extends GStructureChooser } SequenceI[] selectedSeqs = selectedSeqsToView .toArray(new SequenceI[selectedSeqsToView.size()]); - launchStructureViewer(ssm, pdbEntriesToView, ap, selectedSeqs); + sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, + selectedSeqs); } else if (currentView == VIEWS_ENTER_ID) { @@ -832,7 +889,7 @@ public class StructureChooser extends GStructureChooser } PDBEntry[] pdbEntriesToView = new PDBEntry[] { pdbEntry }; - launchStructureViewer(ssm, pdbEntriesToView, ap, + sViewer = launchStructureViewer(ssm, pdbEntriesToView, ap, new SequenceI[] { selectedSequence }); } @@ -849,14 +906,40 @@ public class StructureChooser extends GStructureChooser DataSourceType.FILE, selectedSequence, true, Desktop.instance); - launchStructureViewer(ssm, new PDBEntry[] { fileEntry }, ap, + sViewer = launchStructureViewer( + ssm, new PDBEntry[] + { fileEntry }, ap, new SequenceI[] { selectedSequence }); } - closeAction(preferredHeight); - mainFrame.dispose(); + SwingUtilities.invokeLater(new Runnable() + { + @Override + public void run() + { + closeAction(preferredHeight); + mainFrame.dispose(); + } + }); } - }).start(); + }; + Thread runner = new Thread(viewStruc); + runner.start(); + if (waitUntilFinished) + { + while (sViewer == null ? runner.isAlive() + : (sViewer.sview == null ? true + : !sViewer.sview.hasMapping())) + { + try + { + Thread.sleep(300); + } catch (InterruptedException ie) + { + + } + } + } } private PDBEntry getFindEntry(String id, Vector pdbEntries) @@ -874,7 +957,8 @@ public class StructureChooser extends GStructureChooser return foundEntry; } - private void launchStructureViewer(StructureSelectionManager ssm, + private StructureViewer launchStructureViewer( + StructureSelectionManager ssm, final PDBEntry[] pdbEntriesToView, final AlignmentPanel alignPanel, SequenceI[] sequences) { @@ -948,6 +1032,7 @@ public class StructureChooser extends GStructureChooser sViewer.viewStructures(pdbEntriesToView[0], sequences, alignPanel); } setProgressBar(null, progressId); + return sViewer; } /** @@ -1178,4 +1263,9 @@ public class StructureChooser extends GStructureChooser { return progressBar.operationInProgress(); } + + public JalviewStructureDisplayI getOpenedStructureViewer() + { + return sViewer == null ? null : sViewer.sview; + } } diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java index fb37b77..f37df71 100644 --- a/src/jalview/gui/StructureViewer.java +++ b/src/jalview/gui/StructureViewer.java @@ -104,7 +104,7 @@ public class StructureViewer new PDBEntry[seqsForPdbs.size()]); SequenceI[][] theSeqs = seqsForPdbs.values().toArray( new SequenceI[seqsForPdbs.size()][]); - JalviewStructureDisplayI sview = null; + if (viewerType.equals(ViewerType.JMOL)) { sview = new AppJmol(ap, pdbsForFile, theSeqs); @@ -203,7 +203,7 @@ public class StructureViewer private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs, SequenceI[] seqsForPdbs, AlignmentPanel ap) { - List seqs = new ArrayList(); + List seqs = new ArrayList<>(); if (pdbs == null || pdbs.length == 0) { return null; @@ -227,11 +227,12 @@ public class StructureViewer ap); } + JalviewStructureDisplayI sview = null; + public JalviewStructureDisplayI viewStructures(PDBEntry pdb, SequenceI[] seqsForPdb, AlignmentPanel ap) { ViewerType viewerType = getViewerType(); - JalviewStructureDisplayI sview = null; if (viewerType.equals(ViewerType.JMOL)) { sview = new AppJmol(pdb, seqsForPdb, null, ap); @@ -270,7 +271,6 @@ public class StructureViewer final boolean usetoColourbyseq = viewerData.isColourWithAlignPanel(); final boolean viewerColouring = viewerData.isColourByViewer(); - JalviewStructureDisplayI sview = null; switch (type) { case JMOL: @@ -287,4 +287,16 @@ public class StructureViewer return sview; } + public boolean isBusy() + { + if (sview != null) + { + if (!sview.hasMapping()) + { + return true; + } + } + return false; + } + } diff --git a/src/jalview/gui/StructureViewerBase.java b/src/jalview/gui/StructureViewerBase.java index 31c20ed..93d675a 100644 --- a/src/jalview/gui/StructureViewerBase.java +++ b/src/jalview/gui/StructureViewerBase.java @@ -34,6 +34,7 @@ import jalview.io.JalviewFileView; import jalview.jbgui.GStructureViewer; import jalview.schemes.ColourSchemeI; import jalview.schemes.ColourSchemes; +import jalview.structure.StructureMapping; import jalview.structures.models.AAStructureBindingModel; import jalview.util.MessageManager; @@ -102,9 +103,9 @@ public abstract class StructureViewerBase extends GStructureViewer protected boolean alignAddedStructures = false; - protected boolean _started = false; + protected volatile boolean _started = false; - protected boolean addingStructures = false; + protected volatile boolean addingStructures = false; protected Thread worker = null; @@ -113,6 +114,13 @@ public abstract class StructureViewerBase extends GStructureViewer protected JMenu viewSelectionMenu; /** + * set after sequence colouring has been applied for this structure viewer. + * used to determine if the final sequence/structure mapping has been + * determined + */ + protected volatile boolean seqColoursApplied = false; + + /** * Default constructor */ public StructureViewerBase() @@ -909,6 +917,7 @@ public abstract class StructureViewerBase extends GStructureViewer { binding.colourBySequence(ap); } + seqColoursApplied = true; } } @@ -1028,4 +1037,42 @@ public abstract class StructureViewerBase extends GStructureViewer seqColour_actionPerformed(null); } } + + @Override + public boolean hasMapping() + { + if (worker != null && (addingStructures || _started)) + { + return false; + } + if (getBinding() == null) + { + if (_aps == null || _aps.size() == 0) + { + // viewer has been closed, but we did at some point run. + return true; + } + return false; + } + String[] pdbids = getBinding().getStructureFiles(); + if (pdbids == null) + { + return false; + } + int p=0; + for (String pdbid:pdbids) { + StructureMapping sm[] = getBinding().getSsm().getMapping(pdbid); + if (sm!=null && sm.length>0 && sm[0]!=null) { + p++; + } + } + // only return true if there is a mapping for every structure file we have loaded + if (p == 0 || p != pdbids.length) + { + return false; + } + // and that coloring has been applied + return seqColoursApplied; + } + } diff --git a/src/jalview/gui/VamsasApplication.java b/src/jalview/gui/VamsasApplication.java index d2086e0..973cfe8 100644 --- a/src/jalview/gui/VamsasApplication.java +++ b/src/jalview/gui/VamsasApplication.java @@ -1074,16 +1074,16 @@ public class VamsasApplication implements SelectionSource, VamsasSource } else { - // int[] intervals = colsel.getVisibleContigs( - // seqsel.getStartRes(), seqsel.getEndRes() + 1); - int[] intervals = hidden.getVisibleContigs( - seqsel.getStartRes(), seqsel.getEndRes() + 1); - for (int iv = 0; iv < intervals.length; iv += 2) + Iterator intervals = hidden + .getVisContigsIterator(seqsel.getStartRes(), + seqsel.getEndRes() + 1, false); + while (intervals.hasNext()) { + int[] region = intervals.next(); Seg s = new Seg(); - s.setStart(intervals[iv] + 1); // vamsas indices begin at - // 1, not zero. - s.setEnd(intervals[iv + 1] + 1); + s.setStart(region[0] + 1); // vamsas indices begin at 1, + // not zero. + s.setEnd(region[1] + 1); s.setInclusive(true); range.addSeg(s); } diff --git a/src/jalview/gui/WsJobParameters.java b/src/jalview/gui/WsJobParameters.java index 10798f6..af52d43 100644 --- a/src/jalview/gui/WsJobParameters.java +++ b/src/jalview/gui/WsJobParameters.java @@ -69,14 +69,13 @@ import javax.swing.border.TitledBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import net.miginfocom.swing.MigLayout; - import compbio.metadata.Argument; import compbio.metadata.Option; import compbio.metadata.Parameter; import compbio.metadata.Preset; import compbio.metadata.PresetManager; import compbio.metadata.RunnerConfig; +import net.miginfocom.swing.MigLayout; /** * job parameter editing/browsing dialog box. User can browse existing settings @@ -159,6 +158,21 @@ public class WsJobParameters extends JPanel implements ItemListener, this(service, null); } + public WsJobParameters(JFrame parent, ParamDatastoreI store, + WsParamSetI preset, + List args) + { + super(); + jbInit(); + this.paramStore = store; + this.service = null; + // argSetModified(false); + // populate parameter table + init(preset, args); + // display in new JFrame attached to parent. + validate(); + } + public WsJobParameters(Jws2Instance service, WsParamSetI preset) { this(null, service, preset, null); @@ -217,10 +231,13 @@ public class WsJobParameters extends JPanel implements ItemListener, { frame = new JDialog(Desktop.instance, true); + if (service != null) + { + frame.setTitle(MessageManager.formatMessage("label.edit_params_for", + new String[] + { service.getActionText() })); + } - frame.setTitle(MessageManager.formatMessage("label.edit_params_for", - new String[] - { service.getActionText() })); Rectangle deskr = Desktop.instance.getBounds(); Dimension pref = this.getPreferredSize(); frame.setBounds( @@ -541,6 +558,12 @@ public class WsJobParameters extends JPanel implements ItemListener, // null; } + init(p, jobArgset); + + } + + void init(WsParamSetI p, List jobArgset) + { Hashtable exnames = new Hashtable(); for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++) { @@ -594,7 +617,6 @@ public class WsJobParameters extends JPanel implements ItemListener, } } settingDialog = false; - } @SuppressWarnings("unchecked") @@ -967,7 +989,7 @@ public class WsJobParameters extends JPanel implements ItemListener, int p = 0; if (args.length > 0) { - Vector services = new Vector(); + Vector services = new Vector<>(); services.addElement(args[p++]); Jws2Discoverer.getDiscoverer().setServiceUrls(services); } @@ -1340,8 +1362,8 @@ public class WsJobParameters extends JPanel implements ItemListener, if (e.getSource() == setName && e.getStateChange() == e.SELECTED) { final String setname = (String) setName.getSelectedItem(); - System.out.println("Item state changed for " + setname - + " (handling ? " + !settingDialog + ")"); + // System.out.println("Item state changed for " + setname + // + " (handling ? " + !settingDialog + ")"); if (settingDialog) { // ignore event diff --git a/src/jalview/hmmer/HMMAlign.java b/src/jalview/hmmer/HMMAlign.java new file mode 100644 index 0000000..44828aa --- /dev/null +++ b/src/jalview/hmmer/HMMAlign.java @@ -0,0 +1,349 @@ +package jalview.hmmer; + +import jalview.analysis.AlignmentSorter; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentOrder; +import jalview.datamodel.AlignmentView; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; +import jalview.gui.JvOptionPane; +import jalview.gui.SplitFrame; +import jalview.io.DataSourceType; +import jalview.io.StockholmFile; +import jalview.util.MessageManager; +import jalview.viewmodel.seqfeatures.FeatureRendererSettings; +import jalview.ws.params.ArgumentI; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +import javax.swing.JInternalFrame; + +public class HMMAlign extends HmmerCommand +{ + static final String HMMALIGN = "hmmalign"; + + static final String ARG_TRIM = "--trim"; + + private final AlignmentI dataset; + + /** + * Constructor for the HMMAlignThread + * + * @param af + * @param args + */ + public HMMAlign(AlignFrame af, List args) + { + super(af, args); + if (alignment.getDataset() != null) + { + dataset = alignment.getDataset(); + } + else + { + dataset = null; + } + } + + /** + * Runs the HMMAlignThread: the data on the alignment or group is exported, + * then the command is executed in the command line and then the data is + * imported and displayed in a new frame (if true). The command is executed + * for each segment of the alignment. Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. + */ + @Override + public void run() + { + HiddenMarkovModel hmm = af.getSelectedHMM(); + if (hmm == null) + { + System.err.println("Can't run hmmalign as no HMM profile selected"); + return; + } + + long msgId = System.currentTimeMillis(); + af.setProgressBar(MessageManager.getString("status.running_hmmalign"), + msgId); + + AlignmentView msa = af.gatherSequencesForAlignment(); + SequenceI[][] subAlignments = msa.getVisibleContigs(alignment.getGapCharacter()); + + List allOrders = new ArrayList<>(); + + SequenceI[][] allResults = new SequenceI[subAlignments.length][]; + int job = 0; + for (SequenceI[] seqs : subAlignments) + { + Hashtable sequencesHash = stashSequences(seqs); + try + { + File modelFile = createTempFile("hmm", ".hmm"); + File alignmentFile = createTempFile("output", ".sto"); + File resultFile = createTempFile("input", ".sto"); + + exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null); + exportHmm(hmm, modelFile.getAbsoluteFile()); + + boolean ran = runCommand(modelFile, alignmentFile, resultFile); + if (!ran) + { + JvOptionPane.showInternalMessageDialog(af, + MessageManager.getString("warn.hmmalign_failed")); + return; + } + + SequenceI[] result = importData(resultFile, allOrders); + recoverSequences(sequencesHash, result); + allResults[job] = result; + modelFile.delete(); + alignmentFile.delete(); + resultFile.delete(); + } catch (IOException e) + { + e.printStackTrace(); + } + job++; + } + + String title = "hmmalign to " + hmm.getConsensusSequence().getName(); + displayResults(allResults, allOrders, msa, title); + + af.setProgressBar("", msgId); + } + + /** + * Executes the hmmalign command and returns true if successful, false if an + * error is detected + * + * @param modelFile + * the HMM to align to + * @param alignmentFile + * the sequences to align + * @param resultFile + * the file to hold the results of alignment + * @return + * @throws IOException + */ + private boolean runCommand(File modelFile, File alignmentFile, + File resultFile) throws IOException + { + String command = getCommandPath(HMMALIGN); + if (command == null) + { + return false; + } + List args = new ArrayList<>(); + args.add(command); + + if (params != null) + { + for (ArgumentI arg : params) + { + String name = arg.getName(); + if (MessageManager.getString("label.trim_termini").equals(name)) + { + args.add(ARG_TRIM); + } + } + } + args.add("-o"); + args.add(resultFile.getAbsolutePath()); + args.add(modelFile.getAbsolutePath()); + args.add(alignmentFile.getAbsolutePath()); + + return runCommand(args); + } + + /** + * Imports the data from the file holding the output of hmmalign + * + * @param resultFile + * @param allOrders + * a list of alignment orders to add to + * + * @return + * @throws IOException + */ + private SequenceI[] importData(File resultFile, + List allOrders) throws IOException + { + StockholmFile file = new StockholmFile(resultFile.getAbsolutePath(), + DataSourceType.FILE); + SequenceI[] result = file.getSeqsAsArray(); + AlignmentOrder msaorder = new AlignmentOrder(result); + AlignmentSorter.recoverOrder(result); + allOrders.add(msaorder); + + return result; + } + + /** + * Displays the results of all 'jobs' in a new frame + * + * @param allResults + * + * @param allOrders + * @param msa + * @param title + */ + private void displayResults(SequenceI[][] allResults, + List allOrders, AlignmentView msa, String title) + { + AlignmentOrder[] arrOrders = allOrders + .toArray(new AlignmentOrder[allOrders.size()]); + Object[] newview = msa.getUpdatedView(allResults, arrOrders, + alignment.getGapCharacter()); + SequenceI[] seqs = (SequenceI[]) newview[0]; + HiddenColumns hidden = (HiddenColumns) newview[1]; + Alignment al = new Alignment(seqs); + al.setProperty("Alignment Program", "hmmalign"); + if (dataset != null) + { + al.setDataset(dataset); + } + + /* + * hack to ensure hmm set on alignment + */ + if (al.getSequenceAt(0).isHMMConsensusSequence()) + { + al.setHmmConsensus(al.getSequenceAt(0)); + } + + displayInNewFrame(al, allOrders, hidden, title); + } + + /** + * Displays the results in a new frame + * + * @param al + * The alignment containing the results + * @param alorders + * The order of the sequences in the alignment on which the jobs were + * run + * @param hidden + * Hidden columns in the previous alignment + * @param title + */ + private void displayInNewFrame(AlignmentI al, + List alorders, HiddenColumns hidden, String title) + { + AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + alignFrame.setTitle(title); + + FeatureRendererSettings featureSettings = af.getFeatureRenderer() + .getSettings(); + // initialise with same renderer settings as in parent alignframe. + alignFrame.getFeatureRenderer().transferSettings(featureSettings); + + addSortByMenuItems(alignFrame, alorders); + + // TODO: refactor retrieve and show as new splitFrame as Desktop method + + /* + * If alignment was requested from one half of a SplitFrame, show in a + * SplitFrame with the other pane similarly aligned. + */ + AlignFrame requestedBy = this.af; + if (requestedBy != null && requestedBy.getSplitViewContainer() != null + && requestedBy.getSplitViewContainer() + .getComplement(requestedBy) != null) + { + AlignmentI complement = requestedBy.getSplitViewContainer() + .getComplement(requestedBy); + String complementTitle = requestedBy.getSplitViewContainer() + .getComplementTitle(requestedBy); + // becomes null if the alignment window was closed before the alignment + // job finished. + AlignmentI copyComplement = new Alignment(complement); + // todo should this be done by copy constructor? + copyComplement.setGapCharacter(complement.getGapCharacter()); + // share the same dataset (and the mappings it holds) + copyComplement.setDataset(complement.getDataset()); + copyComplement.alignAs(al); + if (copyComplement.getHeight() > 0) + { + alignFrame.setTitle(this.af.getTitle()); + AlignFrame af2 = new AlignFrame(copyComplement, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + af2.setTitle(complementTitle); + String linkedTitle = MessageManager + .getString("label.linked_view_title"); + JInternalFrame splitFrame = new SplitFrame( + al.isNucleotide() ? alignFrame : af2, al.isNucleotide() ? af2 : alignFrame); + Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1); + return; + } + } + + /* + * Not from SplitFrame, or failed to created a complementary alignment + */ + Desktop.addInternalFrame(alignFrame, alignFrame.getTitle(), AlignFrame.DEFAULT_WIDTH, + AlignFrame.DEFAULT_HEIGHT); + } + + /** + * Adds sort order options to the AlignFrame menus + * + * @param alignFrame + * @param alorders + */ + protected void addSortByMenuItems(AlignFrame alignFrame, + List alorders) + { + // update orders + if (alorders.size() == 1) + { + alignFrame.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0)); + } + else + { + // construct a non-redundant ordering set + List names = new ArrayList<>(); + for (int i = 0, l = alorders.size(); i < l; i++) + { + String orderName = " Region " + i; + int j = i + 1; + + while (j < l) + { + if (alorders.get(i).equals(alorders.get(j))) + { + alorders.remove(j); + l--; + orderName += "," + j; + } + else + { + j++; + } + } + + if (i == 0 && j == 1) + { + names.add(""); + } + else + { + names.add(orderName); + } + } + for (int i = 0, l = alorders.size(); i < l; i++) + { + alignFrame.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering", + alorders.get(i)); + } + } + } +} diff --git a/src/jalview/hmmer/HMMBuild.java b/src/jalview/hmmer/HMMBuild.java new file mode 100644 index 0000000..d95be48 --- /dev/null +++ b/src/jalview/hmmer/HMMBuild.java @@ -0,0 +1,362 @@ +package jalview.hmmer; + +import jalview.api.AlignViewportI; +import jalview.bin.Cache; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.JvOptionPane; +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +/** + * A class that runs the hmmbuild command as a separate process. + * + * @author gmcarstairs + * + */ +public class HMMBuild extends HmmerCommand +{ + static final String ARG_AMINO = "--amino"; + + static final String ARG_DNA = "--dna"; + + static final String ARG_RNA = "--rna"; + + /** + * Constructor + * + * @param alignFrame + * @param args + */ + public HMMBuild(AlignFrame alignFrame, List args) + { + super(alignFrame, args); + } + + /** + * Builds a HMM from an alignment (and/or groups), then imports and adds it to + * the alignment (and/or groups). Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. + */ + @Override + public void run() + { + if (params == null || params.isEmpty()) + { + Cache.log.error("No parameters to HMMBuild!|"); + return; + } + + long msgID = System.currentTimeMillis(); + af.setProgressBar(MessageManager.getString("status.running_hmmbuild"), + msgID); + + AlignViewportI viewport = af.getViewport(); + try + { + /* + * run hmmbuild for alignment and/or groups as selected + */ + List runBuildFor = parseParameters(viewport); + + for (AnnotatedCollectionI grp : runBuildFor) + { + runHMMBuild(grp); + } + } finally + { + af.setProgressBar("", msgID); + viewport.alignmentChanged(af.alignPanel); + af.buildColourMenu(); // to enable HMMER colour schemes + } + } + + /** + * Scans the parameters to determine whether to run hmmmbuild for the whole + * alignment or specified subgroup(s) or both + * + * @param viewport + * @return + */ + protected List parseParameters( + AlignViewportI viewport) + { + List runBuildFor = new ArrayList<>(); + for (ArgumentI arg : params) + { + String name = arg.getName(); + if (MessageManager.getString("label.hmmbuild_for").equals(name)) + { + String value = arg.getValue(); + if (MessageManager.getString("label.alignment").equals(value)) + { + runBuildFor.add(alignment); + } + else if (MessageManager.getString("label.groups_and_alignment") + .equals(value)) + { + runBuildFor.add(alignment); + runBuildFor.addAll(viewport.getAlignment().getGroups()); + } + else if (MessageManager.getString("label.groups").equals(value)) + { + runBuildFor.addAll(viewport.getAlignment().getGroups()); + } + else if (MessageManager.getString("label.selected_group") + .equals(value)) + { + runBuildFor.add(viewport.getSelectionGroup()); + } + } + else if (MessageManager.getString("label.use_reference") + .equals(name)) + { + // todo disable this option if no RF annotation on alignment + if (!af.getViewport().hasReferenceAnnotation()) + { + JvOptionPane.showInternalMessageDialog(af, MessageManager + .getString("warn.no_reference_annotation")); + // return; + } + } + } + return runBuildFor; + } + + /** + * Runs hmmbuild on the given sequences (alignment or group) + * + * @param grp + */ + private void runHMMBuild(AnnotatedCollectionI ac) + { + File hmmFile = null; + File alignmentFile = null; + try + { + hmmFile = createTempFile("hmm", ".hmm"); + alignmentFile = createTempFile("output", ".sto"); + + if (ac instanceof Alignment) + { + AlignmentI al = (Alignment) ac; + // todo pad gaps in an unaligned SequenceGroup as well? + if (!al.isAligned()) + { + al.padGaps(); + } + } + + deleteHmmSequences(ac); + + List copy = new ArrayList<>(); + if (ac instanceof Alignment) + { + copy.addAll(ac.getSequences()); + } + else + { + SequenceI[] sel = ((SequenceGroup) ac) + .getSelectionAsNewSequences((AlignmentI) ac.getContext()); + for (SequenceI seq : sel) + { + copy.add(seq); + } + } + + SequenceI[] copyArray = copy.toArray(new SequenceI[copy.size()]); + Hashtable sequencesHash = stashSequences(copyArray); + + exportStockholm(copyArray, alignmentFile, ac); + + recoverSequences(sequencesHash, copy.toArray(new SequenceI[] {})); + + boolean ran = runCommand(alignmentFile, hmmFile, ac); + if (!ran) + { + return; + } + importData(hmmFile, ac); + } catch (Exception e) + { + e.printStackTrace(); + } finally + { + if (hmmFile != null) + { + hmmFile.delete(); + } + if (alignmentFile != null) + { + alignmentFile.delete(); + } + } + } + + /** + * A helper method that deletes any HMM consensus sequence from the given + * collection, and from the parent alignment if ac is a subgroup + * + * @param ac + */ + void deleteHmmSequences(AnnotatedCollectionI ac) + { + SequenceI hmmSeq = ac.getHmmConsensus(); + if (hmmSeq != null) + { + if (ac instanceof SequenceGroup) + { + ((SequenceGroup) ac).deleteSequence(hmmSeq, false); + AnnotatedCollectionI context = ac.getContext(); + if (context != null && context instanceof AlignmentI) + { + ((AlignmentI) context).deleteSequence(hmmSeq); + } + } + else + { + ((AlignmentI) ac).deleteSequence(hmmSeq); + } + } + } + + /** + * Constructs and executes the hmmbuild command as a separate process + * + * @param sequencesFile + * the alignment from which the HMM is built + * @param hmmFile + * the output file to which the HMM is written + * @param group + * alignment or group for which the hmm is generated + * + * @return + * @throws IOException + */ + private boolean runCommand(File sequencesFile, File hmmFile, + AnnotatedCollectionI group) throws IOException + { + String cmd = getCommandPath(HMMBUILD); + if (cmd == null) + { + return false; // executable not found + } + List args = new ArrayList<>(); + args.add(cmd); + + /* + * HMM name (will be given to consensus sequence) is + * - as specified by an input parameter if set + * - else group name with _HMM appended (if for a group) + * - else align frame title with _HMM appended (if title is not too long) + * - else "Alignment_HMM" + */ + String name = ""; + + if (params != null) + { + for (ArgumentI arg : params) + { + String argName = arg.getName(); + switch (argName) + { + case "HMM Name": + name = arg.getValue().trim(); + break; + case "Use Reference Annotation": + args.add("--hand"); + break; + } + } + } + + if (group instanceof SequenceGroup) + { + name = ((SequenceGroup) group).getName() + "_HMM"; + } + + if ("".equals(name)) + { + if (af != null && af.getTitle().length() < 15) + { + name = af.getTitle(); + } + else + { + name = "Alignment_HMM"; + } + } + + args.add("-n"); + args.add(name.replace(' ', '_')); + if (!alignment.isNucleotide()) + { + args.add(ARG_AMINO); // TODO check for rna + } + else + { + args.add(ARG_DNA); + } + + args.add(hmmFile.getAbsolutePath()); + args.add(sequencesFile.getAbsolutePath()); + + return runCommand(args); + } + + /** + * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus + * sequence (with attached HMM profile) as the first sequence in the alignment + * or group for which it was generated + * + * @param hmmFile + * @param ac + * (optional) the group for which the hmm was generated + * @throws IOException + */ + private void importData(File hmmFile, AnnotatedCollectionI ac) + throws IOException + { + HMMFile file = new HMMFile( + new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE)); + SequenceI hmmSeq = file.getHMM().getConsensusSequence(); + + if (ac instanceof SequenceGroup) + { + SequenceGroup grp = (SequenceGroup) ac; + char gapChar = alignment.getGapCharacter(); + hmmSeq.insertCharAt(0, ac.getStartRes(), gapChar); + hmmSeq.insertCharAt(ac.getEndRes() + 1, + alignment.getWidth() - ac.getEndRes() - 1, gapChar); + SequenceI topSeq = grp.getSequencesInOrder(alignment)[0]; + int topIndex = alignment.findIndex(topSeq); + alignment.insertSequenceAt(topIndex, hmmSeq); + ac.setSeqrep(hmmSeq); + grp.addSequence(hmmSeq, false); + grp.setHmmConsensus(hmmSeq); + } + else + { + alignment.insertSequenceAt(0, hmmSeq); + alignment.setHmmConsensus(hmmSeq); + } + + if (af.getSelectedHMM() == null) + { + af.setSelectedHMMSequence(hmmSeq); + } + } +} diff --git a/src/jalview/hmmer/HMMERParamStore.java b/src/jalview/hmmer/HMMERParamStore.java new file mode 100644 index 0000000..c668481 --- /dev/null +++ b/src/jalview/hmmer/HMMERParamStore.java @@ -0,0 +1,225 @@ +package jalview.hmmer; + +import jalview.bin.Cache; +import jalview.gui.Preferences; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.ParamDatastoreI; +import jalview.ws.params.WsParamSetI; +import jalview.ws.params.simple.BooleanOption; +import jalview.ws.params.simple.IntegerParameter; +import jalview.ws.params.simple.LogarithmicParameter; +import jalview.ws.params.simple.Option; +import jalview.ws.params.simple.StringParameter; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Scanner; + +public final class HMMERParamStore implements ParamDatastoreI +{ + private static final String HMMBUILD = "hmmbuild"; + + private static final String HMMALIGN = "hmmalign"; + + private static final String HMMSEARCH = "hmmsearch"; + + String name; + + List presets = new ArrayList<>(); + + private HMMERParamStore(String nam) + { + this.name = nam; + } + + public static HMMERParamStore forBuild() + { + return new HMMERParamStore(HMMBUILD); + } + + public static HMMERParamStore forAlign() + { + return new HMMERParamStore(HMMALIGN); + } + + public static HMMERParamStore forSearch() + { + return new HMMERParamStore(HMMSEARCH); + } + + @Override + public List getPresets() + { + return presets; + } + + @Override + public WsParamSetI getPreset(String nam) + { + return null; + } + + @Override + public List getServiceParameters() + { + List args = new ArrayList<>(); + switch (name) + { + case HMMSEARCH: + getHMMSearchParams(args); + break; + case HMMALIGN: + getHMMAlignParams(args); + break; + case HMMBUILD: + getHMMBuildParams(args); + break; + default: + } + + return args; + } + + private void getHMMSearchParams(List args) + { + args.add(new IntegerParameter( + MessageManager.getString("label.number_of_results"), + MessageManager.getString("label.number_of_results_desc"), true, + 100, 0, 100000)); + String names = Cache.getProperty(Preferences.HMMSEARCH_DBS); + if (names != null && !names.isEmpty()) + { + Collection databases = new ArrayList<>(); + databases.add(MessageManager.getString("label.this_alignment")); + Scanner nameScanner = new Scanner(names); + + if (nameScanner.hasNext()) + { + while (nameScanner.hasNext()) + { + String next = nameScanner.next(); + if ("null".equals(next)) + { + Cache.setProperty(Preferences.HMMSEARCH_DBS, ""); + Cache.setProperty(Preferences.HMMSEARCH_DB_PATHS, ""); + } + else + { + databases.add(next); + } + } + } + nameScanner.close(); + args.add(new Option(MessageManager.getString("label.database"), + MessageManager.getString("label.database_for_hmmsearch"), + true, MessageManager.getString("label.this_alignment"), + MessageManager.getString("label.this_alignment"), databases, + null)); + } + args.add(new BooleanOption( + MessageManager.getString("label.auto_align_seqs"), + MessageManager.getString("label.auto_align_seqs_desc"), false, + false, true, null)); + args.add(new BooleanOption( + MessageManager.getString("label.use_accessions"), + MessageManager.getString("label.use_accessions_desc"), false, + false, true, null)); + args.add(new BooleanOption( + MessageManager.getString("label.trim_termini"), + MessageManager.getString("label.trim_termini_desc"), false, + false, true, null)); + args.add(new LogarithmicParameter( + MessageManager.getString("label.seq_e_value"), + MessageManager.getString("label.seq_e_value_desc"), false, -3d, + -37.92977945, 1d, 10d)); + /* + args.add(new DoubleParameter( + MessageManager.getString("label.seq_score"), + MessageManager.getString("label.seq_score_desc"), false, + 0d, 0d, 10000d)); + */ + args.add(new LogarithmicParameter( + MessageManager.getString("label.dom_e_value_desc"), + MessageManager.getString("label.dom_e_value_desc"), false, -3d, + -37.92977945, 1d, 10d)); + /* + args.add(new DoubleParameter( + MessageManager.getString("label.dom_score"), + MessageManager.getString("label.dom_score_desc"), false, 0d, + 0d, + 10000d)); + */ + } + + private void getHMMAlignParams(List args) + { + args.add(new BooleanOption( + MessageManager.getString("label.trim_termini"), + MessageManager.getString("label.trim_termini_desc"), + false, false, true, null)); + } + + private void getHMMBuildParams(List args) + { + args.add(new StringParameter(MessageManager.getString("label.hmm_name"), + MessageManager.getString("label.hmm_name_desc"), true, "")); + // todo only enable Use Reference Annotation if RF is present + args.add(new BooleanOption( + MessageManager.getString("label.use_reference"), + MessageManager.getString("label.use_reference_desc"), true, + true, true, null)); + + Collection options = new ArrayList<>(); + options.add(MessageManager.getString("label.alignment")); + options.add(MessageManager.getString("label.groups_and_alignment")); + options.add(MessageManager.getString("label.groups")); + options.add(MessageManager.getString("label.selected_group")); + + args.add(new Option(MessageManager.getString("label.hmmbuild_for"), + MessageManager.getString("label.hmmbuild_for_desc"), true, + MessageManager.getString("label.alignment"), + MessageManager.getString("label.alignment"), options, null)); + } + + @Override + public boolean presetExists(String forName) + { + return false; + } + + @Override + public void deletePreset(String forName) + { + } + + @Override + public void storePreset(String presetName, String text, + List jobParams) + { + } + + @Override + public void updatePreset(String oldName, String presetName, String text, + List jobParams) + { + } + + @Override + public WsParamSetI parseServiceParameterFile(String forName, + String description, String[] serviceURL, String parameters) + throws IOException + { + return null; + } + + @Override + public String generateServiceParameterFile(WsParamSetI pset) + throws IOException + { + return null; + } + +} diff --git a/src/jalview/hmmer/HMMERPreset.java b/src/jalview/hmmer/HMMERPreset.java new file mode 100644 index 0000000..2712259 --- /dev/null +++ b/src/jalview/hmmer/HMMERPreset.java @@ -0,0 +1,57 @@ +package jalview.hmmer; + +import jalview.ws.params.ArgumentI; +import jalview.ws.params.WsParamSetI; + +import java.util.List; + +public class HMMERPreset implements WsParamSetI +{ + + @Override + public String getName() + { + return null; + } + + @Override + public String getDescription() + { + return null; + } + + @Override + public String[] getApplicableUrls() + { + return null; + } + + @Override + public String getSourceFile() + { + return null; + } + + @Override + public void setSourceFile(String newfile) + { + } + + @Override + public boolean isModifiable() + { + return false; + } + + @Override + public List getArguments() + { + return null; + } + + @Override + public void setArguments(List args) + { + } + +} diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java new file mode 100644 index 0000000..30299e9 --- /dev/null +++ b/src/jalview/hmmer/HMMSearch.java @@ -0,0 +1,320 @@ +package jalview.hmmer; + +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.JvOptionPane; +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.StockholmFile; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.simple.BooleanOption; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import javax.swing.JOptionPane; + +public class HMMSearch extends HmmerCommand +{ + static final String HMMSEARCH = "hmmsearch"; + + boolean realign = false; + + boolean trim = false; + + int seqsToReturn = Integer.MAX_VALUE; + + SequenceI[] seqs; + + /** + * Constructor for the HMMSearchThread + * + * @param af + */ + public HMMSearch(AlignFrame af, List args) + { + super(af, args); + } + + /** + * Runs the HMMSearchThread: the data on the alignment or group is exported, + * then the command is executed in the command line and then the data is + * imported and displayed in a new frame. Call this method directly to execute + * synchronously, or via start() in a new Thread for asynchronously. + */ + @Override + public void run() + { + HiddenMarkovModel hmm = af.getSelectedHMM(); + if (hmm == null) + { + JOptionPane.showMessageDialog(af, + MessageManager.getString("warn.no_selected_hmm")); + return; + } + + SequenceI hmmSeq = af.getSelectedHMMSequence(); + long msgId = System.currentTimeMillis(); + af.setProgressBar(MessageManager.getString("status.running_hmmsearch"), + msgId); + + try + { + File hmmFile = createTempFile("hmm", ".hmm"); + File hitsAlignmentFile = createTempFile("hitAlignment", ".sto"); + File searchOutputFile = createTempFile("searchOutput", ".sto"); + + exportHmm(hmm, hmmFile.getAbsoluteFile()); + + boolean ran = runCommand(searchOutputFile, hitsAlignmentFile, hmmFile); + if (!ran) + { + JvOptionPane.showInternalMessageDialog(af, + MessageManager.getString("warn.hmmsearch_failed")); + return; + } + + importData(hmmSeq, hitsAlignmentFile, hmmFile, searchOutputFile); + // TODO make realignment of search results a step at this level + // and make it conditional on this.realign + } catch (IOException | InterruptedException e) + { + e.printStackTrace(); + } + finally + { + af.setProgressBar("", msgId); + } + } + + /** + * Executes an hmmsearch with the given hmm as input. The database to be + * searched is a local file as specified by the 'Database' parameter, or the + * current alignment (written to file) if none is specified. + * + * @param searchOutputFile + * @param hitsAlignmentFile + * @param hmmFile + * + * @return + * @throws IOException + */ + private boolean runCommand(File searchOutputFile, File hitsAlignmentFile, + File hmmFile) throws IOException + { + String command = getCommandPath(HMMSEARCH); + if (command == null) + { + return false; + } + + List args = new ArrayList<>(); + args.add(command); + args.add("-o"); + args.add(searchOutputFile.getAbsolutePath()); + args.add("-A"); + args.add(hitsAlignmentFile.getAbsolutePath()); + + boolean dbFound = false; + String dbPath = ""; + File databaseFile = null; + + if (params != null) + { + for (ArgumentI arg : params) + { + String name = arg.getName(); + if (MessageManager.getString("label.number_of_results") + .equals(name)) + { + seqsToReturn = Integer.parseInt(arg.getValue()); + } + else if (MessageManager.getString("label.auto_align_seqs") + .equals(name)) + { + realign = true; // TODO: not used + } + else if (MessageManager.getString("label.use_accessions") + .equals(name)) + { + args.add("--acc"); + } + else if (MessageManager.getString("label.seq_e_value").equals(name)) + { + args.add("--incE"); + args.add(arg.getValue()); + } + else if (MessageManager.getString("label.seq_score").equals(name)) + { + args.add("-incT"); + args.add(arg.getValue()); + } + else if (MessageManager.getString("label.dom_e_value_desc") + .equals(name)) + { + args.add("--incdomE"); + args.add(arg.getValue()); + } + else if (MessageManager.getString("label.dom_score").equals(name)) + { + args.add("--incdomT"); + args.add(arg.getValue()); + } + else if (MessageManager.getString("label.trim_termini") + .equals(name)) + { + trim = true; + } + else if (MessageManager.getString("label.database").equals(name)) + { + dbFound = true; + dbPath = arg.getValue(); + if (!MessageManager.getString("label.this_alignment") + .equals(dbPath)) + { + databaseFile = new File(dbPath); + } + } + } + } + + if (!dbFound || MessageManager.getString("label.this_alignment") + .equals(dbPath)) + { + /* + * no external database specified for search, so + * export current alignment as 'database' to search + */ + databaseFile = createTempFile("database", ".sto"); + AlignmentI al = af.getViewport().getAlignment(); + AlignmentI copy = new Alignment(al); + SequenceI hmms = copy.getHmmConsensus(); + if (hmms != null) + { + copy.deleteSequence(hmms); + } + exportStockholm(copy.getSequencesArray(), databaseFile, null); + // StockholmFile stoFile = new StockholmFile(copy); + // stoFile.setSeqs(copy.getSequencesArray()); + // String alignmentString = stoFile.print(); + // PrintWriter writer = new PrintWriter(databaseFile); + // writer.print(alignmentString); + // writer.close(); + } + + args.add(hmmFile.getAbsolutePath()); + args.add(databaseFile.getAbsolutePath()); + + return runCommand(args); + } + + /** + * Imports the data from the temporary file to which the output of hmmsearch + * is directed. + * + * @param hmmSeq + */ + private void importData(SequenceI hmmSeq, File inputAlignmentTemp, + File hmmTemp, File searchOutputFile) + throws IOException, InterruptedException + { + BufferedReader br = new BufferedReader( + new FileReader(inputAlignmentTemp)); + try + { + if (br.readLine() == null) + { + JOptionPane.showMessageDialog(af, + MessageManager.getString("label.no_sequences_found")); + return; + } + StockholmFile file = new StockholmFile(new FileParse( + inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE)); + seqs = file.getSeqsAsArray(); + + readTable(searchOutputFile); + + int seqCount = Math.min(seqs.length, seqsToReturn); + SequenceI[] hmmAndSeqs = new SequenceI[seqCount + 1]; + hmmAndSeqs[0] = hmmSeq; + System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqCount); + + AlignmentI alignment = new Alignment(hmmAndSeqs); + AlignFrame frame = new AlignFrame(alignment, 1, 1); + frame.setSelectedHMMSequence(hmmSeq); + List alignArgs = new ArrayList<>(); + if (trim) + { + alignArgs.add(new BooleanOption( + MessageManager.getString("label.trim_termini"), + MessageManager.getString("label.trim_termini_desc"), true, + true, true, null)); + } + HMMAlign hmmalign = new HMMAlign(frame, alignArgs); + hmmalign.run(); + frame = null; + hmmTemp.delete(); + inputAlignmentTemp.delete(); + searchOutputFile.delete(); + } finally + { + if (br != null) + { + br.close(); + } + } + } + + void readTable(File inputTableTemp) throws IOException + { + BufferedReader br = new BufferedReader(new FileReader(inputTableTemp)); + String line = ""; + while (!line.startsWith("Query:")) + { + line = br.readLine(); + } + for (int i = 0; i < 5; i++) + { + line = br.readLine(); + } + + int index = 0; + while (!" ------ inclusion threshold ------".equals(line) + && !"".equals(line)) + { + Scanner scanner = new Scanner(line); + + String str = scanner.next(); // full sequence eValue score + float eValue = Float.parseFloat(str); + int seqLength = seqs[index].getLength(); + Annotation[] annots = new Annotation[seqLength]; + for (int j = 0; j < seqLength; j++) + { + annots[j] = new Annotation(eValue); + } + AlignmentAnnotation annot = new AlignmentAnnotation("E-value", + "Score", annots); + annot.setScore(Double.parseDouble(str)); + annot.setSequenceRef(seqs[index]); + seqs[index].addAlignmentAnnotation(annot); + + scanner.close(); + line = br.readLine(); + index++; + } + + br.close(); + } + +} diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java new file mode 100644 index 0000000..fe6c0f9 --- /dev/null +++ b/src/jalview/hmmer/HmmerCommand.java @@ -0,0 +1,280 @@ +package jalview.hmmer; + +import jalview.analysis.SeqsetUtils; +import jalview.bin.Cache; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.JvOptionPane; +import jalview.gui.Preferences; +import jalview.io.HMMFile; +import jalview.io.StockholmFile; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.Hashtable; +import java.util.List; + +/** + * Base class for hmmbuild, hmmalign and hmmsearch + * + * @author TZVanaalten + * + */ +public abstract class HmmerCommand implements Runnable +{ + public static final String HMMBUILD = "hmmbuild"; + + protected final AlignFrame af; + + protected final AlignmentI alignment; + + protected final List params; + + /** + * Constructor + * + * @param alignFrame + * @param args + */ + public HmmerCommand(AlignFrame alignFrame, List args) + { + af = alignFrame; + alignment = af.getViewport().getAlignment(); + params = args; + } + + /** + * Answers true if preference HMMER_PATH is set, and its value is the path to + * a directory that contains an executable hmmbuild or + * hmmbuild.exe, else false + * + * @return + */ + public static boolean isHmmerAvailable() + { + File exec = getExecutable(HMMBUILD, Cache.getProperty(Preferences.HMMER_PATH)); + return exec != null; + } + + /** + * Uniquifies the sequences when exporting and stores their details in a + * hashtable + * + * @param seqs + */ + protected Hashtable stashSequences(SequenceI[] seqs) + { + return SeqsetUtils.uniquify(seqs, true); + } + + /** + * Restores the sequence data lost by uniquifying + * + * @param hashtable + * @param seqs + */ + protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs) + { + SeqsetUtils.deuniquify(hashtable, seqs); + } + + /** + * Runs a command as a separate process and waits for it to complete. Answers + * true if the process return status is zero, else false. + * + * @param command + * the executable command and any arguments to it + * @throws IOException + */ + public boolean runCommand(List command) + throws IOException + { + try + { + ProcessBuilder pb = new ProcessBuilder(command); + pb.redirectErrorStream(true); // merge syserr to sysout + final Process p = pb.start(); + new Thread(new Runnable() + { + @Override + public void run() + { + BufferedReader input = new BufferedReader( + new InputStreamReader(p.getInputStream())); + try + { + String line = input.readLine(); + while (line != null) + { + System.out.println(line); + line = input.readLine(); + } + } catch (IOException e) + { + e.printStackTrace(); + } + } + }).start(); + + p.waitFor(); + return p.exitValue() == 0; // 0 is success, by convention + } catch (Exception e) + { + e.printStackTrace(); + return false; + } + } + + /** + * Exports an alignment, and reference (RF) annotation if present, to the + * specified file, in Stockholm format + * + * @param seqs + * @param toFile + * @param annotated + * @throws IOException + */ + public void exportStockholm(SequenceI[] seqs, File toFile, + AnnotatedCollectionI annotated) throws IOException + { + if (seqs == null) + { + return; + } + AlignmentI newAl = new Alignment(seqs); + if (!newAl.isAligned()) + { + newAl.padGaps(); + } + + if (toFile != null && annotated != null) + { + AlignmentAnnotation[] annots = annotated.getAlignmentAnnotation(); + if (annots != null) + { + for (AlignmentAnnotation annot : annots) + { + if (annot.label.contains("Reference") || "RF".equals(annot.label)) + { + AlignmentAnnotation newRF; + if (annot.annotations.length > newAl.getWidth()) + { + Annotation[] rfAnnots = new Annotation[newAl.getWidth()]; + System.arraycopy(annot.annotations, 0, rfAnnots, 0, + rfAnnots.length); + newRF = new AlignmentAnnotation("RF", "Reference Positions", + rfAnnots); + } + else + { + newRF = new AlignmentAnnotation(annot); + } + newAl.addAnnotation(newRF); + } + } + } + } + + StockholmFile file = new StockholmFile(newAl); + String output = file.print(seqs, false); + PrintWriter writer = new PrintWriter(toFile); + writer.println(output); + writer.close(); + } + + /** + * Answers the full path to the given hmmer executable, or null if file cannot + * be found or is not executable + * + * @param cmd + * command short name e.g. hmmalign + * @return + */ + protected String getCommandPath(String cmd) + { + String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH); + File file = getExecutable(cmd, binariesFolder); + if (file == null && af != null) + { + JvOptionPane.showInternalMessageDialog(af, + MessageManager.getString("warn.hmm_command_failed")); + } + + return file == null ? null : file.getAbsolutePath(); + } + + /** + * Answers the executable file for the given hmmer command, or null if not + * found or not executable. The path to the executable is the command name + * prefixed by the hmmer binaries folder path, optionally with .exe appended. + * + * @param cmd + * hmmer command short name, for example hmmbuild + * @param binaryPath + * parent folder containing hmmer executables + * @return + */ + public static File getExecutable(String cmd, String binaryPath) + { + File file = new File(binaryPath, cmd); + if (!file.canExecute()) + { + file = new File(binaryPath, cmd + ".exe"); + { + if (!file.canExecute()) + { + file = null; + } + } + } + return file; + } + + /** + * A convenience method to create a temporary file that is deleted on exit of + * the JVM + * + * @param prefix + * @param suffix + * @return + * @throws IOException + */ + protected File createTempFile(String prefix, String suffix) + throws IOException + { + File f = File.createTempFile(prefix, suffix); + f.deleteOnExit(); + return f; + + } + + /** + * Exports an HMM to the specified file + * + * @param hmm + * @param hmmFile + * @throws IOException + */ + public void exportHmm(HiddenMarkovModel hmm, File hmmFile) + throws IOException + { + if (hmm != null) + { + HMMFile file = new HMMFile(hmm); + PrintWriter writer = new PrintWriter(hmmFile); + writer.print(file.print()); + writer.close(); + } + } +} diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java index 2340283..dcdf98e 100755 --- a/src/jalview/io/AlignFile.java +++ b/src/jalview/io/AlignFile.java @@ -304,9 +304,9 @@ public abstract class AlignFile extends FileParse */ protected void initData() { - seqs = new Vector(); - annotations = new Vector(); - seqGroups = new ArrayList(); + seqs = new Vector<>(); + annotations = new Vector<>(); + seqGroups = new ArrayList<>(); parseCalled = false; } @@ -319,7 +319,7 @@ public abstract class AlignFile extends FileParse @Override public void setSeqs(SequenceI[] s) { - seqs = new Vector(); + seqs = new Vector<>(); for (int i = 0; i < s.length; i++) { @@ -390,7 +390,7 @@ public abstract class AlignFile extends FileParse { if (newickStrings == null) { - newickStrings = new Vector(); + newickStrings = new Vector<>(); } newickStrings.addElement(new String[] { treeName, newickString }); } @@ -414,4 +414,16 @@ public abstract class AlignFile extends FileParse { seqs.add(seq); } + + /** + * Used only for hmmer statistics, so should probably be removed at some + * point. TODO remove this + * + * @return + */ + public Vector getAnnotations() + { + return annotations; + } + } diff --git a/src/jalview/io/AnnotationFile.java b/src/jalview/io/AnnotationFile.java index 00476d6..e578a45 100755 --- a/src/jalview/io/AnnotationFile.java +++ b/src/jalview/io/AnnotationFile.java @@ -968,7 +968,7 @@ public class AnnotationFile else { // consider deferring this till after the file has been parsed ? - hidden.hideInsertionsFor(sr); + hidden.hideList(sr.getInsertions()); } } modified = true; diff --git a/src/jalview/io/FileFormat.java b/src/jalview/io/FileFormat.java index 4b33dbf..6ff5461 100644 --- a/src/jalview/io/FileFormat.java +++ b/src/jalview/io/FileFormat.java @@ -373,8 +373,24 @@ public enum FileFormat implements FileFormatI { return false; } + }, + HMMER3("HMMER3", "hmm", true, true) + { + @Override + public AlignmentFileReaderI getReader(FileParse source) + throws IOException + { + return new HMMFile(source); + } + + @Override + public AlignmentFileWriterI getWriter(AlignmentI al) + { + return new HMMFile(); + } }; + private boolean writable; private boolean readable; diff --git a/src/jalview/io/FileLoader.java b/src/jalview/io/FileLoader.java index f26d6da..2d753c1 100755 --- a/src/jalview/io/FileLoader.java +++ b/src/jalview/io/FileLoader.java @@ -199,6 +199,32 @@ public class FileLoader implements Runnable return alignFrame; } + public void LoadFileOntoAlignmentWaitTillLoaded(AlignViewport viewport, + String file, DataSourceType sourceType, FileFormatI format) + { + this.viewport = viewport; + this.file = file; + this.protocol = sourceType; + this.format = format; + _LoadAlignmentFileWaitTillLoaded(); + } + + protected void _LoadAlignmentFileWaitTillLoaded() + { + Thread loader = new Thread(this); + loader.start(); + + while (loader.isAlive()) + { + try + { + Thread.sleep(500); + } catch (Exception ex) + { + } + } + } + public void updateRecentlyOpened() { Vector recent = new Vector(); @@ -394,6 +420,23 @@ public class FileLoader implements Runnable } // append to existing alignment viewport.addAlignment(al, title); + if (source instanceof HMMFile) + { + AlignmentI alignment = viewport.getAlignment(); + SequenceI seq = alignment + .getSequenceAt(alignment.getAbsoluteHeight() - 1); + if (seq.isHMMConsensusSequence()) + { + /* + * fudge: move HMM consensus sequence from last to first + */ + alignment.deleteSequence(alignment.getAbsoluteHeight() - 1); + alignment.insertSequenceAt(0, seq); + alignment.setHmmConsensus(seq); + } + viewport.getAlignPanel().adjustAnnotationHeight(); + viewport.updateSequenceIdColours(); + } } else { diff --git a/src/jalview/io/FormatAdapter.java b/src/jalview/io/FormatAdapter.java index 7647a16..6d3c18a 100755 --- a/src/jalview/io/FormatAdapter.java +++ b/src/jalview/io/FormatAdapter.java @@ -212,12 +212,12 @@ public class FormatAdapter extends AppletFormatAdapter AlignmentAnnotation na = new AlignmentAnnotation(ala[i]); if (selgp != null) { - hidden.makeVisibleAnnotation(selgp.getStartRes(), - selgp.getEndRes(), na); + na.makeVisibleAnnotation(selgp.getStartRes(), selgp.getEndRes(), + hidden); } else { - hidden.makeVisibleAnnotation(na); + na.makeVisibleAnnotation(hidden); } alv.addAnnotation(na); } diff --git a/src/jalview/io/HMMFile.java b/src/jalview/io/HMMFile.java new file mode 100644 index 0000000..2a17915 --- /dev/null +++ b/src/jalview/io/HMMFile.java @@ -0,0 +1,717 @@ +package jalview.io; + +import jalview.api.AlignExportSettingI; +import jalview.api.AlignmentViewPanel; +import jalview.datamodel.HMMNode; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + + +/** + * Adds capability to read in and write out HMMER3 files. . + * + * + * @author TZVanaalten + * + */ +public class HMMFile extends AlignFile + implements AlignmentFileReaderI, AlignmentFileWriterI +{ + private static final String TERMINATOR = "//"; + + /* + * keys to data in HMM file, used to store as properties of the HiddenMarkovModel + */ + public static final String HMM = "HMM"; + + public static final String NAME = "NAME"; + + public static final String ACCESSION_NUMBER = "ACC"; + + public static final String DESCRIPTION = "DESC"; + + public static final String LENGTH = "LENG"; + + public static final String MAX_LENGTH = "MAXL"; + + public static final String ALPHABET = "ALPH"; + + public static final String DATE = "DATE"; + + public static final String COMMAND_LOG = "COM"; + + public static final String NUMBER_OF_SEQUENCES = "NSEQ"; + + public static final String EFF_NUMBER_OF_SEQUENCES = "EFFN"; + + public static final String CHECK_SUM = "CKSUM"; + + public static final String STATISTICS = "STATS"; + + public static final String COMPO = "COMPO"; + + public static final String GATHERING_THRESHOLD = "GA"; + + public static final String TRUSTED_CUTOFF = "TC"; + + public static final String NOISE_CUTOFF = "NC"; + + public static final String VITERBI = "VITERBI"; + + public static final String MSV = "MSV"; + + public static final String FORWARD = "FORWARD"; + + public static final String MAP = "MAP"; + + public static final String REFERENCE_ANNOTATION = "RF"; + + public static final String CONSENSUS_RESIDUE = "CONS"; + + public static final String CONSENSUS_STRUCTURE = "CS"; + + public static final String MASKED_VALUE = "MM"; + + private static final String ALPH_AMINO = "amino"; + + private static final String ALPH_DNA = "DNA"; + + private static final String ALPH_RNA = "RNA"; + + private static final String ALPHABET_AMINO = "ACDEFGHIKLMNPQRSTVWY"; + + private static final String ALPHABET_DNA = "ACGT"; + + private static final String ALPHABET_RNA = "ACGU"; + + private static final int NUMBER_OF_TRANSITIONS = 7; + + private static final String SPACE = " "; + + /* + * optional guide line added to an output HMMER file, purely for readability + */ + private static final String TRANSITIONTYPELINE = " m->m m->i m->d i->m i->i d->m d->d"; + + private static String NL = System.lineSeparator(); + + private HiddenMarkovModel hmm; + + // number of symbols in the alphabet used in the hidden Markov model + private int numberOfSymbols; + + /** + * Constructor that parses immediately + * + * @param inFile + * @param type + * @throws IOException + */ + public HMMFile(String inFile, DataSourceType type) throws IOException + { + super(inFile, type); + } + + /** + * Constructor that parses immediately + * + * @param source + * @throws IOException + */ + public HMMFile(FileParse source) throws IOException + { + super(source); + } + + /** + * Default constructor + */ + public HMMFile() + { + } + + /** + * Constructor for HMMFile used for exporting + * + * @param hmm + * @param exportImmediately + */ + public HMMFile(HiddenMarkovModel markov) + { + hmm = markov; + } + + /** + * Returns the HMM produced by parsing a HMMER3 file + * + * @return + */ + public HiddenMarkovModel getHMM() + { + return hmm; + } + + /** + * Gets the name of the hidden Markov model + * + * @return + */ + public String getName() + { + return hmm.getName(); + } + + /** + * Reads the data from HMM file into the HMM model + */ + @Override + public void parse() + { + try + { + hmm = new HiddenMarkovModel(); + parseHeaderLines(dataIn); + parseModel(dataIn); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * Reads the header properties from a HMMER3 file and saves them in the + * HiddeMarkovModel. This method exits after reading the next line after the + * HMM line. + * + * @param input + * @throws IOException + */ + void parseHeaderLines(BufferedReader input) throws IOException + { + boolean readingHeaders = true; + hmm.setFileHeader(input.readLine()); + String line = input.readLine(); + while (readingHeaders && line != null) + { + Scanner parser = new Scanner(line); + String next = parser.next(); + if (ALPHABET.equals(next)) + { + String alphabetType = parser.next(); + hmm.setProperty(ALPHABET, alphabetType); + String alphabet = ALPH_DNA.equalsIgnoreCase(alphabetType) + ? ALPHABET_DNA + : (ALPH_RNA.equalsIgnoreCase(alphabetType) ? ALPHABET_RNA + : ALPHABET_AMINO); + numberOfSymbols = hmm.setAlphabet(alphabet); + } + else if (HMM.equals(next)) + { + readingHeaders = false; + String symbols = line.substring(line.indexOf(HMM) + HMM.length()); + numberOfSymbols = hmm.setAlphabet(symbols); + } + else if (STATISTICS.equals(next)) + { + parser.next(); + String key; + String value; + key = parser.next(); + value = parser.next() + SPACE + SPACE + parser.next(); + hmm.setProperty(key, value); + } + else + { + String key = next; + String value = parser.next(); + while (parser.hasNext()) + { + value = value + SPACE + parser.next(); + } + hmm.setProperty(key, value); + } + parser.close(); + line = input.readLine(); + } + } + + /** + * Parses the model data from the HMMER3 file. The input buffer should be + * positioned at the (optional) COMPO line if there is one, else at the insert + * emissions line for the BEGIN node of the model. + * + * @param input + * @throws IOException + */ + void parseModel(BufferedReader input) throws IOException + { + /* + * specification says there must always be an HMM header (already read) + * and one more header (guide headings) which is skipped here + */ + int nodeNo = 0; + String line = input.readLine(); + List nodes = new ArrayList<>(); + + while (line != null && !TERMINATOR.equals(line)) + { + HMMNode node = new HMMNode(); + nodes.add(node); + Scanner scanner = new Scanner(line); + String next = scanner.next(); + + /* + * expect COMPO (optional) for average match emissions + * or a node number followed by node's match emissions + */ + if (COMPO.equals(next) || nodeNo > 0) + { + /* + * parse match emissions + */ + double[] matches = parseDoubles(scanner, numberOfSymbols); + node.setMatchEmissions(matches); + if (!COMPO.equals(next)) + { + int resNo = parseAnnotations(scanner, node); + if (resNo == 0) + { + /* + * no MAP annotation provided, just number off from 0 (begin node) + */ + resNo = nodeNo; + } + node.setResidueNumber(resNo); + } + line = input.readLine(); + } + scanner.close(); + + /* + * parse insert emissions + */ + scanner = new Scanner(line); + double[] inserts = parseDoubles(scanner, numberOfSymbols); + node.setInsertEmissions(inserts); + scanner.close(); + + /* + * parse state transitions + */ + line = input.readLine(); + scanner = new Scanner(line); + double[] transitions = parseDoubles(scanner, + NUMBER_OF_TRANSITIONS); + node.setStateTransitions(transitions); + scanner.close(); + line = input.readLine(); + + nodeNo++; + } + + hmm.setNodes(nodes); + } + + /** + * Parses the annotations on the match emission line and add them to the node. + * (See p109 of the HMMER User Guide (V3.1b2) for the specification.) Returns + * the residue position that the node maps to, if provided, else zero. + * + * @param scanner + * @param node + */ + int parseAnnotations(Scanner scanner, HMMNode node) + { + int mapTo = 0; + + /* + * map from hmm node to sequence position, if provided + */ + if (scanner.hasNext()) + { + String value = scanner.next(); + if (!"-".equals(value)) + { + try + { + mapTo = Integer.parseInt(value); + node.setResidueNumber(mapTo); + } catch (NumberFormatException e) + { + // ignore + } + } + } + + /* + * hmm consensus residue if provided, else '-' + */ + if (scanner.hasNext()) + { + node.setConsensusResidue(scanner.next().charAt(0)); + } + + /* + * RF reference annotation, if provided, else '-' + */ + if (scanner.hasNext()) + { + node.setReferenceAnnotation(scanner.next().charAt(0)); + } + + /* + * 'm' for masked position, if provided, else '-' + */ + if (scanner.hasNext()) + { + node.setMaskValue(scanner.next().charAt(0)); + } + + /* + * structure consensus symbol, if provided, else '-' + */ + if (scanner.hasNext()) + { + node.setConsensusStructure(scanner.next().charAt(0)); + } + + return mapTo; + } + + /** + * Fills an array of doubles parsed from an input line + * + * @param input + * @param numberOfElements + * @return + * @throws IOException + */ + static double[] parseDoubles(Scanner input, + int numberOfElements) throws IOException + { + double[] values = new double[numberOfElements]; + for (int i = 0; i < numberOfElements; i++) + { + if (!input.hasNext()) + { + throw new IOException("Incomplete data"); + } + String next = input.next(); + if (next.contains("*")) + { + values[i] = Double.NEGATIVE_INFINITY; + } + else + { + double prob = Double.valueOf(next); + prob = Math.pow(Math.E, -prob); + values[i] = prob; + } + } + return values; + } + + /** + * Returns a string to be added to the StringBuilder containing the entire + * output String. + * + * @param initialColumnSeparation + * The initial whitespace separation between the left side of the + * file and first character. + * @param columnSeparation + * The separation between subsequent data entries. + * @param data + * The list of data to be added to the String. + * @return + */ + String addData(int initialColumnSeparation, + int columnSeparation, List data) + { + String line = ""; + boolean first = true; + for (String value : data) + { + int sep = first ? initialColumnSeparation : columnSeparation; + line += String.format("%" + sep + "s", value); + first = false; + } + return line; + } + + /** + * Converts list of characters into a list of Strings. + * + * @param list + * @return Returns the list of Strings. + */ + List charListToStringList(List list) + { + List strList = new ArrayList<>(); + for (char value : list) + { + String strValue = Character.toString(value); + strList.add(strValue); + } + return strList; + } + + /** + * Converts an array of doubles into a list of Strings, rounded to the nearest + * 5th decimal place + * + * @param doubles + * @param noOfDecimals + * @return + */ + List doublesToStringList(double[] doubles) + { + List strList = new ArrayList<>(); + for (double value : doubles) + { + String strValue; + if (value > 0) + { + strValue = String.format("%.5f", value); + } + else if (value == -0.00000d) + { + strValue = "0.00000"; + } + else + { + strValue = "*"; + } + strList.add(strValue); + } + return strList; + } + + /** + * Appends model data in string format to the string builder + * + * @param output + */ + void appendModelAsString(StringBuilder output) + { + output.append(HMM).append(" "); + String charSymbols = hmm.getSymbols(); + for (char c : charSymbols.toCharArray()) + { + output.append(String.format("%9s", c)); + } + output.append(NL).append(TRANSITIONTYPELINE); + + int length = hmm.getLength(); + + for (int nodeNo = 0; nodeNo <= length; nodeNo++) + { + String matchLine = String.format("%7s", + nodeNo == 0 ? COMPO : Integer.toString(nodeNo)); + + double[] doubleMatches = convertToLogSpace( + hmm.getNode(nodeNo).getMatchEmissions()); + List strMatches = doublesToStringList(doubleMatches); + matchLine += addData(10, 9, strMatches); + + if (nodeNo != 0) + { + matchLine += SPACE + (hmm.getNodeMapPosition(nodeNo)); + matchLine += SPACE + hmm.getConsensusResidue(nodeNo); + matchLine += SPACE + hmm.getReferenceAnnotation(nodeNo); + if (hmm.getFileHeader().contains("HMMER3/f")) + { + matchLine += SPACE + hmm.getMaskedValue(nodeNo); + matchLine += SPACE + hmm.getConsensusStructure(nodeNo); + } + } + + output.append(NL).append(matchLine); + + String insertLine = ""; + + double[] doubleInserts = convertToLogSpace( + hmm.getNode(nodeNo).getInsertEmissions()); + List strInserts = doublesToStringList(doubleInserts); + insertLine += addData(17, 9, strInserts); + + output.append(NL).append(insertLine); + + String transitionLine = ""; + double[] doubleTransitions = convertToLogSpace( + hmm.getNode(nodeNo).getStateTransitions()); + List strTransitions = doublesToStringList( + doubleTransitions); + transitionLine += addData(17, 9, strTransitions); + + output.append(NL).append(transitionLine); + } + } + + /** + * Appends formatted HMM file properties to the string builder + * + * @param output + */ + void appendProperties(StringBuilder output) + { + output.append(hmm.getFileHeader()); + + String format = "%n%-5s %1s"; + appendProperty(output, format, NAME); + appendProperty(output, format, ACCESSION_NUMBER); + appendProperty(output, format, DESCRIPTION); + appendProperty(output, format, LENGTH); + appendProperty(output, format, MAX_LENGTH); + appendProperty(output, format, ALPHABET); + appendBooleanProperty(output, format, REFERENCE_ANNOTATION); + appendBooleanProperty(output, format, MASKED_VALUE); + appendBooleanProperty(output, format, CONSENSUS_RESIDUE); + appendBooleanProperty(output, format, CONSENSUS_STRUCTURE); + appendBooleanProperty(output, format, MAP); + appendProperty(output, format, DATE); + appendProperty(output, format, NUMBER_OF_SEQUENCES); + appendProperty(output, format, EFF_NUMBER_OF_SEQUENCES); + appendProperty(output, format, CHECK_SUM); + appendProperty(output, format, GATHERING_THRESHOLD); + appendProperty(output, format, TRUSTED_CUTOFF); + appendProperty(output, format, NOISE_CUTOFF); + + if (hmm.getMSV() != null) + { + format = "%n%-19s %18s"; + output.append(String.format(format, "STATS LOCAL MSV", hmm.getMSV())); + + output.append(String.format(format, "STATS LOCAL VITERBI", + hmm.getViterbi())); + + output.append(String.format(format, "STATS LOCAL FORWARD", + hmm.getForward())); + } + } + + /** + * Appends 'yes' or 'no' for the given property, according to whether or not + * it is set in the HMM + * + * @param output + * @param format + * @param propertyName + */ + private void appendBooleanProperty(StringBuilder output, String format, + String propertyName) + { + boolean set = hmm.getBooleanProperty(propertyName); + output.append(String.format(format, propertyName, + set ? HiddenMarkovModel.YES : HiddenMarkovModel.NO)); + } + + /** + * Appends the value of the given property to the output, if not null + * + * @param output + * @param format + * @param propertyName + */ + private void appendProperty(StringBuilder output, String format, + String propertyName) + { + String value = hmm.getProperty(propertyName); + if (value != null) + { + output.append(String.format(format, propertyName, value)); + } + } + + @Override + public String print(SequenceI[] sequences, boolean jvsuffix) + { + if (sequences[0].getHMM() != null) + { + hmm = sequences[0].getHMM(); + } + return print(); + } + + /** + * Prints the .hmm file to a String. + * + * @return + */ + public String print() + { + StringBuilder output = new StringBuilder(); + appendProperties(output); + output.append(NL); + appendModelAsString(output); + output.append(NL).append(TERMINATOR).append(NL); + return output.toString(); + } + + /** + * Converts the probabilities contained in an array into log space + * + * @param ds + */ + double[] convertToLogSpace(double[] ds) + { + double[] converted = new double[ds.length]; + for (int i = 0; i < ds.length; i++) + { + double prob = ds[i]; + double logProb = -1 * Math.log(prob); + + converted[i] = logProb; + } + return converted; + } + + /** + * Returns the HMM sequence produced by reading a .hmm file. + */ + @Override + public SequenceI[] getSeqsAsArray() + { + SequenceI hmmSeq = hmm.getConsensusSequence(); + SequenceI[] seq = new SequenceI[1]; + seq[0] = hmmSeq; + return seq; + } + + @Override + public void setNewlineString(String newLine) + { + NL = newLine; + } + + @Override + public void setExportSettings(AlignExportSettingI exportSettings) + { + + } + + @Override + public void configureForView(AlignmentViewPanel viewpanel) + { + + } + + @Override + public boolean hasWarningMessage() + { + return false; + } + + @Override + public String getWarningMessage() + { + return "warning message"; + } + +} + diff --git a/src/jalview/io/IdentifyFile.java b/src/jalview/io/IdentifyFile.java index ff959b0..ad5884c 100755 --- a/src/jalview/io/IdentifyFile.java +++ b/src/jalview/io/IdentifyFile.java @@ -150,6 +150,11 @@ public class IdentifyFile reply = FileFormat.ScoreMatrix; break; } + if (data.startsWith("HMMER3")) + { + reply = FileFormat.HMMER3; + break; + } if (data.startsWith("H ") && !aaIndexHeaderRead) { aaIndexHeaderRead = true; diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java index f5b5177..58b171d 100644 --- a/src/jalview/io/StockholmFile.java +++ b/src/jalview/io/StockholmFile.java @@ -28,6 +28,7 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; import jalview.datamodel.DBRefEntry; +import jalview.datamodel.DBRefSource; import jalview.datamodel.Mapping; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; @@ -42,10 +43,12 @@ import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Vector; import com.stevesoft.pat.Regex; @@ -76,23 +79,48 @@ public class StockholmFile extends AlignFile { private static final String ANNOTATION = "annotation"; - private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "("); + private static final char UNDERSCORE = '_'; - private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")"); + // private static final Regex OPEN_PAREN = new Regex("(<|\\[)", "("); + // private static final Regex CLOSE_PAREN = new Regex("(>|\\])", ")"); public static final Regex DETECT_BRACKETS = new Regex( "(<|>|\\[|\\]|\\(|\\)|\\{|\\})"); - StringBuffer out; // output buffer + /* + * lookup table of Stockholm 'feature' (annotation) types + * see http://sonnhammer.sbc.su.se/Stockholm.html + */ + private static Map featureTypes = null; + + static + { + featureTypes = new HashMap<>(); + featureTypes.put("SS", "Secondary Structure"); + featureTypes.put("SA", "Surface Accessibility"); + featureTypes.put("TM", "transmembrane"); + featureTypes.put("PP", "Posterior Probability"); + featureTypes.put("LI", "ligand binding"); + featureTypes.put("AS", "active site"); + featureTypes.put("IN", "intron"); + featureTypes.put("IR", "interacting residue"); + featureTypes.put("AC", "accession"); + featureTypes.put("OS", "organism"); + featureTypes.put("CL", "class"); + featureTypes.put("DE", "description"); + featureTypes.put("DR", "reference"); + featureTypes.put("LO", "look"); + featureTypes.put("RF", "Reference Positions"); + } - AlignmentI al; + private AlignmentI al; public StockholmFile() { } /** - * Creates a new StockholmFile object for output. + * Creates a new StockholmFile object for output */ public StockholmFile(AlignmentI al) { @@ -110,6 +138,47 @@ public class StockholmFile extends AlignFile super(source); } + /** + * Answers the readable description for a (case-sensitive) annotation type + * code, for example "Reference Positions" for "RF". Returns the type code if + * no description is found. + * + * @param id + * @return + */ + public static String typeToDescription(String id) + { + if (featureTypes.containsKey(id)) + { + return featureTypes.get(id); + } + System.err.println( + "Warning : Unknown Stockholm annotation type code " + id); + return id; + } + + /** + * Answers the annotation type code for a (non-case-sensitive) readable + * description, for example "RF" for "Reference Positions" (or null if not + * found) + * + * @param description + * @return + */ + public static String descriptionToType(String description) + { + for (Entry entry : featureTypes.entrySet()) + { + if (entry.getValue().equalsIgnoreCase(description)) + { + return entry.getKey(); + } + } + System.err.println( + "Warning : Unknown Stockholm annotation type: " + description); + return null; + } + @Override public void initData() { @@ -197,7 +266,7 @@ public class StockholmFile extends AlignFile String version; // String id; Hashtable seqAnn = new Hashtable(); // Sequence related annotations - LinkedHashMap seqs = new LinkedHashMap(); + LinkedHashMap seqs = new LinkedHashMap<>(); Regex p, r, rend, s, x; // Temporary line for processing RNA annotation // String RNAannot = ""; @@ -219,7 +288,7 @@ public class StockholmFile extends AlignFile // logger.debug("Stockholm version: " + version); } - // We define some Regexes here that will be used regularily later + // We define some Regexes here that will be used regularly later rend = new Regex("^\\s*\\/\\/"); // Find the end of an alignment p = new Regex("(\\S+)\\/(\\d+)\\-(\\d+)"); // split sequence id in // id/from/to @@ -232,7 +301,7 @@ public class StockholmFile extends AlignFile Regex closeparen = new Regex("(>|\\])", ")"); // Detect if file is RNA by looking for bracket types - Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))"); + // Regex detectbrackets = new Regex("(<|>|\\[|\\]|\\(|\\))"); rend.optimize(); p.optimize(); @@ -366,7 +435,7 @@ public class StockholmFile extends AlignFile Hashtable content = (Hashtable) features.remove(type); // add alignment annotation for this feature - String key = type2id(type); + String key = descriptionToType(type); /* * have we added annotation rows for this type ? @@ -624,17 +693,18 @@ public class StockholmFile extends AlignFile } Hashtable content; - if (features.containsKey(this.id2type(type))) + if (features.containsKey(StockholmFile.typeToDescription(type))) { // logger.debug("Found content for " + this.id2type(type)); - content = (Hashtable) features.get(this.id2type(type)); + content = (Hashtable) features + .get(StockholmFile.typeToDescription(type)); } else { // logger.debug("Creating new content holder for " + // this.id2type(type)); content = new Hashtable(); - features.put(this.id2type(type), content); + features.put(StockholmFile.typeToDescription(type), content); } String ns = (String) content.get(ANNOTATION); @@ -658,7 +728,7 @@ public class StockholmFile extends AlignFile strucAnn = new Hashtable(); } - Vector newStruc = new Vector(); + Vector newStruc = new Vector<>(); parseAnnotationRow(newStruc, type, ns); for (AlignmentAnnotation alan : newStruc) { @@ -710,7 +780,7 @@ public class StockholmFile extends AlignFile private void guessDatabaseFor(Sequence seqO, String dbr, String dbsource) { DBRefEntry dbrf = null; - List dbrs = new ArrayList(); + List dbrs = new ArrayList<>(); String seqdb = "Unknown", sdbac = "" + dbr; int st = -1, en = -1, p; if ((st = sdbac.indexOf("/")) > -1) @@ -809,10 +879,8 @@ public class StockholmFile extends AlignFile Vector annotation, String label, String annots) { - String convert1, convert2 = null; - - // convert1 = OPEN_PAREN.replaceAll(annots); - // convert2 = CLOSE_PAREN.replaceAll(convert1); + // String convert1 = OPEN_PAREN.replaceAll(annots); + // String convert2 = CLOSE_PAREN.replaceAll(convert1); // annots = convert2; String type = label; @@ -823,7 +891,7 @@ public class StockholmFile extends AlignFile : label; } boolean ss = false, posterior = false; - type = id2type(type); + type = typeToDescription(type); if (type.equalsIgnoreCase("secondary structure")) { ss = true; @@ -837,6 +905,10 @@ public class StockholmFile extends AlignFile for (int i = 0; i < annots.length(); i++) { String pos = annots.substring(i, i + 1); + if (UNDERSCORE == pos.charAt(0)) + { + pos = " "; + } Annotation ann; ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not // be written out @@ -918,143 +990,123 @@ public class StockholmFile extends AlignFile } @Override - public String print(SequenceI[] s, boolean jvSuffix) + public String print(final SequenceI[] sequences, boolean jvSuffix) { - out = new StringBuffer(); + StringBuilder out = new StringBuilder(); out.append("# STOCKHOLM 1.0"); out.append(newline); - // find max length of id - int max = 0; - int maxid = 0; - int in = 0; - Hashtable dataRef = null; - while ((in < s.length) && (s[in] != null)) + int maxIdWidth = 0; + for (SequenceI seq : sequences) { - String tmp = printId(s[in], jvSuffix); - max = Math.max(max, s[in].getLength()); - - if (tmp.length() > maxid) - { - maxid = tmp.length(); - } - if (s[in].getDBRefs() != null) + if (seq != null) { - for (int idb = 0; idb < s[in].getDBRefs().length; idb++) - { - if (dataRef == null) - { - dataRef = new Hashtable(); - } - - String datAs1 = s[in].getDBRefs()[idb].getSource().toString() - + " ; " - + s[in].getDBRefs()[idb].getAccessionId().toString(); - dataRef.put(tmp, datAs1); - } + String formattedId = printId(seq, jvSuffix); + maxIdWidth = Math.max(maxIdWidth, formattedId.length()); } - in++; } - maxid += 9; - int i = 0; + maxIdWidth += 9; - // output database type - if (al.getProperties() != null) + /* + * generic alignment properties + */ + Hashtable props = al.getProperties(); + if (props != null) { - if (!al.getProperties().isEmpty()) + for (Object key : props.keySet()) { - Enumeration key = al.getProperties().keys(); - Enumeration val = al.getProperties().elements(); - while (key.hasMoreElements()) - { - out.append("#=GF " + key.nextElement() + " " + val.nextElement()); - out.append(newline); - } + out.append(String.format("#=GF %s %s", key.toString(), + props.get(key).toString())); + out.append(newline); } } - // output database accessions - if (dataRef != null) + /* + * output database accessions as #=GS (per sequence annotation) + * PFAM or RFAM are output as AC + * others are output as DR ; + */ + Format formatter = new Format("%-" + (maxIdWidth - 2) + "s"); + for (SequenceI seq : sequences) { - Enumeration en = dataRef.keys(); - while (en.hasMoreElements()) + if (seq != null) { - Object idd = en.nextElement(); - String type = (String) dataRef.remove(idd); - out.append(new Format("%-" + (maxid - 2) + "s") - .form("#=GS " + idd.toString() + " ")); - if (type.contains("PFAM") || type.contains("RFAM")) - { - - out.append(" AC " + type.substring(type.indexOf(";") + 1)); - } - else + DBRefEntry[] dbRefs = seq.getDBRefs(); + if (dbRefs != null) { - out.append(" DR " + type + " "); + String idField = formatter + .form("#=GS " + printId(seq, jvSuffix) + " "); + for (DBRefEntry dbRef : dbRefs) + { + out.append(idField); + printDbRef(out, dbRef); + } } - out.append(newline); } } - // output annotations - while (i < s.length && s[i] != null) + /* + * output annotations + */ + for (SequenceI seq : sequences) { - AlignmentAnnotation[] alAnot = s[i].getAnnotation(); - if (alAnot != null) + if (seq != null) { - Annotation[] ann; - for (int j = 0; j < alAnot.length; j++) + AlignmentAnnotation[] alAnot = seq.getAnnotation(); + if (alAnot != null) { - - String key = type2id(alAnot[j].label); - boolean isrna = alAnot[j].isValidStruc(); - - if (isrna) - { - // hardwire to secondary structure if there is RNA secondary - // structure on the annotation - key = "SS"; - } - if (key == null) + for (int j = 0; j < alAnot.length; j++) { + AlignmentAnnotation ann = alAnot[j]; + String key = descriptionToType(ann.label); + boolean isrna = ann.isValidStruc(); + if (isrna) + { + /* + * output as secondary structure if there is + * RNA secondary structure on the annotation + */ + key = "SS"; + } + if (key == null) + { + continue; + } - continue; - } - - // out.append("#=GR "); - out.append(new Format("%-" + maxid + "s").form( - "#=GR " + printId(s[i], jvSuffix) + " " + key + " ")); - ann = alAnot[j].annotations; - String seq = ""; - for (int k = 0; k < ann.length; k++) - { - seq += outputCharacter(key, k, isrna, ann, s[i]); + out.append(new Format("%-" + maxIdWidth + "s").form( + "#=GR " + printId(seq, jvSuffix) + " " + key + " ")); + Annotation[] anns = ann.annotations; + StringBuilder seqString = new StringBuilder(); + for (int k = 0; k < anns.length; k++) + { + seqString + .append(getAnnotationCharacter(key, k, anns[k], seq)); + } + out.append(seqString.toString()); + out.append(newline); } - out.append(seq); - out.append(newline); } - } - out.append(new Format("%-" + maxid + "s") - .form(printId(s[i], jvSuffix) + " ")); - out.append(s[i].getSequenceAsString()); - out.append(newline); - i++; + out.append(new Format("%-" + maxIdWidth + "s") + .form(printId(seq, jvSuffix) + " ")); + out.append(seq.getSequenceAsString()); + out.append(newline); + } } - // alignment annotation - AlignmentAnnotation aa; + /* + * output alignment annotation (but not auto-calculated or sequence-related) + */ if (al.getAlignmentAnnotation() != null) { for (int ia = 0; ia < al.getAlignmentAnnotation().length; ia++) { - aa = al.getAlignmentAnnotation()[ia]; + AlignmentAnnotation aa = al.getAlignmentAnnotation()[ia]; if (aa.autoCalculated || !aa.visible || aa.sequenceRef != null) { continue; } - String seq = ""; - String label; + String label = aa.label; String key = ""; if (aa.label.equals("seq")) { @@ -1062,30 +1114,28 @@ public class StockholmFile extends AlignFile } else { - key = type2id(aa.label.toLowerCase()); - if (key == null) + key = descriptionToType(aa.label); + if ("RF".equals(key)) { - label = aa.label; + label = key; } - else + else if (key != null) { label = key + "_cons"; } } - if (label == null) - { - label = aa.label; - } label = label.replace(" ", "_"); out.append( - new Format("%-" + maxid + "s").form("#=GC " + label + " ")); - boolean isrna = aa.isValidStruc(); + new Format("%-" + maxIdWidth + "s") + .form("#=GC " + label + " ")); + StringBuilder sb = new StringBuilder(aa.annotations.length); for (int j = 0; j < aa.annotations.length; j++) { - seq += outputCharacter(key, j, isrna, aa.annotations, null); + sb.append( + getAnnotationCharacter(key, j, aa.annotations[j], null)); } - out.append(seq); + out.append(sb.toString()); out.append(newline); } } @@ -1097,20 +1147,40 @@ public class StockholmFile extends AlignFile } /** - * add an annotation character to the output row + * A helper method that appends a formatted dbref to the output buffer + * + * @param out + * @param dbRef + */ + protected void printDbRef(StringBuilder out, DBRefEntry dbRef) + { + String db = dbRef.getSource(); + String acc = dbRef.getAccessionId(); + if (DBRefSource.PFAM.equalsIgnoreCase(db) + || DBRefSource.RFAM.equalsIgnoreCase(db)) + { + out.append(" AC " + acc); + } + else + { + out.append(" DR " + db + " ; " + acc); + } + out.append(newline); + } + + /** + * Returns an annotation character to add to the output row * * @param seq * @param key * @param k - * @param isrna * @param ann * @param sequenceI */ - private char outputCharacter(String key, int k, boolean isrna, - Annotation[] ann, SequenceI sequenceI) + static char getAnnotationCharacter(String key, int k, Annotation annot, + SequenceI sequenceI) { char seq = ' '; - Annotation annot = ann[k]; String ch = (annot == null) ? ((sequenceI == null) ? "-" : Character.toString(sequenceI.getCharAt(k))) @@ -1119,8 +1189,8 @@ public class StockholmFile extends AlignFile { if (annot == null) { - // sensible gap character - return ' '; + // Stockholm format requires underscore, not space + return UNDERSCORE; } else { @@ -1147,77 +1217,6 @@ public class StockholmFile extends AlignFile return seq; } - public String print() - { - out = new StringBuffer(); - out.append("# STOCKHOLM 1.0"); - out.append(newline); - print(getSeqsAsArray(), false); - - out.append("//"); - out.append(newline); - return out.toString(); - } - - private static Hashtable typeIds = null; - - static - { - if (typeIds == null) - { - typeIds = new Hashtable(); - typeIds.put("SS", "Secondary Structure"); - typeIds.put("SA", "Surface Accessibility"); - typeIds.put("TM", "transmembrane"); - typeIds.put("PP", "Posterior Probability"); - typeIds.put("LI", "ligand binding"); - typeIds.put("AS", "active site"); - typeIds.put("IN", "intron"); - typeIds.put("IR", "interacting residue"); - typeIds.put("AC", "accession"); - typeIds.put("OS", "organism"); - typeIds.put("CL", "class"); - typeIds.put("DE", "description"); - typeIds.put("DR", "reference"); - typeIds.put("LO", "look"); - typeIds.put("RF", "Reference Positions"); - - } - } - - protected static String id2type(String id) - { - if (typeIds.containsKey(id)) - { - return (String) typeIds.get(id); - } - System.err.println( - "Warning : Unknown Stockholm annotation type code " + id); - return id; - } - - protected static String type2id(String type) - { - String key = null; - Enumeration e = typeIds.keys(); - while (e.hasMoreElements()) - { - Object ll = e.nextElement(); - if (typeIds.get(ll).toString().equalsIgnoreCase(type)) - { - key = (String) ll; - break; - } - } - if (key != null) - { - return key; - } - System.err.println( - "Warning : Unknown Stockholm annotation type: " + type); - return key; - } - /** * make a friendly ID string. * diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java index 1cf482d..8226cee 100755 --- a/src/jalview/jbgui/GAlignFrame.java +++ b/src/jalview/jbgui/GAlignFrame.java @@ -25,6 +25,8 @@ import jalview.api.SplitContainerI; import jalview.bin.Cache; import jalview.gui.JvSwingUtils; import jalview.gui.Preferences; +import jalview.hmmer.HmmerCommand; +import jalview.io.FileFormatException; import jalview.io.FileFormats; import jalview.util.MessageManager; import jalview.util.Platform; @@ -40,6 +42,7 @@ import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -67,6 +70,28 @@ public class GAlignFrame extends JInternalFrame protected JMenu webService = new JMenu(); + protected JMenu hmmerMenu = new JMenu(); + + protected JMenu hmmAlign = new JMenu(); + + protected JMenuItem hmmAlignRun = new JMenuItem(); + + protected JMenuItem hmmAlignSettings = new JMenuItem(); + + protected JMenu hmmSearch = new JMenu(); + + protected JMenuItem hmmSearchRun = new JMenuItem(); + + protected JMenuItem hmmSearchSettings = new JMenuItem(); + + protected JMenuItem addDatabase = new JMenuItem(); + + protected JMenu hmmBuild = new JMenu(); + + protected JMenuItem hmmBuildRun = new JMenuItem(); + + protected JMenuItem hmmBuildSettings = new JMenuItem(); + protected JMenuItem webServiceNoServices; protected JCheckBoxMenuItem viewBoxesMenuItem = new JCheckBoxMenuItem(); @@ -195,13 +220,19 @@ public class GAlignFrame extends JInternalFrame protected JCheckBoxMenuItem normaliseSequenceLogo = new JCheckBoxMenuItem(); + protected JCheckBoxMenuItem showInformationHistogram = new JCheckBoxMenuItem(); + + protected JCheckBoxMenuItem showHMMSequenceLogo = new JCheckBoxMenuItem(); + + protected JCheckBoxMenuItem normaliseHMMSequenceLogo = new JCheckBoxMenuItem(); + protected JCheckBoxMenuItem applyAutoAnnotationSettings = new JCheckBoxMenuItem(); private SequenceAnnotationOrder annotationSortOrder; private boolean showAutoCalculatedAbove = false; - private Map accelerators = new HashMap(); + private Map accelerators = new HashMap<>(); private SplitContainerI splitFrame; @@ -249,7 +280,8 @@ public class GAlignFrame extends JInternalFrame private void jbInit() throws Exception { initColourMenu(); - + initHMMERMenu(); + JMenuItem saveAs = new JMenuItem( MessageManager.getString("action.save_as")); ActionListener al = new ActionListener() @@ -260,14 +292,14 @@ public class GAlignFrame extends JInternalFrame saveAs_actionPerformed(e); } }; - + // FIXME getDefaultToolkit throws an exception in Headless mode KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | KeyEvent.SHIFT_MASK, false); addMenuActionAndAccelerator(keyStroke, saveAs, al); - + closeMenuItem.setText(MessageManager.getString("action.close")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); @@ -280,7 +312,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, closeMenuItem, al); - + JMenu editMenu = new JMenu(MessageManager.getString("action.edit")); JMenu viewMenu = new JMenu(MessageManager.getString("action.view")); JMenu annotationsMenu = new JMenu( @@ -290,6 +322,20 @@ public class GAlignFrame extends JInternalFrame JMenu calculateMenu = new JMenu( MessageManager.getString("action.calculate")); webService.setText(MessageManager.getString("action.web_service")); + hmmerMenu.setText(MessageManager.getString("action.hmmer")); + hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable()); + hmmerMenu.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmerMenu_actionPerformed(e); + } + }); + hmmerMenu.add(hmmBuild); + hmmerMenu.add(hmmAlign); + hmmerMenu.add(hmmSearch); + JMenuItem selectAllSequenceMenuItem = new JMenuItem( MessageManager.getString("action.select_all")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A, @@ -303,7 +349,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, selectAllSequenceMenuItem, al); - + JMenuItem deselectAllSequenceMenuItem = new JMenuItem( MessageManager.getString("action.deselect_all")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false); @@ -316,7 +362,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, deselectAllSequenceMenuItem, al); - + JMenuItem invertSequenceMenuItem = new JMenuItem( MessageManager.getString("action.invert_sequence_selection")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I, @@ -330,7 +376,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, invertSequenceMenuItem, al); - + JMenuItem grpsFromSelection = new JMenuItem( MessageManager.getString("action.make_groups_selection")); grpsFromSelection.addActionListener(new ActionListener() @@ -366,7 +412,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, remove2LeftMenuItem, al); - + JMenuItem remove2RightMenuItem = new JMenuItem( MessageManager.getString("action.remove_right")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, @@ -380,7 +426,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, remove2RightMenuItem, al); - + JMenuItem removeGappedColumnMenuItem = new JMenuItem( MessageManager.getString("action.remove_empty_columns")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, @@ -394,7 +440,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, removeGappedColumnMenuItem, al); - + JMenuItem removeAllGapsMenuItem = new JMenuItem( MessageManager.getString("action.remove_all_gaps")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E, @@ -410,7 +456,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, removeAllGapsMenuItem, al); - + JMenuItem justifyLeftMenuItem = new JMenuItem( MessageManager.getString("action.left_justify_alignment")); justifyLeftMenuItem.addActionListener(new ActionListener() @@ -502,7 +548,7 @@ public class GAlignFrame extends JInternalFrame sortGroupMenuItem_actionPerformed(e); } }); - + JMenuItem removeRedundancyMenuItem = new JMenuItem( MessageManager.getString("action.remove_redundancy")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D, @@ -516,7 +562,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, removeRedundancyMenuItem, al); - + JMenuItem pairwiseAlignmentMenuItem = new JMenuItem( MessageManager.getString("action.pairwise_alignment")); pairwiseAlignmentMenuItem.addActionListener(new ActionListener() @@ -527,16 +573,18 @@ public class GAlignFrame extends JInternalFrame pairwiseAlignmentMenuItem_actionPerformed(e); } }); - + this.getContentPane().setLayout(new BorderLayout()); alignFrameMenuBar.setFont(new java.awt.Font("Verdana", 0, 11)); statusBar.setBackground(Color.white); statusBar.setFont(new java.awt.Font("Verdana", 0, 11)); statusBar.setBorder(BorderFactory.createLineBorder(Color.black)); statusBar.setText(MessageManager.getString("label.status_bar")); + outputTextboxMenu .setText(MessageManager.getString("label.out_to_textbox")); + annotationPanelMenuItem.setActionCommand(""); annotationPanelMenuItem .setText(MessageManager.getString("label.show_annotations")); @@ -604,6 +652,7 @@ public class GAlignFrame extends JInternalFrame final JCheckBoxMenuItem sortAnnByLabel = new JCheckBoxMenuItem( MessageManager.getString("label.sort_annotations_by_label")); + sortAnnBySequence.setSelected( sortAnnotationsBy == SequenceAnnotationOrder.SEQUENCE_AND_LABEL); sortAnnBySequence.addActionListener(new ActionListener() @@ -644,7 +693,7 @@ public class GAlignFrame extends JInternalFrame colourTextMenuItem_actionPerformed(e); } }); - + JMenuItem htmlMenuItem = new JMenuItem( MessageManager.getString("label.html")); htmlMenuItem.addActionListener(new ActionListener() @@ -655,7 +704,7 @@ public class GAlignFrame extends JInternalFrame htmlMenuItem_actionPerformed(e); } }); - + JMenuItem createBioJS = new JMenuItem( MessageManager.getString("label.biojs_html_export")); createBioJS.addActionListener(new java.awt.event.ActionListener() @@ -666,7 +715,7 @@ public class GAlignFrame extends JInternalFrame bioJSMenuItem_actionPerformed(e); } }); - + JMenuItem overviewMenuItem = new JMenuItem( MessageManager.getString("label.overview_window")); overviewMenuItem.addActionListener(new ActionListener() @@ -677,7 +726,7 @@ public class GAlignFrame extends JInternalFrame overviewMenuItem_actionPerformed(e); } }); - + undoMenuItem.setEnabled(false); undoMenuItem.setText(MessageManager.getString("action.undo")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z, @@ -691,7 +740,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, undoMenuItem, al); - + redoMenuItem.setEnabled(false); redoMenuItem.setText(MessageManager.getString("action.redo")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y, @@ -705,7 +754,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, redoMenuItem, al); - + wrapMenuItem.setText(MessageManager.getString("label.wrap")); wrapMenuItem.addActionListener(new ActionListener() { @@ -715,7 +764,7 @@ public class GAlignFrame extends JInternalFrame wrapMenuItem_actionPerformed(e); } }); - + JMenuItem printMenuItem = new JMenuItem( MessageManager.getString("action.print")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P, @@ -729,7 +778,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, printMenuItem, al); - + renderGapsMenuItem .setText(MessageManager.getString("action.show_gaps")); renderGapsMenuItem.setState(true); @@ -741,7 +790,7 @@ public class GAlignFrame extends JInternalFrame renderGapsMenuItem_actionPerformed(e); } }); - + JMenuItem findMenuItem = new JMenuItem( MessageManager.getString("action.find")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F, @@ -760,6 +809,7 @@ public class GAlignFrame extends JInternalFrame showSeqFeatures.setText( MessageManager.getString("label.show_sequence_features")); + showSeqFeatures.addActionListener(new ActionListener() { @Override @@ -778,86 +828,86 @@ public class GAlignFrame extends JInternalFrame .setText(MessageManager.getString("label.show_database_refs")); showDbRefsMenuitem.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showDbRefs_actionPerformed(e); } - + }); showNpFeatsMenuitem.setText( MessageManager.getString("label.show_non_positional_features")); showNpFeatsMenuitem.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showNpFeats_actionPerformed(e); } - + }); showGroupConservation .setText(MessageManager.getString("label.group_conservation")); showGroupConservation.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showGroupConservation_actionPerformed(e); } - + }); showGroupConsensus .setText(MessageManager.getString("label.group_consensus")); showGroupConsensus.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showGroupConsensus_actionPerformed(e); } - + }); showConsensusHistogram.setText( MessageManager.getString("label.show_consensus_histogram")); showConsensusHistogram.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showConsensusHistogram_actionPerformed(e); } - + }); showSequenceLogo .setText(MessageManager.getString("label.show_consensus_logo")); showSequenceLogo.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { showSequenceLogo_actionPerformed(e); } - + }); normaliseSequenceLogo .setText(MessageManager.getString("label.norm_consensus_logo")); normaliseSequenceLogo.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { normaliseSequenceLogo_actionPerformed(e); } - + }); applyAutoAnnotationSettings .setText(MessageManager.getString("label.apply_all_groups")); @@ -871,7 +921,7 @@ public class GAlignFrame extends JInternalFrame applyAutoAnnotationSettings_actionPerformed(e); } }); - + ButtonGroup buttonGroup = new ButtonGroup(); final JRadioButtonMenuItem showAutoFirst = new JRadioButtonMenuItem( MessageManager.getString("label.show_first")); @@ -902,7 +952,7 @@ public class GAlignFrame extends JInternalFrame sortAnnotations_actionPerformed(); } }); - + JMenuItem deleteGroups = new JMenuItem( MessageManager.getString("action.undefine_groups")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U, @@ -916,7 +966,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, deleteGroups, al); - + JMenuItem annotationColumn = new JMenuItem( MessageManager.getString("action.select_by_annotation")); annotationColumn.addActionListener(new ActionListener() @@ -927,7 +977,7 @@ public class GAlignFrame extends JInternalFrame annotationColumn_actionPerformed(e); } }); - + JMenuItem createGroup = new JMenuItem( MessageManager.getString("action.create_group")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, @@ -941,7 +991,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, createGroup, al); - + JMenuItem unGroup = new JMenuItem( MessageManager.getString("action.remove_group")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, @@ -957,7 +1007,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, unGroup, al); - + copy.setText(MessageManager.getString("action.copy")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); @@ -971,7 +1021,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, copy, al); - + cut.setText(MessageManager.getString("action.cut")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); @@ -984,7 +1034,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, cut, al); - + JMenuItem delete = new JMenuItem( MessageManager.getString("action.delete")); delete.addActionListener(new ActionListener() @@ -995,7 +1045,7 @@ public class GAlignFrame extends JInternalFrame delete_actionPerformed(e); } }); - + pasteMenu.setText(MessageManager.getString("action.paste")); JMenuItem pasteNew = new JMenuItem( MessageManager.getString("label.to_new_alignment")); @@ -1008,11 +1058,18 @@ public class GAlignFrame extends JInternalFrame @Override public void actionPerformed(ActionEvent e) { - pasteNew_actionPerformed(e); + try + { + pasteNew_actionPerformed(e); + } catch (IOException | InterruptedException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } } }; addMenuActionAndAccelerator(keyStroke, pasteNew, al); - + JMenuItem pasteThis = new JMenuItem( MessageManager.getString("label.to_this_alignment")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, @@ -1022,11 +1079,18 @@ public class GAlignFrame extends JInternalFrame @Override public void actionPerformed(ActionEvent e) { - pasteThis_actionPerformed(e); + try + { + pasteThis_actionPerformed(e); + } catch (IOException | InterruptedException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } } }; addMenuActionAndAccelerator(keyStroke, pasteThis, al); - + JMenuItem createPNG = new JMenuItem("PNG"); createPNG.addActionListener(new ActionListener() { @@ -1038,7 +1102,6 @@ public class GAlignFrame extends JInternalFrame }); createPNG.setActionCommand( MessageManager.getString("label.save_png_image")); - JMenuItem font = new JMenuItem(MessageManager.getString("action.font")); font.addActionListener(new ActionListener() { @@ -1068,7 +1131,7 @@ public class GAlignFrame extends JInternalFrame createEPS(null); } }); - + JMenuItem createSVG = new JMenuItem("SVG"); createSVG.addActionListener(new ActionListener() { @@ -1078,7 +1141,7 @@ public class GAlignFrame extends JInternalFrame createSVG(null); } }); - + JMenuItem loadTreeMenuItem = new JMenuItem( MessageManager.getString("label.load_associated_tree")); loadTreeMenuItem.setActionCommand( @@ -1091,7 +1154,7 @@ public class GAlignFrame extends JInternalFrame loadTreeMenuItem_actionPerformed(e); } }); - + scaleAbove.setVisible(false); scaleAbove.setText(MessageManager.getString("action.scale_above")); scaleAbove.addActionListener(new ActionListener() @@ -1142,15 +1205,15 @@ public class GAlignFrame extends JInternalFrame .setText(MessageManager.getString("label.automatic_scrolling")); followHighlightMenuItem.addActionListener(new ActionListener() { - + @Override public void actionPerformed(ActionEvent e) { followHighlight_actionPerformed(); } - + }); - + sortByTreeMenu .setText(MessageManager.getString("action.by_tree_order")); sort.setText(MessageManager.getString("action.sort")); @@ -1161,12 +1224,12 @@ public class GAlignFrame extends JInternalFrame { buildTreeSortMenu(); } - + @Override public void menuDeselected(MenuEvent e) { } - + @Override public void menuCanceled(MenuEvent e) { @@ -1177,17 +1240,17 @@ public class GAlignFrame extends JInternalFrame sort.add(sortByAnnotScore); sort.addMenuListener(new javax.swing.event.MenuListener() { - + @Override public void menuCanceled(MenuEvent e) { } - + @Override public void menuDeselected(MenuEvent e) { } - + @Override public void menuSelected(MenuEvent e) { @@ -1250,7 +1313,7 @@ public class GAlignFrame extends JInternalFrame showReverse_actionPerformed(true); } }); - + JMenuItem extractScores = new JMenuItem( MessageManager.getString("label.extract_scores")); extractScores.addActionListener(new ActionListener() @@ -1263,10 +1326,10 @@ public class GAlignFrame extends JInternalFrame }); extractScores.setVisible(true); // JBPNote: TODO: make gui for regex based score extraction - + // for show products actions see AlignFrame.canShowProducts showProducts.setText(MessageManager.getString("label.get_cross_refs")); - + runGroovy.setText(MessageManager.getString("label.run_groovy")); runGroovy.setToolTipText( MessageManager.getString("label.run_groovy_tip")); @@ -1278,7 +1341,7 @@ public class GAlignFrame extends JInternalFrame runGroovy_actionPerformed(); } }); - + JMenuItem openFeatureSettings = new JMenuItem( MessageManager.getString("action.feature_settings")); openFeatureSettings.addActionListener(new ActionListener() @@ -1299,7 +1362,7 @@ public class GAlignFrame extends JInternalFrame fetchSequence_actionPerformed(e); } }); - + JMenuItem associatedData = new JMenuItem( MessageManager.getString("label.load_features_annotations")); associatedData.addActionListener(new ActionListener() @@ -1307,7 +1370,14 @@ public class GAlignFrame extends JInternalFrame @Override public void actionPerformed(ActionEvent e) { - associatedData_actionPerformed(e); + try + { + associatedData_actionPerformed(e); + } catch (IOException | InterruptedException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } } }); loadVcf = new JMenuItem(MessageManager.getString("label.load_vcf_file")); @@ -1361,7 +1431,7 @@ public class GAlignFrame extends JInternalFrame listenToViewSelections_actionPerformed(e); } }); - + JMenu addSequenceMenu = new JMenu( MessageManager.getString("label.add_sequences")); JMenuItem addFromFile = new JMenuItem( @@ -1507,7 +1577,7 @@ public class GAlignFrame extends JInternalFrame hiddenMarkers_actionPerformed(e); } }); - + JMenuItem invertColSel = new JMenuItem( MessageManager.getString("action.invert_column_selection")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I, @@ -1523,7 +1593,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, invertColSel, al); - + showComplementMenuItem.setVisible(false); showComplementMenuItem.addActionListener(new ActionListener() { @@ -1533,7 +1603,7 @@ public class GAlignFrame extends JInternalFrame showComplement_actionPerformed(showComplementMenuItem.getState()); } }); - + tabbedPane.addChangeListener(new javax.swing.event.ChangeListener() { @Override @@ -1554,7 +1624,7 @@ public class GAlignFrame extends JInternalFrame tabbedPane_mousePressed(e); } } - + @Override public void mouseReleased(MouseEvent e) { @@ -1572,7 +1642,7 @@ public class GAlignFrame extends JInternalFrame tabbedPane_focusGained(e); } }); - + JMenuItem save = new JMenuItem(MessageManager.getString("action.save")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false); @@ -1585,7 +1655,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, save, al); - + reload.setEnabled(false); reload.setText(MessageManager.getString("action.reload")); reload.addActionListener(new ActionListener() @@ -1596,7 +1666,7 @@ public class GAlignFrame extends JInternalFrame reload_actionPerformed(e); } }); - + JMenuItem newView = new JMenuItem( MessageManager.getString("action.new_view")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T, @@ -1610,11 +1680,11 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, newView, al); - + tabbedPane.setToolTipText("" + MessageManager.getString("label.rename_tab_eXpand_reGroup") + ""); - + formatMenu.setText(MessageManager.getString("action.format")); JMenu selectMenu = new JMenu(MessageManager.getString("action.select")); @@ -1628,7 +1698,7 @@ public class GAlignFrame extends JInternalFrame idRightAlign_actionPerformed(e); } }); - + gatherViews.setEnabled(false); gatherViews.setText(MessageManager.getString("action.gather_views")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false); @@ -1641,7 +1711,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, gatherViews, al); - + expandViews.setEnabled(false); expandViews.setText(MessageManager.getString("action.expand_views")); keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false); @@ -1654,7 +1724,7 @@ public class GAlignFrame extends JInternalFrame } }; addMenuActionAndAccelerator(keyStroke, expandViews, al); - + JMenuItem pageSetup = new JMenuItem( MessageManager.getString("action.page_setup")); pageSetup.addActionListener(new ActionListener() @@ -1687,12 +1757,87 @@ public class GAlignFrame extends JInternalFrame selectHighlightedColumns_actionPerformed(actionEvent); } }; + hmmBuildRun.setText(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmbuild")); + hmmBuildRun.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmBuild_actionPerformed(true); + } + }); + hmmBuildSettings.setText( + MessageManager.getString("label.edit_settings_and_run")); + hmmBuildSettings.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmBuild_actionPerformed(false); + } + }); + hmmAlignRun.setText(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmalign")); + hmmAlignRun.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmAlign_actionPerformed(true); + } + }); + hmmAlignSettings.setText( + MessageManager.getString("label.edit_settings_and_run")); + hmmAlignSettings.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmAlign_actionPerformed(false); + } + }); + hmmSearchRun.setText(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmsearch")); + hmmSearchRun.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmSearch_actionPerformed(true); + } + }); + hmmSearchSettings.setText( + MessageManager.getString("label.edit_settings_and_run")); + hmmSearchSettings.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + hmmSearch_actionPerformed(false); + } + }); + addDatabase.setText(MessageManager.getString("label.add_database")); + addDatabase.addActionListener(new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + try + { + addDatabase_actionPerformed(); + } catch (IOException e1) + { + e1.printStackTrace(); + } + } + }); selectHighlighted.addActionListener(al); JMenu tooltipSettingsMenu = new JMenu( MessageManager.getString("label.sequence_id_tooltip")); JMenu autoAnnMenu = new JMenu( MessageManager.getString("label.autocalculated_annotation")); - + JMenu exportImageMenu = new JMenu( MessageManager.getString("label.export_image")); JMenu fileMenu = new JMenu(MessageManager.getString("action.file")); @@ -1705,7 +1850,8 @@ public class GAlignFrame extends JInternalFrame alignFrameMenuBar.add(colourMenu); alignFrameMenuBar.add(calculateMenu); alignFrameMenuBar.add(webService); - + alignFrameMenuBar.add(hmmerMenu); + fileMenu.add(fetchSequence); fileMenu.add(addSequenceMenu); fileMenu.add(reload); @@ -1725,7 +1871,7 @@ public class GAlignFrame extends JInternalFrame fileMenu.add(loadVcf); fileMenu.addSeparator(); fileMenu.add(closeMenuItem); - + pasteMenu.add(pasteNew); pasteMenu.add(pasteThis); editMenu.add(undoMenuItem); @@ -1747,7 +1893,7 @@ public class GAlignFrame extends JInternalFrame // editMenu.add(justifyRightMenuItem); // editMenu.addSeparator(); editMenu.add(padGapsMenuitem); - + showMenu.add(showAllColumns); showMenu.add(showAllSeqs); showMenu.add(showAllhidden); @@ -1775,7 +1921,7 @@ public class GAlignFrame extends JInternalFrame viewMenu.add(alignmentProperties); viewMenu.addSeparator(); viewMenu.add(overviewMenuItem); - + annotationsMenu.add(annotationPanelMenuItem); annotationsMenu.addSeparator(); annotationsMenu.add(showAllAlAnnotations); @@ -1819,7 +1965,7 @@ public class GAlignFrame extends JInternalFrame calculateMenu.add(extractScores); calculateMenu.addSeparator(); calculateMenu.add(runGroovy); - + webServiceNoServices = new JMenuItem( MessageManager.getString("label.no_services")); webService.add(webServiceNoServices); @@ -1834,7 +1980,7 @@ public class GAlignFrame extends JInternalFrame this.getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH); statusPanel.add(statusBar, null); this.getContentPane().add(tabbedPane, java.awt.BorderLayout.CENTER); - + formatMenu.add(font); formatMenu.addSeparator(); formatMenu.add(wrapMenuItem); @@ -1868,6 +2014,42 @@ public class GAlignFrame extends JInternalFrame // selectMenu.add(listenToViewSelections); } + public void hmmerMenu_actionPerformed(ActionEvent e) + { + + } + + /** + * Constructs the entries on the HMMER menu (does not add them to the menu). + */ + protected void initHMMERMenu() + { + hmmAlign = new JMenu(MessageManager.getString("label.hmmalign")); + hmmAlignSettings = new JMenuItem( + MessageManager.getString("label.edit_settings_and_run")); + hmmAlignRun = new JMenuItem(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmalign")); + hmmAlign.add(hmmAlignSettings); + hmmAlign.add(hmmAlignRun); + hmmBuild = new JMenu(MessageManager.getString("label.hmmbuild")); + hmmBuildSettings = new JMenuItem( + MessageManager.getString("label.edit_settings_and_run")); + hmmBuildRun = new JMenuItem(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmbuild")); + hmmBuild.add(hmmBuildSettings); + hmmBuild.add(hmmBuildRun); + hmmSearch = new JMenu(MessageManager.getString("label.hmmsearch")); + hmmSearchSettings = new JMenuItem( + MessageManager.getString("label.edit_settings_and_run")); + hmmSearchRun = new JMenuItem(MessageManager.formatMessage( + "label.action_with_default_settings", "hmmsearch")); + addDatabase = new JMenuItem( + MessageManager.getString("label.add_database")); + hmmSearch.add(hmmSearchSettings); + hmmSearch.add(hmmSearchRun); + hmmSearch.add(addDatabase); + } + protected void loadVcf_actionPerformed() { } @@ -2343,10 +2525,12 @@ public class GAlignFrame extends JInternalFrame } protected void pasteNew_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { } protected void pasteThis_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { } @@ -2354,6 +2538,23 @@ public class GAlignFrame extends JInternalFrame { } + protected void hmmBuild_actionPerformed(boolean withDefaults) + { + } + + protected void hmmSearch_actionPerformed(boolean withDefaults) + { + } + + protected void addDatabase_actionPerformed() + throws FileFormatException, IOException + { + } + + protected void hmmAlign_actionPerformed(boolean withDefaults) + { + } + public void createPNG(java.io.File f) { } @@ -2469,6 +2670,7 @@ public class GAlignFrame extends JInternalFrame } public void associatedData_actionPerformed(ActionEvent e) + throws IOException, InterruptedException { } diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java index 1ca0802..358298d 100755 --- a/src/jalview/jbgui/GPreferences.java +++ b/src/jalview/jbgui/GPreferences.java @@ -40,11 +40,11 @@ import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import javax.swing.AbstractButton; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; @@ -142,10 +142,15 @@ public class GPreferences extends JPanel protected JCheckBox showConsensLogo = new JCheckBox(); + protected JCheckBox showInformationHistogram = new JCheckBox(); + + protected JCheckBox showHMMLogo = new JCheckBox(); + protected JCheckBox showDbRefTooltip = new JCheckBox(); protected JCheckBox showNpTooltip = new JCheckBox(); + /* * Structure tab and components */ @@ -265,6 +270,21 @@ public class GPreferences extends JPanel protected JCheckBox sortByTree = new JCheckBox(); /* + * hmmer tab and components + */ + protected JPanel hmmerTab = new JPanel(); + + protected JCheckBox hmmrTrimTermini = new JCheckBox(); + + protected AbstractButton hmmerBackgroundUniprot = new JCheckBox(); + + protected AbstractButton hmmerBackgroundAlignment = new JCheckBox(); + + protected JTextField hmmerSequenceCount = new JTextField(); + + protected JTextField hmmerPath = new JTextField(); + + /* * DAS Settings tab */ protected JPanel dasTab = new JPanel(); @@ -274,6 +294,8 @@ public class GPreferences extends JPanel */ protected JPanel wsTab = new JPanel(); + + /** * Creates a new GPreferences object. */ @@ -325,6 +347,8 @@ public class GPreferences extends JPanel tabbedPane.add(initEditingTab(), MessageManager.getString("label.editing")); + tabbedPane.add(initHMMERTab(), MessageManager.getString("label.hmmer")); + /* * See DasSourceBrowser for the real work of configuring this tab. */ @@ -339,7 +363,7 @@ public class GPreferences extends JPanel /* * Handler to validate a tab before leaving it - currently only for - * Structure. + * Structure */ tabbedPane.addChangeListener(new ChangeListener() { @@ -393,6 +417,83 @@ public class GPreferences extends JPanel } /** + * Initialises the hmmer tabbed panel + * + * @return + */ + private JPanel initHMMERTab() + { + hmmerTab.setLayout(null); + + JLabel installationLocation = new JLabel( + MessageManager.getString("label.hmmer_location")); + installationLocation.setFont(LABEL_FONT); + installationLocation.setBounds(new Rectangle(22, 10, 250, 23)); + hmmerPath.setBounds(new Rectangle(22, 30, 300, 23)); + hmmerPath.addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (e.getClickCount() == 2) + { + String chosen = openFileChooser(true); + if (chosen != null) + { + hmmerPath.setText(chosen); + } + } + } + }); + + JLabel hmmalign = new JLabel( + MessageManager.getString("label.hmmalign_label")); + hmmalign.setFont(LABEL_FONT); + hmmalign.setBounds(new Rectangle(22, 50, 200, 23)); + + hmmrTrimTermini.setFont(LABEL_FONT); + hmmrTrimTermini.setText(MessageManager.getString("label.trim_termini")); + hmmrTrimTermini.setBounds(new Rectangle(22, 70, 200, 23)); + + JLabel hmmsearch = new JLabel( + MessageManager.getString("label.hmmsearch_label")); + hmmsearch.setFont(LABEL_FONT); + hmmsearch.setBounds(new Rectangle(22, 90, 200, 23)); + + JLabel sequencesToKeep = new JLabel( + MessageManager.getString("label.no_of_sequences")); + sequencesToKeep.setFont(LABEL_FONT); + sequencesToKeep.setBounds(new Rectangle(22, 110, 125, 23)); + hmmerSequenceCount.setBounds(new Rectangle(150, 110, 40, 23)); + + ButtonGroup backgroundFreqSource = new ButtonGroup(); + backgroundFreqSource.add(hmmerBackgroundUniprot); + backgroundFreqSource.add(hmmerBackgroundAlignment); + backgroundFreqSource.setSelected(hmmerBackgroundUniprot.getModel(), true); + + hmmerBackgroundUniprot.setText(MessageManager.getString("label.freq_uniprot")); + hmmerBackgroundUniprot.setFont(LABEL_FONT); + hmmerBackgroundUniprot.setBounds(new Rectangle(22, 130, 255, 23)); + + hmmerBackgroundAlignment.setText(MessageManager.getString("label.freq_alignment")); + hmmerBackgroundAlignment.setFont(LABEL_FONT); + hmmerBackgroundAlignment.setBounds(new Rectangle(22, 150, 300, 23)); + + hmmerTab.add(hmmerBackgroundUniprot); + hmmerTab.add(hmmerBackgroundAlignment); + hmmerTab.add(hmmalign); + hmmerTab.add(hmmsearch); + hmmerTab.add(installationLocation); + hmmerTab.add(hmmerPath); + hmmerTab.add(hmmrTrimTermini); + hmmerTab.add(sequencesToKeep); + hmmerTab.add(sequencesToKeep); + hmmerTab.add(hmmerSequenceCount); + + return hmmerTab; + } + + /** * Initialises the Output tabbed panel. * * @return @@ -1222,7 +1323,7 @@ public class GPreferences extends JPanel { if (e.getClickCount() == 2) { - String chosen = openFileChooser(); + String chosen = openFileChooser(false); if (chosen != null) { chimeraPath.setText(chosen); @@ -1277,10 +1378,14 @@ public class GPreferences extends JPanel * * @return */ - protected String openFileChooser() + protected String openFileChooser(boolean forFolder) { String choice = null; JFileChooser chooser = new JFileChooser(); + if (forFolder) + { + chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } // chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle( @@ -1296,22 +1401,12 @@ public class GPreferences extends JPanel return choice; } - /** - * Validate the structure tab preferences; if invalid, set focus on this tab. - * - * @param e - */ - protected boolean validateStructure(FocusEvent e) + protected boolean validateStructure() { - if (!validateStructure()) - { - e.getComponent().requestFocusInWindow(); - return false; - } - return true; + return false; } - protected boolean validateStructure() + protected boolean validateHMMERPath(boolean showWarning) { return false; } @@ -1819,4 +1914,9 @@ public class GPreferences extends JPanel } } + + public void hmmerPath_actionPerformed(ActionEvent e) + { + + } } diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java index 8a80d41..b2e569e 100644 --- a/src/jalview/renderer/AnnotationRenderer.java +++ b/src/jalview/renderer/AnnotationRenderer.java @@ -29,12 +29,14 @@ import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; +import jalview.datamodel.HiddenMarkovModel; import jalview.datamodel.ProfilesI; import jalview.schemes.ColourSchemeI; import jalview.schemes.NucleotideColourScheme; import jalview.schemes.ResidueProperties; import jalview.schemes.ZappoColourScheme; import jalview.util.Platform; +import jalview.workers.InformationThread; import java.awt.BasicStroke; import java.awt.Color; @@ -70,8 +72,14 @@ public class AnnotationRenderer private final boolean MAC = Platform.isAMac(); - boolean av_renderHistogram = true, av_renderProfile = true, - av_normaliseProfile = false; + // todo remove these flags, read from group/viewport where needed + boolean av_renderHistogram = true; + + boolean av_renderProfile = true; + + boolean av_normaliseProfile = false; + + boolean av_infoHeight = false; ResidueShaderI profcolour = null; @@ -87,6 +95,8 @@ public class AnnotationRenderer private boolean av_ignoreGapsConsensus; + private boolean av_ignoreBelowBackground; + /** * attributes set from AwtRenderPanelI */ @@ -163,7 +173,7 @@ public class AnnotationRenderer { g.setColor(STEM_COLOUR); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -230,7 +240,7 @@ public class AnnotationRenderer g.setColor(nonCanColor); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -341,12 +351,16 @@ public class AnnotationRenderer } columnSelection = av.getColumnSelection(); hiddenColumns = av.getAlignment().getHiddenColumns(); - hconsensus = av.getSequenceConsensusHash(); + hconsensus = av.getConsensusProfiles(); complementConsensus = av.getComplementConsensusHash(); hStrucConsensus = av.getRnaStructureConsensusHash(); av_ignoreGapsConsensus = av.isIgnoreGapsConsensus(); + av_ignoreBelowBackground = av.isIgnoreBelowBackground(); + av_infoHeight = av.isInfoLetterHeight(); } + + /** * Returns profile data; the first element is the profile type, the second is * the number of distinct values, the third the total count, and the remainder @@ -362,17 +376,25 @@ public class AnnotationRenderer // properties/rendering attributes as a global 'alignment group' which holds // all vis settings for the alignment as a whole rather than a subset // - if (aa.autoCalculated && (aa.label.startsWith("Consensus") - || aa.label.startsWith("cDNA Consensus"))) + if (InformationThread.HMM_CALC_ID.equals(aa.getCalcId())) + { + HiddenMarkovModel hmm = aa.sequenceRef.getHMM(); + return AAFrequency.extractHMMProfile(hmm, column, + av_ignoreBelowBackground, av_infoHeight); // TODO check if this follows standard + // pipeline + } + if (aa.autoCalculated + && (aa.label.startsWith("Consensus") || aa.label + .startsWith("cDNA Consensus"))) { boolean forComplement = aa.label.startsWith("cDNA Consensus"); - if (aa.groupRef != null && aa.groupRef.consensusData != null + if (aa.groupRef != null && aa.groupRef.getConsensusData() != null && aa.groupRef.isShowSequenceLogo()) { // TODO? group consensus for cDNA complement return AAFrequency.extractProfile( - aa.groupRef.consensusData.get(column), - aa.groupRef.getIgnoreGapsConsensus()); + aa.groupRef.getConsensusData().get(column), + aa.groupRef.isIgnoreGapsConsensus()); } // TODO extend annotation row to enable dynamic and static profile data to // be stored @@ -505,6 +527,21 @@ public class AnnotationRenderer renderProfile = av_renderProfile; normaliseProfile = av_normaliseProfile; } + else if (InformationThread.HMM_CALC_ID.equals(row.getCalcId())) + { + if (row.groupRef != null) + { + renderHistogram = row.groupRef.isShowInformationHistogram(); + renderProfile = row.groupRef.isShowHMMSequenceLogo(); + normaliseProfile = row.groupRef.isNormaliseHMMSequenceLogo(); + } + else + { + renderHistogram = av.isShowInformationHistogram(); + renderProfile = av.isShowHMMSequenceLogo(); + normaliseProfile = av.isNormaliseHMMSequenceLogo(); + } + } else { renderHistogram = true; @@ -602,7 +639,7 @@ public class AnnotationRenderer { if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(startRes + x); + column = hiddenColumns.visibleToAbsoluteColumn(startRes + x); if (column > row_annotations.length - 1) { break; @@ -1150,7 +1187,7 @@ public class AnnotationRenderer g.setColor(HELIX_COLOUR); int sCol = (lastSSX / charWidth) - + hiddenColumns.adjustForHiddenColumns(startRes); + + hiddenColumns.visibleToAbsoluteColumn(startRes); int x1 = lastSSX; int x2 = (x * charWidth); @@ -1250,7 +1287,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) @@ -1330,7 +1367,7 @@ public class AnnotationRenderer column = sRes + x; if (hasHiddenColumns) { - column = hiddenColumns.adjustForHiddenColumns(column); + column = hiddenColumns.visibleToAbsoluteColumn(column); } if (column > aaMax) diff --git a/src/jalview/renderer/ResidueShaderI.java b/src/jalview/renderer/ResidueShaderI.java index 4d97171..7e67598 100644 --- a/src/jalview/renderer/ResidueShaderI.java +++ b/src/jalview/renderer/ResidueShaderI.java @@ -5,16 +5,16 @@ * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License + * modify it under the terms of the GNU General License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. + * PURPOSE. See the GNU General License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU General License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ @@ -32,16 +32,15 @@ import java.util.Map; public interface ResidueShaderI { + void setConsensus(ProfilesI cons); - public abstract void setConsensus(ProfilesI cons); + boolean conservationApplied(); - public abstract boolean conservationApplied(); + void setConservationApplied(boolean conservationApplied); - public abstract void setConservationApplied(boolean conservationApplied); + void setConservation(Conservation cons); - public abstract void setConservation(Conservation cons); - - public abstract void alignmentChanged(AnnotatedCollectionI alignment, + void alignmentChanged(AnnotatedCollectionI alignment, Map hiddenReps); /** @@ -51,19 +50,19 @@ public interface ResidueShaderI * @param consensusThreshold * @param ignoreGaps */ - public abstract void setThreshold(int consensusThreshold, + void setThreshold(int consensusThreshold, boolean ignoreGaps); - public abstract void setConservationInc(int i); + void setConservationInc(int i); - public abstract int getConservationInc(); + int getConservationInc(); /** * Get the percentage threshold for this colour scheme * * @return Returns the percentage threshold */ - public abstract int getThreshold(); + int getThreshold(); /** * Returns the possibly context dependent colour for the given symbol at the @@ -75,11 +74,11 @@ public interface ResidueShaderI * @param seq * @return */ - public abstract Color findColour(char symbol, int position, + Color findColour(char symbol, int position, SequenceI seq); - public abstract ColourSchemeI getColourScheme(); + ColourSchemeI getColourScheme(); - public abstract void setColourScheme(ColourSchemeI cs); + void setColourScheme(ColourSchemeI cs); } \ No newline at end of file diff --git a/src/jalview/renderer/ScaleRenderer.java b/src/jalview/renderer/ScaleRenderer.java index d92608c..dc3272f 100644 --- a/src/jalview/renderer/ScaleRenderer.java +++ b/src/jalview/renderer/ScaleRenderer.java @@ -21,9 +21,11 @@ package jalview.renderer; import jalview.api.AlignViewportI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceI; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; /** @@ -60,27 +62,19 @@ public class ScaleRenderer column = col; text = txt; } - - /** - * String representation for inspection when debugging only - */ - @Override - public String toString() - { - return String.format("%s:%d:%s", major ? "major" : "minor", column, - text); - } } /** - * Calculates position markers on the alignment ruler + * calculate positions markers on the alignment ruler * * @param av * @param startx - * left-most column in visible view (0..) + * left-most column in visible view * @param endx - * - right-most column in visible view (0..) - * @return + * - right-most column in visible view + * @return List of ScaleMark holding boolean: true/false for major/minor mark, + * marker position in alignment column coords, a String to be rendered + * at the position (or null) */ public List calculateMarks(AlignViewportI av, int startx, int endx) @@ -88,17 +82,27 @@ public class ScaleRenderer int scalestartx = (startx / 10) * 10; SequenceI refSeq = av.getAlignment().getSeqrep(); - int refSp = 0, refStartI = 0, refEndI = -1; + int refSp = 0; + int refStartI = 0; + int refEndI = -1; + + HiddenColumns hc = av.getAlignment().getHiddenColumns(); + if (refSeq != null) { - // find bounds and set origin appopriately - // locate first visible position for this sequence - int[] refbounds = av.getAlignment().getHiddenColumns() - .locateVisibleBoundsOfSequence(refSeq); + // find bounds and set origin appropriately + // locate first residue in sequence which is not hidden + Iterator it = hc.iterator(); + int index = refSeq.firstResidueOutsideIterator(it); + refSp = hc.absoluteToVisibleColumn(index); + + refStartI = refSeq.findIndex(refSeq.getStart()) - 1; + + int seqlength = refSeq.getLength(); + // get sequence position past the end of the sequence + int pastEndPos = refSeq.findPosition(seqlength + 1); + refEndI = refSeq.findIndex(pastEndPos - 1) - 1; - refSp = refbounds[0]; - refStartI = refbounds[4]; - refEndI = refbounds[5]; scalestartx = refSp + ((scalestartx - refSp) / 10) * 10; } @@ -106,41 +110,40 @@ public class ScaleRenderer { scalestartx += 5; } - List marks = new ArrayList(); + List marks = new ArrayList<>(); + String string; + int refN, iadj; // todo: add a 'reference origin column' to set column number relative to for (int i = scalestartx; i <= endx; i += 5) { if (((i - refSp) % 10) == 0) { - String text; if (refSeq == null) { - int iadj = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(i - 1) + 1; - text = String.valueOf(iadj); + iadj = hc.visibleToAbsoluteColumn(i - 1) + 1; + string = String.valueOf(iadj); } else { - int iadj = av.getAlignment().getHiddenColumns() - .adjustForHiddenColumns(i - 1); - int refN = refSeq.findPosition(iadj); + iadj = hc.visibleToAbsoluteColumn(i - 1); + refN = refSeq.findPosition(iadj); // TODO show bounds if position is a gap // - ie L--R -> "1L|2R" for // marker if (iadj < refStartI) { - text = String.valueOf(iadj - refStartI); + string = String.valueOf(iadj - refStartI); } else if (iadj > refEndI) { - text = "+" + String.valueOf(iadj - refEndI); + string = "+" + String.valueOf(iadj - refEndI); } else { - text = String.valueOf(refN) + refSeq.getCharAt(iadj); + string = String.valueOf(refN) + refSeq.getCharAt(iadj); } } - marks.add(new ScaleMark(true, i - startx - 1, text)); + marks.add(new ScaleMark(true, i - startx - 1, string)); } else { diff --git a/src/jalview/schemes/HmmerColourScheme.java b/src/jalview/schemes/HmmerColourScheme.java new file mode 100644 index 0000000..9ea468d --- /dev/null +++ b/src/jalview/schemes/HmmerColourScheme.java @@ -0,0 +1,196 @@ +package jalview.schemes; + +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceCollectionI; +import jalview.datamodel.SequenceI; +import jalview.util.ColorUtils; +import jalview.util.Comparison; + +import java.awt.Color; +import java.util.Map; + +/** + * Base class for colour schemes based on a selected Hidden Markov Model. The + * colour is with reference to an HMM consensus sequence and HMM profile + *

      + *
    • white for a gap
    • + *
    • red for an insertion (position is gapped in the HMM consensus)
    • + *
    • orange for negative information content
    • + *
    • white to blue for increasing information content
    • + *
    + * where information content is the log ratio + * + *
    + *   log(profile match emission probability / residue background probability)
    + * 
    + * + * Sub-class implementations use either global ('Uniprot') or local + * ('alignment') background frequencies. + * + * @author tzvanaalten + * @author gmcarstairs + */ +public abstract class HmmerColourScheme extends ResidueColourScheme +{ + private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish + + /* + * the aligned HMM consensus sequence to use as reference for colouring + */ + private SequenceI hmmSeq; + + private HiddenMarkovModel hmm; + + private Map frequencies; + + /** + * Constructor given a Hidden Markov Model consensus sequence. This provides + * the HMM profile from which we can read the emission probabilities that + * determine the colour. + * + * @param consensusSeq + */ + public HmmerColourScheme(SequenceI consensusSeq) + { + hmmSeq = consensusSeq; + hmm = hmmSeq == null ? null : hmmSeq.getHMM(); + } + + /** + * Default constructor (required by ColourSchemes.loadColourSchemes) + */ + public HmmerColourScheme() + { + } + + @Override + public Color findColour(char symbol, int column, SequenceI seq, + String consensusResidue, float pid) + { + return findColour(symbol, column); + } + + /** + * Returns the colour at a particular symbol at a column in the alignment: + *
      + *
    • white for a gap
    • + *
    • red for an insertion
    • + *
    • orange for negative information content
    • + *
    • white to blue for increasing information content
    • + *
    + * + * @param symbol + * @param column + * @return + */ + private Color findColour(char symbol, int column) + { + if (getHmm() == null || Comparison.isGap(symbol)) + { + return Color.white; + } + if (Comparison.isGap(hmmSeq.getCharAt(column))) + { + return INSERTION_COLOUR; + } + if (Character.isLowerCase(symbol)) + { + symbol = Character.toUpperCase(symbol); + } + + final double prob = getHmm().getMatchEmissionProbability(column, + symbol); + + Float freq = 0f; + + if (!frequencies.containsKey(symbol)) + { + return Color.WHITE; + } + else + { + freq = frequencies.get(symbol); + } + + /* + * Orange if match emission probability is less than background probability + */ + double infoRatio = prob / freq.floatValue(); + Color colour = Color.ORANGE; + if (infoRatio >= 1) + { + /* + * log-scale graduated shade of blue if prob is greater than background + */ + float infoLog = (float) Math.log(infoRatio); + colour = ColorUtils.getGraduatedColour(infoLog, 0, Color.WHITE, + getMaxInformationScore(), Color.blue); + } + + return colour; + } + + /** + * Answers the maximum possible value of information score (log ratio), for + * use in scaling a graduated colour range + * + * @return + */ + abstract float getMaxInformationScore(); + + /** + * Answers a new colour scheme instance based on the HMM of the first sequence + * in ac that has an HMM + */ + @Override + public ColourSchemeI getInstance(AnnotatedCollectionI ac, + Map hiddenRepSequences) + { + return newInstance(ac); + } + + /** + * Answers a new instance of the colour scheme for the given HMM + * + * @param ac + * @return + */ + protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac); + + @Override + public boolean isSimple() + { + return false; + } + + /** + * Answers true if the sequence collection has an HMM consensus sequence, else + * false + */ + @Override + public boolean isApplicableTo(AnnotatedCollectionI ac) + { + return ac.getHmmConsensus() != null; + } + + protected Map getFrequencies() + { + return frequencies; + } + + protected void setFrequencies(Map frequencies) + { + this.frequencies = frequencies; + } + + protected HiddenMarkovModel getHmm() + { + return hmm; + } + + protected SequenceI getHmmSequence() + { + return hmmSeq; + } +} diff --git a/src/jalview/schemes/HmmerGlobalBackground.java b/src/jalview/schemes/HmmerGlobalBackground.java new file mode 100644 index 0000000..d5508f1 --- /dev/null +++ b/src/jalview/schemes/HmmerGlobalBackground.java @@ -0,0 +1,60 @@ +package jalview.schemes; + +import jalview.datamodel.AnnotatedCollectionI; + +/** + * An HMM colour scheme that uses global ('Uniprot') background frequencies for + * residues + * + * @author tzvanaalten + */ +public class HmmerGlobalBackground extends HmmerColourScheme +{ + /* + * The highest possible log ratio is when match emission probability in + * the HMM model is 1, and background (for W) is 0.0109 giving + * log(1/0.0109) = log(91.743) = 4.519 + */ + private static final float MAX_LOG_RATIO = 4.519f; + + /** + * Constructor given a Hidden Markov Model + * + * @param markov + */ + public HmmerGlobalBackground(AnnotatedCollectionI ac) + { + super(ac.getHmmConsensus()); + String alphabetType = getHmm() == null + ? ResidueProperties.ALPHABET_AMINO + : getHmm().getAlphabetType(); + setFrequencies( + ResidueProperties.backgroundFrequencies.get(alphabetType)); + } + + /** + * Default constructor (required by ColourSchemes.loadColourSchemes) + */ + public HmmerGlobalBackground() + { + } + + @Override + public String getSchemeName() + { + return JalviewColourScheme.HMMERU.toString(); + } + + @Override + protected HmmerColourScheme newInstance(AnnotatedCollectionI ac) + { + return new HmmerGlobalBackground(ac); + } + + @Override + float getMaxInformationScore() + { + return MAX_LOG_RATIO; + } + +} diff --git a/src/jalview/schemes/HmmerLocalBackground.java b/src/jalview/schemes/HmmerLocalBackground.java new file mode 100644 index 0000000..d7a5e65 --- /dev/null +++ b/src/jalview/schemes/HmmerLocalBackground.java @@ -0,0 +1,97 @@ +package jalview.schemes; + +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.ResidueCount; +import jalview.datamodel.SequenceI; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An HMM colour scheme that uses local (alignment or sub-group) background + * frequencies for residues + * + * @author tzvanaalten + */ +public class HmmerLocalBackground extends HmmerColourScheme +{ + float logTotalCount; + + /** + * Constructor given a Hidden Markov Model + * + * @param sg + * + * @param markov + */ + public HmmerLocalBackground(AnnotatedCollectionI ac) + { + super(ac.getHmmConsensus()); + countFrequencies(ac); + } + + /** + * Default constructor (required by ColourSchemes.loadColourSchemes) + */ + public HmmerLocalBackground() + { + } + + @Override + public String getSchemeName() + { + return JalviewColourScheme.HMMERA.toString(); + } + + /** + * Counts and stores the relative frequency of every residue in the alignment + * (apart from any HMM consensus sequences) + * + * @param sg + */ + public void countFrequencies(AnnotatedCollectionI sg) + { + // TODO or total counts in Consensus Profile (how do we get at it?)? + Map freqs = new HashMap<>(); + + /* + * count symbols, excluding any HMM consensus sequences + */ + ResidueCount counts = new ResidueCount(); + List seqs = sg.getSequences(); + for (SequenceI seq : seqs) + { + if (!seq.isHMMConsensusSequence()) + { + for (char c : seq.getSequence()) + { + counts.add(c); + } + } + } + int total = counts.getTotalResidueCount(); // excludes gaps + + for (char symbol : counts.getSymbolCounts().symbols) + { + double freq = counts.getCount(symbol) / (double) total; + freqs.put(symbol, (float) freq); + } + + setFrequencies(freqs); + + logTotalCount = (float) Math.log(total); + } + + @Override + float getMaxInformationScore() + { + return logTotalCount; + } + + @Override + protected HmmerColourScheme newInstance(AnnotatedCollectionI ac) + { + return new HmmerLocalBackground(ac); + } +} diff --git a/src/jalview/schemes/JalviewColourScheme.java b/src/jalview/schemes/JalviewColourScheme.java index e1fc02d..357ea03 100644 --- a/src/jalview/schemes/JalviewColourScheme.java +++ b/src/jalview/schemes/JalviewColourScheme.java @@ -42,7 +42,9 @@ public enum JalviewColourScheme Nucleotide("Nucleotide", NucleotideColourScheme.class), PurinePyrimidine("Purine/Pyrimidine", PurinePyrimidineColourScheme.class), RNAHelices("RNA Helices", RNAHelicesColour.class), - TCoffee("T-Coffee Scores", TCoffeeColourScheme.class); + TCoffee("T-Coffee Scores", TCoffeeColourScheme.class), + HMMERU("HMMER-Uniprot", HmmerGlobalBackground.class), + HMMERA("HMMER-Alignment", HmmerLocalBackground.class); // RNAInteraction("RNA Interaction type", RNAInteractionColourScheme.class) private String name; diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java index a4e6480..9b0489e 100755 --- a/src/jalview/schemes/ResidueProperties.java +++ b/src/jalview/schemes/ResidueProperties.java @@ -32,6 +32,13 @@ import java.util.Vector; public class ResidueProperties { + // alphabet names used in Hidden Markov Model files + public static final String ALPHABET_RNA = "RNA"; + + public static final String ALPHABET_DNA = "DNA"; + + public static final String ALPHABET_AMINO = "amino"; + // Stores residue codes/names and colours and other things public static final int[] aaIndex; // aaHash version 2.1.1 and below @@ -48,6 +55,9 @@ public class ResidueProperties // lookup from modified amino acid (e.g. MSE) to canonical form (e.g. MET) public static final Map modifications = new HashMap<>(); + // residue background frequencies across different alphabets + public static final Map> backgroundFrequencies = new HashMap<>(); + static { aaIndex = new int[255]; @@ -2517,6 +2527,58 @@ public class ResidueProperties } + static + { + Map amino = new HashMap<>(); + amino.put('A', 0.0826f); + amino.put('Q', 0.0393f); + amino.put('L', 0.0965f); + amino.put('S', 0.0661f); + amino.put('R', 0.0553f); + amino.put('E', 0.0674f); + amino.put('K', 0.0582f); + amino.put('T', 0.0535f); + amino.put('N', 0.0406f); + amino.put('G', 0.0708f); + amino.put('M', 0.0241f); + amino.put('W', 0.0109f); + amino.put('D', 0.0546f); + amino.put('H', 0.0227f); + amino.put('F', 0.0386f); + amino.put('Y', 0.0292f); + amino.put('C', 0.0137f); + amino.put('I', 0.0593f); + amino.put('P', 0.0472f); + amino.put('V', 0.0686f); + backgroundFrequencies.put(ALPHABET_AMINO, amino); + // todo: these don't match https://www.ebi.ac.uk/uniprot/TrEMBLstats - what + // are they? + } + + // TODO get correct frequencies + + static + { + Map dna = new HashMap<>(); + dna.put('A', 0.25f); + dna.put('C', 0.25f); + dna.put('T', 0.25f); + dna.put('G', 0.25f); + backgroundFrequencies.put(ALPHABET_DNA, dna); + + } + + static + { + Map rna = new HashMap<>(); + rna.put('A', 0.25f); + rna.put('C', 0.25f); + rna.put('T', 0.25f); + rna.put('G', 0.25f); + backgroundFrequencies.put(ALPHABET_RNA, rna); + + } + public static String getCanonicalAminoAcid(String aA) { String canonical = modifications.get(aA); diff --git a/src/jalview/structure/StructureMapping.java b/src/jalview/structure/StructureMapping.java index 40789ed..fcf322d 100644 --- a/src/jalview/structure/StructureMapping.java +++ b/src/jalview/structure/StructureMapping.java @@ -21,6 +21,7 @@ package jalview.structure; import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.Mapping; import jalview.datamodel.SequenceI; import java.util.ArrayList; @@ -39,7 +40,7 @@ public class StructureMapping String pdbchain; - public static final int UNASSIGNED_VALUE = -1; + public static final int UNASSIGNED_VALUE = Integer.MIN_VALUE; private static final int PDB_RES_NUM_INDEX = 0; @@ -49,6 +50,7 @@ public class StructureMapping // and atomNo HashMap mapping; + jalview.datamodel.Mapping seqToPdbMapping = null; /** * Constructor * @@ -73,6 +75,14 @@ public class StructureMapping this.mappingDetails = mappingDetails; } + public StructureMapping(SequenceI seq, String pdbFile2, String pdbId2, + String chain, HashMap mapping2, + String mappingOutput, Mapping seqToPdbMapping) + { + this(seq, pdbFile2, pdbId2, chain, mapping2, mappingOutput); + this.seqToPdbMapping = seqToPdbMapping; + } + public SequenceI getSequence() { return sequence; @@ -109,7 +119,8 @@ public class StructureMapping /** * * @param seqpos - * @return 0 or the corresponding residue number for the sequence position + * @return UNASSIGNED_VALUE or the corresponding residue number for the + * sequence position */ public int getPDBResNum(int seqpos) { @@ -247,4 +258,9 @@ public class StructureMapping { return mapping; } + + public Mapping getSeqToPdbMapping() + { + return seqToPdbMapping; + } } diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index 35e2536..10fe836 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -74,8 +74,6 @@ public class StructureSelectionManager private boolean addTempFacAnnot = false; - private SiftsClient siftsClient = null; - /* * Set of any registered mappings between (dataset) sequences. */ @@ -328,22 +326,20 @@ public class StructureSelectionManager } /** - * create sequence structure mappings between each sequence and the given - * pdbFile (retrieved via the given protocol). + * Import a single structure file and register sequence structure mappings for + * broadcasting colouring, mouseovers and selection events (convenience + * wrapper). * * @param forStructureView * when true, record the mapping for use in mouseOvers - * - * @param sequenceArray + * @param sequence * - one or more sequences to be mapped to pdbFile - * @param targetChainIds + * @param targetChains * - optional chain specification for mapping each sequence to pdb - * (may be nill, individual elements may be nill) - JBPNote: JAL-2693 - * - this should be List>, empty lists indicate no - * predefined mappings + * (may be nill, individual elements may be nill) * @param pdbFile * - structure data resource - * @param sourceType + * @param protocol * - how to resolve data from resource * @return null or the structure data parsed as a pdb file */ @@ -355,46 +351,51 @@ public class StructureSelectionManager pdbFile, sourceType, null); } + /** + * create sequence structure mappings between each sequence and the given + * pdbFile (retrieved via the given protocol). Either constructs a mapping + * using NW alignment or derives one from any available SIFTS mapping data. + * + * @param forStructureView + * when true, record the mapping for use in mouseOvers + * + * @param sequenceArray + * - one or more sequences to be mapped to pdbFile + * @param targetChainIds + * - optional chain specification for mapping each sequence to pdb + * (may be nill, individual elements may be nill) - JBPNote: JAL-2693 + * - this should be List>, empty lists indicate no + * predefined mappings + * @param pdbFile + * - structure data resource + * @param sourceType + * - how to resolve data from resource + * @param IProgressIndicator + * reference to UI component that maintains a progress bar for the + * mapping operation + * @return null or the structure data parsed as a pdb file + */ synchronized public StructureFile computeMapping( boolean forStructureView, SequenceI[] sequenceArray, String[] targetChainIds, String pdbFile, DataSourceType sourceType, IProgressIndicator progress) { long progressSessionId = System.currentTimeMillis() * 3; - /* - * There will be better ways of doing this in the future, for now we'll use - * the tried and tested MCview pdb mapping + + /** + * do we extract and transfer annotation from 3D data ? */ - boolean parseSecStr = processSecondaryStructure; - if (isPDBFileRegistered(pdbFile)) - { - for (SequenceI sq : sequenceArray) - { - SequenceI ds = sq; - while (ds.getDatasetSequence() != null) - { - ds = ds.getDatasetSequence(); - } - ; - if (ds.getAnnotation() != null) - { - for (AlignmentAnnotation ala : ds.getAnnotation()) - { - // false if any annotation present from this structure - // JBPNote this fails for jmol/chimera view because the *file* is - // passed, not the structure data ID - - if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile))) - { - parseSecStr = false; - } - } - } - } - } + // FIXME: possibly should just delete + + boolean parseSecStr = processSecondaryStructure + ? isStructureFileProcessed(pdbFile, sequenceArray) + : false; + StructureFile pdb = null; boolean isMapUsingSIFTs = SiftsSettings.isMapWithSifts(); try { + // FIXME if sourceType is not null, we've lost data here sourceType = AppletFormatAdapter.checkProtocol(pdbFile); pdb = new JmolParser(pdbFile, sourceType); @@ -411,7 +412,10 @@ public class StructureSelectionManager ex.printStackTrace(); return null; } - + /* + * sifts client - non null if SIFTS mappings are to be used + */ + SiftsClient siftsClient = null; try { if (isMapUsingSIFTs) @@ -422,6 +426,7 @@ public class StructureSelectionManager { isMapUsingSIFTs = false; e.printStackTrace(); + siftsClient = null; } String targetChainId; @@ -524,12 +529,12 @@ public class StructureSelectionManager try { siftsMapping = getStructureMapping(seq, pdbFile, targetChainId, - pdb, maxChain, sqmpping, maxAlignseq); + pdb, maxChain, sqmpping, maxAlignseq, siftsClient); seqToStrucMapping.add(siftsMapping); - maxChain.makeExactMapping(maxAlignseq, seq); - maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this + maxChain.makeExactMapping(siftsMapping, seq); + maxChain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this // "IEA:SIFTS" ? - maxChain.transferResidueAnnotation(siftsMapping, sqmpping); + maxChain.transferResidueAnnotation(siftsMapping, null); ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); } catch (SiftsException e) @@ -540,7 +545,8 @@ public class StructureSelectionManager targetChainId, maxChain, pdb, maxAlignseq); seqToStrucMapping.add(nwMapping); maxChain.makeExactMapping(maxAlignseq, seq); - maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this + maxChain.transferRESNUMFeatures(seq, "IEA:Jalview"); // FIXME: is + // this // "IEA:Jalview" ? maxChain.transferResidueAnnotation(nwMapping, sqmpping); ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); @@ -551,11 +557,17 @@ public class StructureSelectionManager List foundSiftsMappings = new ArrayList<>(); for (PDBChain chain : pdb.getChains()) { + StructureMapping siftsMapping = null; try { - StructureMapping siftsMapping = getStructureMapping(seq, - pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq); + siftsMapping = getStructureMapping(seq, + pdbFile, chain.id, pdb, chain, sqmpping, maxAlignseq, + siftsClient); foundSiftsMappings.add(siftsMapping); + chain.makeExactMapping(siftsMapping, seq); + chain.transferRESNUMFeatures(seq, "IEA: SIFTS");// FIXME: is this + // "IEA:SIFTS" ? + chain.transferResidueAnnotation(siftsMapping, null); } catch (SiftsException e) { System.err.println(e.getMessage()); @@ -564,11 +576,6 @@ public class StructureSelectionManager if (!foundSiftsMappings.isEmpty()) { seqToStrucMapping.addAll(foundSiftsMappings); - maxChain.makeExactMapping(maxAlignseq, seq); - maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this - // "IEA:SIFTS" ? - maxChain.transferResidueAnnotation(foundSiftsMappings.get(0), - sqmpping); ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0)); } else @@ -608,6 +615,46 @@ public class StructureSelectionManager return pdb; } + /** + * check if we need to extract secondary structure from given pdbFile and + * transfer to sequences + * + * @param pdbFile + * @param sequenceArray + * @return + */ + private boolean isStructureFileProcessed(String pdbFile, + SequenceI[] sequenceArray) + { + boolean parseSecStr = true; + if (isPDBFileRegistered(pdbFile)) + { + for (SequenceI sq : sequenceArray) + { + SequenceI ds = sq; + while (ds.getDatasetSequence() != null) + { + ds = ds.getDatasetSequence(); + } + ; + if (ds.getAnnotation() != null) + { + for (AlignmentAnnotation ala : ds.getAnnotation()) + { + // false if any annotation present from this structure + // JBPNote this fails for jmol/chimera view because the *file* is + // passed, not the structure data ID - + if (PDBfile.isCalcIdForFile(ala, findIdForPDBFile(pdbFile))) + { + parseSecStr = false; + } + } + } + } + } + return parseSecStr; + } + public void addStructureMapping(StructureMapping sm) { mappings.add(sm); @@ -624,13 +671,15 @@ public class StructureSelectionManager * @param maxChain * @param sqmpping * @param maxAlignseq + * @param siftsClient + * client for retrieval of SIFTS mappings for this structure * @return * @throws SiftsException */ private StructureMapping getStructureMapping(SequenceI seq, String pdbFile, String targetChainId, StructureFile pdb, PDBChain maxChain, jalview.datamodel.Mapping sqmpping, - AlignSeq maxAlignseq) throws SiftsException + AlignSeq maxAlignseq, SiftsClient siftsClient) throws SiftsException { StructureMapping curChainMapping = siftsClient .getSiftsStructureMapping(seq, pdbFile, targetChainId); @@ -639,7 +688,7 @@ public class StructureSelectionManager PDBChain chain = pdb.findChain(targetChainId); if (chain != null) { - chain.transferResidueAnnotation(curChainMapping, sqmpping); + chain.transferResidueAnnotation(curChainMapping, null); } } catch (Exception e) { diff --git a/src/jalview/util/HMMProbabilityDistributionAnalyser.java b/src/jalview/util/HMMProbabilityDistributionAnalyser.java new file mode 100644 index 0000000..66ae552 --- /dev/null +++ b/src/jalview/util/HMMProbabilityDistributionAnalyser.java @@ -0,0 +1,978 @@ +package jalview.util; + +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; +import jalview.io.StockholmFile; +import jalview.schemes.ResidueProperties; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Scanner; +import java.util.Vector; + +/** + * Processes probability data. The file indexes used in this program represent + * the index of the location of a family or hmm in their respective files, + * starting from 0. + * + * @author TZVanaalten + * + */ +public class HMMProbabilityDistributionAnalyser +{ + AlignmentAnnotation reference = null; + + Vector sequences; + + HiddenMarkovModel hmm; + + // contains the raw data produced + List> raw = new ArrayList<>(); + + // contains binned data + Map binned = new HashMap<>(); + + // location of the family file + String families = "/media/sf_Shared_Folder/PFAM/Family/SeedFamilies.seed"; + + // location of the file containing the family-clan links + final static String FAMILIESTOCLAN = "/media/sf_Shared_Folder/PFAM/Family/Clanlinks.dat"; + + // location of the HMM file + String hmms = "/media/sf_Shared_Folder/PFAM/HMMs/Pfam-A.hmm"; + + // suffix for raw file + final static String RAW = "/Raw.csv"; + + // suffix for binned file + final static String BINNED = "/Binned.csv"; + + // normalisation scale + final static double SCALE = 1; + + // current position in file + int currentFilePosition = 0; + + final static String NL = "\n"; + + Random generator = new Random(); + + // current directory + String currentFolder; + + boolean keepRaw = false; + + /** + * Sets the working directory. + * + * @param path + */ + public void setFolder(String path) + { + currentFolder = path; + } + + /** + * Moves a buffered reader forward in the file by a certain amount of entries. + * Each entry in the file is delimited by '//'. + * + * @param index + * The index of the location in the file. + * @param br + * @throws IOException + */ + public void moveLocationBy(int index, BufferedReader br) + throws IOException + { + for (int i = 0; i < index; i++) + { + String line = br.readLine(); + while (!"//".equals(line)) + { + line = br.readLine(); + + } + } + + } + + /** + * Analyses a specified number of families and then saves the data. Before + * analysing the data, the previous saved data will be imported and after + * analysing this, the data is exported back into the file. The file must be + * in flat file format. + * + * @param increments + * The number of families to read before saving. + * @throws IOException + */ + public void run(int increments, boolean keepRawData) throws IOException + { + keepRaw = keepRawData; + try + { + readPreviousData(currentFolder); + BufferedReader posReader = new BufferedReader( + new FileReader(currentFolder + "/CurrentPosition.txt")); + + String line = posReader.readLine(); + posReader.close(); + currentFilePosition = Integer.parseInt(line); + } catch (Exception e) + { + System.out.println("No previous data found"); + } + + + + BufferedReader inputSTO = new BufferedReader(new FileReader(families)); + BufferedReader inputHMM = new BufferedReader(new FileReader(hmms)); + + + + moveLocationBy(currentFilePosition, inputHMM); + moveLocationBy(currentFilePosition, inputSTO); + + int filesRead = 0; + int i = 0; + while (filesRead < increments) + { + + readStockholm(inputSTO); + + readHMM(inputHMM); + + int count = countValidResidues(); + processData(count); + filesRead++; + + currentFilePosition++; + System.out.println(i); + i++; + } + + PrintWriter p = new PrintWriter( + new File(currentFolder + "/CurrentPosition.txt")); + p.print(currentFilePosition); + p.close(); + exportData(currentFolder); + raw.clear(); + binned.clear(); + + } + + /** + * Analyses all families and then saves the data. Before analysing the data, + * the previous saved data will be imported and after analysing this, the data + * is exported back into the file. The file must be in flat file format. + * + * @param increments + * The number of families to read before saving. + * @throws IOException + */ + public void runToEnd(int minCount, int maxCount, boolean keepRawData, + boolean forClans) + throws IOException + { + keepRaw = keepRawData; + BufferedReader inputSTO = null; + BufferedReader inputHMM = null; + int size = 0; + int files = 1; + try + { + if (forClans) + { + files = 603; + } + int filesRead = 0; + for (int clan = 0; clan < files; clan++) + { + System.out.println(clan); + String clanPath = ""; + int numberOfFamilies = 0; + if (forClans) + { + clanPath = currentFolder + "/Clan" + clan; + if (!new File(clanPath).exists()) + { + continue; + } + BufferedReader famCountReader = new BufferedReader( + new FileReader(clanPath + "/NumberOfFamilies.txt")); + numberOfFamilies = Integer.parseInt(famCountReader.readLine()); + } + else + { + numberOfFamilies = 1; + } + + for (int fam = 0; fam < numberOfFamilies; fam++) + { + if (forClans) + { + families = clanPath + "/Families/Fam" + fam + ".sto"; + hmms = clanPath + "/HMMs/HMM" + fam + ".hmm"; + } + + inputSTO = new BufferedReader(new FileReader(families)); + inputHMM = new BufferedReader(new FileReader(hmms)); + + + int i = 0; + boolean endReached = atEnd(inputSTO); + while (!endReached) + { + readStockholm(inputSTO); + readHMM(inputHMM); + + int count = countValidResidues(); + if (count >= minCount && count < maxCount) + { + processData(count); + } + filesRead++; + System.out.println(filesRead); + endReached = atEnd(inputSTO); + } + } + } + } catch (Exception e) + { + e.printStackTrace(); + } finally + { + exportData(currentFolder); + raw.clear(); + binned.clear(); + } + } + + /** + * Reads the previous data from both files + * + * @param source + * @throws IOException + */ + public void readPreviousData(String source) throws IOException + { + readBinned(source); + if (keepRaw) + { + readRaw(source); + } + } + + /** + * Reads the previous data from the binned file. + * + * @param source + * @throws IOException + */ + public void readBinned(String source) throws IOException + { + BufferedReader input = new BufferedReader( + new FileReader(source + BINNED)); + String line = input.readLine(); + binned = new HashMap<>(); + while (!("".equals(line) || line == null)) + { + Scanner scanner = new Scanner(line); + scanner.useDelimiter(","); + String key = scanner.next(); + String value = scanner.next(); + binned.put(key, Double.valueOf(value)); + scanner.close(); + line = input.readLine(); + } + + input.close(); + } + + /** + * Reads the previous data from the raw file. + * + * @param source + * @throws IOException + */ + public void readRaw(String source) throws IOException + { + BufferedReader input = new BufferedReader(new FileReader(source + RAW)); + String line = input.readLine(); + if (line == null) + { + input.close(); + return; + } + Scanner numberScanner = new Scanner(line); + numberScanner.useDelimiter(","); + raw = new ArrayList<>(); + while (numberScanner.hasNext()) + { + numberScanner.next(); + raw.add(new ArrayList()); + } + numberScanner.close(); + + line = input.readLine(); + while (!("".equals(line) || line == null)) + { + Scanner scanner = new Scanner(line); + scanner.useDelimiter(","); + + int i = 0; + while (scanner.hasNext()) + { + String value; + value = scanner.next(); + if (!value.equals("EMPTY")) + { + raw.get(i).add(Double.parseDouble(value)); + } + else + { + raw.get(i).add(null); + } + + i++; + } + scanner.close(); + line = input.readLine(); + } + + input.close(); + } + + /** + * Counts the number of valid residues in the sequence. + * + * @return + */ + public int countValidResidues() + { + int count = 0; + + for (int width = 0; width < sequences.size(); width++) + { + for (int length = 1; length < hmm.getLength() + 1; length++) + { + char symbol; + int alignPos; + alignPos = hmm.getNodeMapPosition(length); + + symbol = sequences.get(width).getCharAt(alignPos); + if (ResidueProperties.backgroundFrequencies.get("amino") + .containsKey(symbol)) + { + count++; + } + } + } + + return count; + } + + /** + * Processes data, and stores it in both a raw and binned format. + * + * @param count + */ + public void processData(int count) + { + int rawPos = 0; + if (keepRaw) + { + raw.add(new ArrayList()); + rawPos = raw.size() - 1; + } + Double total = 0d; + for (int width = 0; width < sequences.size(); width++) + { + for (int length = 1; length < hmm.getLength() + 1; length++) + { + char symbol; + int alignPos; + alignPos = hmm.getNodeMapPosition(length); + + symbol = sequences.get(width).getCharAt(alignPos); + if (ResidueProperties.backgroundFrequencies.get("amino") + .containsKey(symbol)) + { + Double prob; + Float bfreq; + Double llr; + prob = hmm.getMatchEmissionProbability(alignPos, symbol); + bfreq = ResidueProperties.backgroundFrequencies.get("amino") + .get(symbol); + if (prob == 0 || bfreq == 0) + { + System.out.println("error"); + } + llr = Math.log(prob / bfreq); + if (keepRaw) + { + raw.get(rawPos).add(llr); + } + + String output; + output = String.format("%.1f", llr); + total += Double.parseDouble(output); + if ("-0.0".equals(output)) + { + output = "0.0"; + } + if (binned.containsKey(output)) + { + double prev = binned.get(output); + prev += (SCALE / count); + binned.put(output, prev); + + } + else + { + binned.put(output, SCALE / count); + } + } + } + } + System.out.println(total / count); + } + + + /** + * Reads in the sequence data from a Stockholm file. + * + * @param source + * @throws IOException + */ + public void readStockholm(BufferedReader inputSTO) throws IOException + { + FileParse parserSTO = new FileParse(inputSTO, "", DataSourceType.FILE); + StockholmFile file = new StockholmFile(parserSTO); + Vector annots = file.getAnnotations(); + + for (AlignmentAnnotation annot : annots) + { + if (annot.label.contains("Reference")) + { + reference = annot; + } + } + sequences = file.getSeqs(); + } + + /** + * Reads in the HMM data from a HMMer file. + * + * @param source + * @throws IOException + */ + public void readHMM(BufferedReader inputHMM) throws IOException + { + FileParse parserHMM = new FileParse(inputHMM, "", DataSourceType.FILE); + HMMFile file = new HMMFile(parserHMM); + hmm = file.getHMM(); + + + } + + /** + * Exports both the binned and raw data into separate files. + * + * @param location + * @throws FileNotFoundException + */ + public void exportData(String location) throws FileNotFoundException + { + PrintWriter writerBin = new PrintWriter(new File(location + BINNED)); + for (Map.Entry entry : binned.entrySet()) + { + writerBin.println(entry.getKey() + "," + entry.getValue()); + } + writerBin.close(); + if (keepRaw) + { + + PrintWriter writerRaw = new PrintWriter(new File(location + RAW)); + + StringBuilder identifier = new StringBuilder(); + + for (int i = 1; i < raw.size() + 1; i++) + { + identifier.append("Fam " + i + ","); + } + + writerRaw.println(identifier); + + boolean rowIsEmpty = false; + int row = 0; + while (!rowIsEmpty) + { + rowIsEmpty = true; + StringBuilder string = new StringBuilder(); + for (int column = 0; column < raw.size(); column++) + { + if (raw.get(column).size() <= row) + { + string.append("EMPTY,"); + } + else + { + string.append(raw.get(column).get(row) + ","); + rowIsEmpty = false; + } + } + row++; + writerRaw.println(string); + } + writerRaw.close(); + + } + + } + + /** + * Prints the specified family on the console. + * + * @param index + * @throws IOException + */ + public void printFam(int index) throws IOException + { + BufferedReader br = new BufferedReader(new FileReader(families)); + + moveLocationBy(index, br); + + String line = br.readLine(); + + while (!"//".equals(line)) + { + System.out.println(line); + line = br.readLine(); + } + System.out.println(line); + br.close(); + + } + + /** + * Prints the specified HMM on the console. + * + * @param index + * @throws IOException + */ + public void printHMM(int index) throws IOException + { + BufferedReader br = new BufferedReader(new FileReader(hmms)); + + moveLocationBy(index, br); + + String line = br.readLine(); + + while (!"//".equals(line)) + { + System.out.println(line); + line = br.readLine(); + } + System.out.println(line); + br.close(); + + } + + /** + * Prints the specified family to a .sto file. + * + * @param index + * @throws IOException + */ + public void exportFam(int index, String location) throws IOException + { + BufferedReader br = new BufferedReader(new FileReader(families)); + + moveLocationBy(index, br); + + String line = br.readLine(); + PrintWriter writer = new PrintWriter( + new FileOutputStream(new File(location), true)); + while (!"//".equals(line)) + { + writer.println(line); + line = br.readLine(); + } + writer.println(line); + writer.close(); + br.close(); + + } + + public void exportFile(BufferedReader br, String location, boolean append) + throws IOException + { + String line = br.readLine(); + PrintWriter writer = new PrintWriter( + new FileOutputStream(location, append)); + while (!"//".equals(line)) + { + writer.println(line); + line = br.readLine(); + } + writer.println(line); + writer.close(); + + + } + + public String getHMMName(int index) throws IOException + { + String name; + + BufferedReader nameFinder = new BufferedReader(new FileReader(hmms)); + + moveLocationBy(index, nameFinder); + + nameFinder.readLine(); + + Scanner scanner = new Scanner(nameFinder.readLine()); + name = scanner.next(); + name = scanner.next(); + scanner.close(); + return name; + } + + public String getFamilyName(int index) throws IOException + { + String name; + + BufferedReader nameFinder = new BufferedReader( + new FileReader(families)); + + moveLocationBy(index, nameFinder); + + nameFinder.readLine(); + + Scanner scanner = new Scanner(nameFinder.readLine()); + name = scanner.next(); + name = scanner.next(); + name = scanner.next(); + scanner.close(); + return name; + } + + /** + * Prints the specified family to a .hmm file. + * + * @param index + * @throws IOException + */ + public void exportHMM(int index, String location) throws IOException + { + + + BufferedReader br = new BufferedReader(new FileReader(hmms)); + + moveLocationBy(index, br); + + String line = br.readLine(); + + PrintWriter writer = new PrintWriter( + new FileOutputStream(new File(location), true)); + while (!"//".equals(line)) + { + writer.println(line); + line = br.readLine(); + } + writer.println(line); + writer.close(); + br.close(); + + } + + /** + * Clears all raw, binned and current position data in the current directory. + * + * @throws FileNotFoundException + */ + public void clear() throws FileNotFoundException + { + PrintWriter pos = new PrintWriter( + currentFolder + "/CurrentPosition.txt"); + pos.println("0"); + + PrintWriter raw = new PrintWriter(currentFolder + RAW); + + PrintWriter bin = new PrintWriter(currentFolder + BINNED); + + pos.close(); + bin.close(); + raw.close(); + } + + public void sortIntoClans(String directory) throws IOException + { + BufferedReader clanFinder = new BufferedReader(new FileReader(FAMILIESTOCLAN)); + BufferedReader familyReader = new BufferedReader( + new FileReader(families)); + BufferedReader hmmReader = new BufferedReader(new FileReader(hmms)); + int families = 0; + // moveLocationBy(7000, familyReader); + // moveLocationBy(7000, clanFinder); + // moveLocationBy(7000, hmmReader); + HashMap clanIndexes = new HashMap<>(); + ArrayList familyCounts = new ArrayList<>(); + int filePos = 0; + int clanCount = 0; + String line; + line = clanFinder.readLine(); + + while (!"".equals(line) && !" ".equals(line) && line != null) + { + String clanName; + boolean inClan = false; + while (!(line.indexOf("//") > -1)) + { + + if (line.indexOf("#=GF CL") > -1) + { + families++; + System.out.println(families); + inClan = true; + Scanner scanner = new Scanner(line); + scanner.next(); + scanner.next(); + clanName = scanner.next(); + scanner.close(); + + if (!clanIndexes.containsKey(clanName)) + { + clanIndexes.put(clanName, clanCount); + clanCount++; + familyCounts.add(0); + } + + + Integer clanI = clanIndexes.get(clanName); + String clanPath = directory + "/Clan" + clanI.toString(); + createFolders(clanPath); + + int index = clanIndexes.get(clanName); + exportFile(familyReader, + clanPath + "/Families/Fam" + familyCounts.get(index) + + ".sto", + false); + exportFile(hmmReader, + clanPath + "/HMMs/HMM" + familyCounts.get(index) + ".hmm", + false); + + int count = familyCounts.get(index); + count++; + familyCounts.set(index, count); + } + line = clanFinder.readLine(); + + } + if (!inClan) + { + moveLocationBy(1, familyReader); + moveLocationBy(1, hmmReader); + } + filePos++; + // System.out.println(filePos + " files read."); + line = clanFinder.readLine(); + + } + clanFinder.close(); + + for (int clan = 0; clan < clanCount; clan++) + { + PrintWriter writer = new PrintWriter( + directory + "/Clan" + clan + "/NumberOfFamilies.txt"); + int count = familyCounts.get(clan); + writer.print(count); + writer.close(); + } + + } + + public String getFamilies() + { + return families; + } + + public void setFamilies(String families) + { + this.families = currentFolder + families; + } + + public String getHmms() + { + return hmms; + } + + public void setHmms(String hmms) + { + this.hmms = currentFolder + hmms; + } + + public void alignWithinClan(String exportLocation, String clansLocation) + throws IOException, InterruptedException + { + int alignmentsExported = 0; + for (int clan = 0; clan < 604; clan++) + { + System.out.println(clan); + int famCount = 0; + String clanPath = clansLocation + "/Clan" + clan; + int numberOfFamilies; + BufferedReader br = new BufferedReader( + new FileReader(clanPath + "/NumberOfFamilies.txt")); + String line = br.readLine(); + numberOfFamilies = Integer.parseInt(line); + br.close(); + if (numberOfFamilies == 1) + { + continue; + } + final String commandExportLocation = exportLocation + "/Clan" + clan; + createFolders(commandExportLocation); + for (int family = 0; family < numberOfFamilies; family++) + { + famCount++; + ArrayList indexes = new ArrayList<>(); + for (int i = 0; i < numberOfFamilies; i++) + { + if (i != family) + { + indexes.add(i); + } + } + + int hmmIndex = getRandom(indexes); + String famPath = clanPath + "/Families/Fam" + family + ".sto"; + String hmmPath = clanPath + "/HMMs/HMM" + hmmIndex + ".hmm"; + String command = "/media/sf_Shared_Folder/hmmer/binaries/hmmalign --mapali " + + clanPath + "/Families/Fam" + hmmIndex + ".sto" + + " --trim "; + command += hmmPath + " "; + command += famPath; + final int familyIndex = family; + final Process p = Runtime.getRuntime().exec(command); + + new Thread(new Runnable() + { + @Override + public void run() + { + BufferedReader input = new BufferedReader( + new InputStreamReader(p.getInputStream())); + String line = null; + + try + { + PrintWriter writer = new PrintWriter(commandExportLocation + + "/Families/Fam" + familyIndex + ".sto"); + String lastLine = ""; + boolean dataFound = false; + while ((line = input.readLine()) != null) + { + if (line.contains("#=GR") && !dataFound) + { + writer.println(lastLine); + dataFound = true; + } + if (line.contains("#") || dataFound || " ".equals(line) + || "".equals(line) || "//".equals(line)) + { + writer.println(line); + } + lastLine = line; + } + writer.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + } + }).start(); + + p.waitFor(); + + BufferedReader hmmExporter = new BufferedReader( + new FileReader(hmmPath)); + + exportFile(hmmExporter, + commandExportLocation + "/HMMs/HMM" + family + ".hmm", + false); + + alignmentsExported++; + + + } + PrintWriter writer = new PrintWriter( + commandExportLocation + "/NumberOfFamilies.txt"); + writer.print(famCount); + writer.close(); + } + + } + + public boolean atEnd(BufferedReader br) throws IOException + { + boolean end = false; + br.mark(80); + String line = br.readLine(); + if ("".equals(line) || line == null) + { + end = true; + } + br.reset(); + return end; + } + + public int getRandom(ArrayList list) + { + if (!(list.size() > 0)) + { + System.out.println("Error - size = " + list.size()); + } + int index = generator.nextInt(list.size()); + int value = list.get(index); + list.remove(index); + return value; + } + + public void createFolders(String clanPath) + { + File clanFolder = new File(clanPath); + if (!clanFolder.exists()) + { + clanFolder.mkdir(); + } + + File famFolder = new File(clanPath + "/Families"); + File hmmFolder = new File(clanPath + "/HMMs"); + if (!famFolder.exists()) + { + famFolder.mkdir(); + hmmFolder.mkdir(); + } + } +} + + + + diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java index c944345..81b9964 100644 --- a/src/jalview/util/MapList.java +++ b/src/jalview/util/MapList.java @@ -1021,70 +1021,15 @@ public class MapList for (int[] range : map.getFromRanges()) { - addRange(range, fromShifts); + MappingUtils.addRange(range, fromShifts); } for (int[] range : map.getToRanges()) { - addRange(range, toShifts); + MappingUtils.addRange(range, toShifts); } } /** - * Adds the given range to a list of ranges. If the new range just extends - * existing ranges, the current endpoint is updated instead. - * - * @param range - * @param addTo - */ - static void addRange(int[] range, List addTo) - { - /* - * list is empty - add to it! - */ - if (addTo.size() == 0) - { - addTo.add(range); - return; - } - - int[] last = addTo.get(addTo.size() - 1); - boolean lastForward = last[1] >= last[0]; - boolean newForward = range[1] >= range[0]; - - /* - * contiguous range in the same direction - just update endpoint - */ - if (lastForward == newForward && last[1] == range[0]) - { - last[1] = range[1]; - return; - } - - /* - * next range starts at +1 in forward sense - update endpoint - */ - if (lastForward && newForward && range[0] == last[1] + 1) - { - last[1] = range[1]; - return; - } - - /* - * next range starts at -1 in reverse sense - update endpoint - */ - if (!lastForward && !newForward && range[0] == last[1] - 1) - { - last[1] = range[1]; - return; - } - - /* - * just add the new range - */ - addTo.add(range); - } - - /** * Returns true if mapping is from forward strand, false if from reverse * strand. Result is just based on the first 'from' range that is not a single * position. Default is true unless proven to be false. Behaviour is not well diff --git a/src/jalview/util/MappingUtils.java b/src/jalview/util/MappingUtils.java index f5dd883..cd8821d 100644 --- a/src/jalview/util/MappingUtils.java +++ b/src/jalview/util/MappingUtils.java @@ -542,9 +542,11 @@ public final class MappingUtils toSequences, fromGapChar); } - for (int[] hidden : hiddencols.getHiddenColumnsCopy()) + Iterator regions = hiddencols.iterator(); + while (regions.hasNext()) { - mapHiddenColumns(hidden, codonFrames, newHidden, fromSequences, + mapHiddenColumns(regions.next(), codonFrames, newHidden, + fromSequences, toSequences, fromGapChar); } return; // mappedColumns; @@ -1018,4 +1020,59 @@ public final class MappingUtils } } } + + /** + * Adds the given range to a list of ranges. If the new range just extends + * existing ranges, the current endpoint is updated instead. + * + * @param range + * @param addTo + */ + public static void addRange(int[] range, List addTo) + { + /* + * list is empty - add to it! + */ + if (addTo.size() == 0) + { + addTo.add(range); + return; + } + + int[] last = addTo.get(addTo.size() - 1); + boolean lastForward = last[1] >= last[0]; + boolean newForward = range[1] >= range[0]; + + /* + * contiguous range in the same direction - just update endpoint + */ + if (lastForward == newForward && last[1] == range[0]) + { + last[1] = range[1]; + return; + } + + /* + * next range starts at +1 in forward sense - update endpoint + */ + if (lastForward && newForward && range[0] == last[1] + 1) + { + last[1] = range[1]; + return; + } + + /* + * next range starts at -1 in reverse sense - update endpoint + */ + if (!lastForward && !newForward && range[0] == last[1] - 1) + { + last[1] = range[1]; + return; + } + + /* + * just add the new range + */ + addTo.add(range); + } } diff --git a/src/jalview/util/ProbabilityAnalyserKickstarter.java b/src/jalview/util/ProbabilityAnalyserKickstarter.java new file mode 100644 index 0000000..59c0a9f --- /dev/null +++ b/src/jalview/util/ProbabilityAnalyserKickstarter.java @@ -0,0 +1,221 @@ +package jalview.util; + +import java.io.IOException; +import java.util.Scanner; + +/** + * This class contains the brain of the analyser program, and contains a number + * of commands for the processing of data. + * + * @author TZVanaalten + * + */ + +public class ProbabilityAnalyserKickstarter +{ + + public static void main(String[] args) + throws IOException, InterruptedException + { + + // this does all of the processing + HMMProbabilityDistributionAnalyser analyser = new HMMProbabilityDistributionAnalyser(); + + boolean running = true; + System.out.println("ACTIVATED"); + while (running) + { + Scanner keyboard = new Scanner(System.in); + String command = keyboard.nextLine(); + + Scanner inputScanner = new Scanner(command); + // prints family to console. Syntax is printFam + if (command.indexOf("printFam") > -1) + { + try + { + inputScanner.next(); + int index = inputScanner.nextInt(); + analyser.printFam(index); + continue; + } catch (Exception e) + { + System.out.println("Command failed"); + } + + } + // prints HMM to console. Syntax is printHMM + if (command.indexOf("printHMM") > -1) + { + try + { + inputScanner.next(); + int index = inputScanner.nextInt(); + analyser.printHMM(index); + continue; + } catch (Exception e) + { + System.out.println("Command failed"); + } + } + // prints family to file in current folder. Syntax is exportFam . + if (command.indexOf("exportFam") > -1) + { + try + { + inputScanner.next(); + int index = inputScanner.nextInt(); + String location = inputScanner.next(); + analyser.exportFam(index, location); + continue; + } catch (Exception e) + { + System.out.println("Command failed"); + } + } + // prints HMM to file in current folder. Syntax is exportHMM . + if (command.indexOf("exportHMM") > -1) + { + try + { + inputScanner.next(); + int index = inputScanner.nextInt(); + String location = inputScanner.next(); + analyser.exportHMM(index, location); + continue; + } catch (Exception e) + { + System.out.println("Command failed"); + } + } + // Processes data. Syntax is run . The + // number loops specifies the number of increments the program will run. + // After each increment, the data stored currently in the program is + // exported and re-read back into the program. This is to ensure that the + // program can be terminated without losing a large quantity of data. The + // increment is the number of families read per 'save'. + if (command.indexOf("run") > -1 && !(command.indexOf("ToEnd") > -1)) + { + try + { + + inputScanner.next(); + + int loops = inputScanner.nextInt(); + int increments = inputScanner.nextInt(); + boolean keepRaw = inputScanner.nextBoolean(); + + for (int i = 0; i < loops; i++) + { + analyser.run(increments, keepRaw); + System.out.println("Saved"); + } + System.out.println("Task completed"); + continue; + } catch (Exception e) + { + System.out.println("Command failed"); + } + continue; + } + if ((command.indexOf("runToEnd") > -1)) + { + try + { + + inputScanner.next(); + int minCount = inputScanner.nextInt(); + int maxCount = inputScanner.nextInt(); + boolean keepRaw = inputScanner.nextBoolean(); + boolean forClans = inputScanner.nextBoolean(); + analyser.runToEnd(minCount, maxCount, keepRaw, forClans); + System.out.println("Task completed"); + } catch (Exception e) + { + System.out.println("Command failed"); + } + continue; + } + // terminates program. Syntax is terminate. + if (command.indexOf("terminate") > -1) + { + running = false; + continue; + } + // clears files in current directory (Only a specific set of files). + // Syntax is clear. + if (command.indexOf("clear") > -1) + { + analyser.clear(); + continue; + } + // changes current directory. Syntax is cd + if (command.indexOf("cd") > -1) + { + try + { + inputScanner.next(); + analyser.setFolder(inputScanner.next()); + } catch (Exception e) + { + System.out.println("Command failed"); + + } + continue; + } + + if (command.indexOf("getFamName") > -1) + { + try + { + inputScanner.next(); + System.out.println(analyser.getFamilyName(inputScanner.nextInt())); + + } catch (Exception e) + { + System.out.println("Command failed"); + } + continue; + } + if (command.indexOf("sortIntoClans") > -1) + { + inputScanner.next(); + analyser.sortIntoClans(inputScanner.next()); + continue; + + } + if (command.indexOf("setFamilies") > -1) + { + inputScanner.next(); + analyser.setFamilies(inputScanner.next()); + continue; + + } + + if (command.indexOf("setHMMs") > -1) + { + inputScanner.next(); + analyser.setHmms(inputScanner.next()); + continue; + + } + + if (command.indexOf("alignWithinClans") > -1) + { + inputScanner.next(); + String export = inputScanner.next(); + String clans = inputScanner.next(); + analyser.alignWithinClan(export, clans); + continue; + + } + + System.out.println("Unrecognised command"); + } + + + + + } + +} diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index a0cbff4..18c2aed 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -57,6 +57,7 @@ import jalview.viewmodel.styles.ViewStyle; import jalview.workers.AlignCalcManager; import jalview.workers.ComplementConsensusThread; import jalview.workers.ConsensusThread; +import jalview.workers.InformationThread; import jalview.workers.StrucConsensusThread; import java.awt.Color; @@ -67,6 +68,7 @@ import java.util.BitSet; import java.util.Deque; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -96,10 +98,69 @@ public abstract class AlignmentViewport protected Deque redoList = new ArrayDeque<>(); + protected String sequenceSetID; + + /* + * probably unused indicator that view is of a dataset rather than an + * alignment + */ + protected boolean isDataset = false; + + private Map hiddenRepSequences; + + protected ColumnSelection colSel = new ColumnSelection(); + + public boolean autoCalculateConsensus = true; + + protected boolean autoCalculateStrucConsensus = true; + + protected boolean ignoreGapsInConsensusCalculation = false; + + protected boolean ignoreBelowBackGroundFrequencyCalculation = false; + + protected boolean infoLetterHeight = false; + + protected ResidueShaderI residueShading = new ResidueShader(); + + protected AlignmentAnnotation consensus; + + protected AlignmentAnnotation complementConsensus; + + protected AlignmentAnnotation occupancy; + + protected AlignmentAnnotation strucConsensus; + + protected AlignmentAnnotation conservation; + + protected AlignmentAnnotation quality; + + /** + * alignment displayed in the viewport + */ + private AlignmentI alignment; + /** - * alignment displayed in the viewport. Please use get/setter + * results of alignment consensus analysis for visible portion of view + */ + protected ProfilesI consensusProfiles; + + /** + * HMM profile for the alignment + */ + protected ProfilesI hmmProfiles; + + /** + * results of cDNA complement consensus visible portion of view */ - protected AlignmentI alignment; + protected Hashtable[] hcomplementConsensus; + + /** + * results of secondary structure base pair consensus for visible portion of + * view + */ + protected Hashtable[] hStrucConsensus; + + protected Conservation hconservation; public AlignmentViewport(AlignmentI al) { @@ -580,14 +641,6 @@ public abstract class AlignmentViewport return alignment.getGapCharacter(); } - protected String sequenceSetID; - - /** - * probably unused indicator that view is of a dataset rather than an - * alignment - */ - protected boolean isDataset = false; - public void setDataset(boolean b) { isDataset = b; @@ -598,18 +651,6 @@ public abstract class AlignmentViewport return isDataset; } - private Map hiddenRepSequences; - - protected ColumnSelection colSel = new ColumnSelection(); - - public boolean autoCalculateConsensus = true; - - protected boolean autoCalculateStrucConsensus = true; - - protected boolean ignoreGapsInConsensusCalculation = false; - - protected ResidueShaderI residueShading = new ResidueShader(); - @Override public void setGlobalColourScheme(ColourSchemeI cs) { @@ -682,41 +723,6 @@ public abstract class AlignmentViewport { return residueShading; } - - protected AlignmentAnnotation consensus; - - protected AlignmentAnnotation complementConsensus; - - protected AlignmentAnnotation gapcounts; - - protected AlignmentAnnotation strucConsensus; - - protected AlignmentAnnotation conservation; - - protected AlignmentAnnotation quality; - - protected AlignmentAnnotation[] groupConsensus; - - protected AlignmentAnnotation[] groupConservation; - - /** - * results of alignment consensus analysis for visible portion of view - */ - protected ProfilesI hconsensus = null; - - /** - * results of cDNA complement consensus visible portion of view - */ - protected Hashtable[] hcomplementConsensus = null; - - /** - * results of secondary structure base pair consensus for visible portion of - * view - */ - protected Hashtable[] hStrucConsensus = null; - - protected Conservation hconservation = null; - @Override public void setConservation(Conservation cons) { @@ -736,9 +742,9 @@ public abstract class AlignmentViewport } @Override - public void setSequenceConsensusHash(ProfilesI hconsensus) + public void setConsensusProfiles(ProfilesI hconsensus) { - this.hconsensus = hconsensus; + this.consensusProfiles = hconsensus; } @Override @@ -748,9 +754,21 @@ public abstract class AlignmentViewport } @Override - public ProfilesI getSequenceConsensusHash() + public ProfilesI getConsensusProfiles() + { + return consensusProfiles; + } + + @Override + public void setHmmProfiles(ProfilesI info) + { + hmmProfiles = info; + } + + @Override + public ProfilesI getHmmProfiles() { - return hconsensus; + return hmmProfiles; } @Override @@ -791,9 +809,9 @@ public abstract class AlignmentViewport } @Override - public AlignmentAnnotation getAlignmentGapAnnotation() + public AlignmentAnnotation getOccupancyAnnotation() { - return gapcounts; + return occupancy; } @Override @@ -882,6 +900,16 @@ public abstract class AlignmentViewport } } + @Override + public void initInformationWorker(final AlignmentViewPanel ap) + { + if (calculator + .getRegisteredWorkersOfClass(InformationThread.class) == null) + { + calculator.registerWorker(new InformationThread(this, ap)); + } + } + // --------START Structure Conservation public void updateStrucConsensus(final AlignmentViewPanel ap) { @@ -945,12 +973,10 @@ public abstract class AlignmentViewport strucConsensus = null; conservation = null; quality = null; - groupConsensus = null; - groupConservation = null; - hconsensus = null; + consensusProfiles = null; hconservation = null; hcomplementConsensus = null; - gapcounts = null; + occupancy = null; calculator = null; residueShading = null; // may hold a reference to Consensus changeSupport = null; @@ -1000,6 +1026,21 @@ public abstract class AlignmentViewport protected boolean showConsensusHistogram = true; /** + * should hmm profile be rendered by default + */ + protected boolean hmmShowSequenceLogo = false; + + /** + * should hmm profile be rendered normalised to row height + */ + protected boolean hmmNormaliseSequenceLogo = false; + + /** + * should information histograms be rendered by default + */ + protected boolean hmmShowHistogram = true; + + /** * @return the showConsensusProfile */ @Override @@ -1009,6 +1050,15 @@ public abstract class AlignmentViewport } /** + * @return the showInformationProfile + */ + @Override + public boolean isShowHMMSequenceLogo() + { + return hmmShowSequenceLogo; + } + + /** * @param showSequenceLogo * the new value */ @@ -1026,6 +1076,18 @@ public abstract class AlignmentViewport this.showSequenceLogo = showSequenceLogo; } + public void setShowHMMSequenceLogo(boolean showHMMSequenceLogo) + { + if (showHMMSequenceLogo != this.hmmShowSequenceLogo) + { + this.hmmShowSequenceLogo = showHMMSequenceLogo; + // TODO: updateAnnotation if description (tooltip) will show + // profile in place of information content? + // calculator.updateAnnotationFor(InformationThread.class); + } + this.hmmShowSequenceLogo = showHMMSequenceLogo; + } + /** * @param showConsensusHistogram * the showConsensusHistogram to set @@ -1036,6 +1098,14 @@ public abstract class AlignmentViewport } /** + * @param showInformationHistogram + */ + public void setShowInformationHistogram(boolean showInformationHistogram) + { + this.hmmShowHistogram = showInformationHistogram; + } + + /** * @return the showGroupConservation */ public boolean isShowGroupConservation() @@ -1081,6 +1151,17 @@ public abstract class AlignmentViewport } /** + * + * @return flag to indicate if the information content histogram should be + * rendered by default + */ + @Override + public boolean isShowInformationHistogram() + { + return this.hmmShowHistogram; + } + + /** * when set, updateAlignment will always ensure sequences are of equal length */ private boolean padGaps = false; @@ -1229,14 +1310,22 @@ public abstract class AlignmentViewport ignoreGapsInConsensusCalculation = b; if (ap != null) { - updateConsensus(ap); if (residueShading != null) { residueShading.setThreshold(residueShading.getThreshold(), ignoreGapsInConsensusCalculation); } } + } + + public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap) + { + ignoreBelowBackGroundFrequencyCalculation = b; + } + public void setInfoLetterHeight(boolean b, AlignmentViewPanel ap) + { + infoLetterHeight = b; } private long sgrouphash = -1, colselhash = -1; @@ -1293,6 +1382,18 @@ public abstract class AlignmentViewport return ignoreGapsInConsensusCalculation; } + @Override + public boolean isIgnoreBelowBackground() + { + return ignoreBelowBackGroundFrequencyCalculation; + } + + @Override + public boolean isInfoLetterHeight() + { + return infoLetterHeight; + } + // property change stuff // JBPNote Prolly only need this in the applet version. private PropertyChangeSupport changeSupport = new PropertyChangeSupport( @@ -1740,8 +1841,12 @@ public abstract class AlignmentViewport if (alignment.getHiddenColumns() != null && alignment.getHiddenColumns().hasHiddenColumns()) { - selection = alignment.getHiddenColumns() - .getVisibleSequenceStrings(start, end, seqs); + for (i = 0; i < iSize; i++) + { + Iterator blocks = alignment.getHiddenColumns() + .getVisContigsIterator(start, end + 1, false); + selection[i] = seqs[i].getSequenceStringFromIterator(blocks); + } } else { @@ -1768,10 +1873,10 @@ public abstract class AlignmentViewport { if (start == 0) { - start = hidden.adjustForHiddenColumns(start); + start = hidden.visibleToAbsoluteColumn(start); } - end = hidden.getHiddenBoundaryRight(start); + end = hidden.getNextHiddenBoundary(false, start); if (start == end) { end = max; @@ -1786,8 +1891,8 @@ public abstract class AlignmentViewport if (hidden != null && hidden.hasHiddenColumns()) { - start = hidden.adjustForHiddenColumns(end); - start = hidden.getHiddenBoundaryLeft(start) + 1; + start = hidden.visibleToAbsoluteColumn(end); + start = hidden.getNextHiddenBoundary(true, start) + 1; } } while (end < max); @@ -1809,13 +1914,13 @@ public abstract class AlignmentViewport AlignmentAnnotation clone = new AlignmentAnnotation(annot); if (selectedOnly && selectionGroup != null) { - alignment.getHiddenColumns().makeVisibleAnnotation( + clone.makeVisibleAnnotation( selectionGroup.getStartRes(), selectionGroup.getEndRes(), - clone); + alignment.getHiddenColumns()); } else { - alignment.getHiddenColumns().makeVisibleAnnotation(clone); + clone.makeVisibleAnnotation(alignment.getHiddenColumns()); } ala.add(clone); } @@ -1848,18 +1953,6 @@ public abstract class AlignmentViewport { alignment.padGaps(); } - if (autoCalculateConsensus) - { - updateConsensus(ap); - } - if (hconsensus != null && autoCalculateConsensus) - { - updateConservation(ap); - } - if (autoCalculateStrucConsensus) - { - updateStrucConsensus(ap); - } // Reset endRes of groups if beyond alignment width int alWidth = alignment.getWidth(); @@ -1882,7 +1975,6 @@ public abstract class AlignmentViewport updateAllColourSchemes(); calculator.restartWorkers(); - // alignment.adjustSequenceAnnotations(); } /** @@ -1895,7 +1987,7 @@ public abstract class AlignmentViewport { rs.alignmentChanged(alignment, hiddenRepSequences); - rs.setConsensus(hconsensus); + rs.setConsensus(consensusProfiles); if (rs.conservationApplied()) { rs.setConservation(Conservation.calculateConservation("All", @@ -1920,7 +2012,7 @@ public abstract class AlignmentViewport // depending on if the user wants to see the annotation or not in a // specific alignment - if (hconsensus == null && !isDataset) + if (consensusProfiles == null && !isDataset) { if (!alignment.isNucleotide()) { @@ -1935,7 +2027,8 @@ public abstract class AlignmentViewport MessageManager.getString("label.consensus_descr"), new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); initConsensus(consensus); - initGapCounts(); + + initOccupancy(); initComplementConsensus(); } @@ -1994,20 +2087,20 @@ public abstract class AlignmentViewport // these should be extracted from the view model - style and settings for // derived annotation - private void initGapCounts() + private void initOccupancy() { if (showOccupancy) { - gapcounts = new AlignmentAnnotation("Occupancy", + occupancy = new AlignmentAnnotation("Occupancy", MessageManager.getString("label.occupancy_descr"), new Annotation[1], 0f, alignment.getHeight(), AlignmentAnnotation.BAR_GRAPH); - gapcounts.hasText = true; - gapcounts.autoCalculated = true; - gapcounts.scaleColLabel = true; - gapcounts.graph = AlignmentAnnotation.BAR_GRAPH; + occupancy.hasText = true; + occupancy.autoCalculated = true; + occupancy.scaleColLabel = true; + occupancy.graph = AlignmentAnnotation.BAR_GRAPH; - alignment.addAnnotation(gapcounts); + alignment.addAnnotation(occupancy); } } @@ -2141,6 +2234,9 @@ public abstract class AlignmentViewport boolean showprf = isShowSequenceLogo(); boolean showConsHist = isShowConsensusHistogram(); boolean normLogo = isNormaliseSequenceLogo(); + boolean showHMMPrf = isShowHMMSequenceLogo(); + boolean showInfoHist = isShowInformationHistogram(); + boolean normHMMLogo = isNormaliseHMMSequenceLogo(); /** * TODO reorder the annotation rows according to group/sequence ordering on @@ -2178,6 +2274,9 @@ public abstract class AlignmentViewport sg.setshowSequenceLogo(showprf); sg.setShowConsensusHistogram(showConsHist); sg.setNormaliseSequenceLogo(normLogo); + sg.setShowHMMSequenceLogo(showHMMPrf); + sg.setShowInformationHistogram(showInfoHist); + sg.setNormaliseHMMSequenceLogo(normHMMLogo); } if (conv) { @@ -2781,7 +2880,7 @@ public abstract class AlignmentViewport int lastSeq = alignment.getHeight() - 1; List seqMappings = null; for (int seqNo = ranges - .getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++) + .getStartSeq(); seqNo <= lastSeq; seqNo++, seqOffset++) { sequence = getAlignment().getSequenceAt(seqNo); if (hiddenSequences != null && hiddenSequences.isHidden(sequence)) @@ -2938,6 +3037,19 @@ public abstract class AlignmentViewport return sq; } + public boolean hasReferenceAnnotation() + { + AlignmentAnnotation[] annots = this.alignment.getAlignmentAnnotation(); + for (AlignmentAnnotation annot : annots) + { + if ("RF".equals(annot.label) || annot.label.contains("Reference")) + { + return true; + } + } + return false; + } + @Override public void setCurrentTree(TreeModel tree) { @@ -2949,4 +3061,26 @@ public abstract class AlignmentViewport { return currentTree; } + + @Override + public boolean isNormaliseSequenceLogo() + { + return normaliseSequenceLogo; + } + + public void setNormaliseSequenceLogo(boolean state) + { + normaliseSequenceLogo = state; + } + + @Override + public boolean isNormaliseHMMSequenceLogo() + { + return hmmNormaliseSequenceLogo; + } + + public void setNormaliseHMMSequenceLogo(boolean state) + { + hmmNormaliseSequenceLogo = state; + } } diff --git a/src/jalview/viewmodel/OverviewDimensions.java b/src/jalview/viewmodel/OverviewDimensions.java index 170f4e9..0235081 100644 --- a/src/jalview/viewmodel/OverviewDimensions.java +++ b/src/jalview/viewmodel/OverviewDimensions.java @@ -58,6 +58,10 @@ public abstract class OverviewDimensions protected int alheight; + protected float widthRatio; + + protected float heightRatio; + /** * Create an OverviewDimensions object * @@ -157,23 +161,25 @@ public abstract class OverviewDimensions public float getPixelsPerCol() { resetAlignmentDims(); - return (float) width / alwidth; + return 1 / widthRatio; } public float getPixelsPerSeq() { resetAlignmentDims(); - return (float) sequencesHeight / alheight; + return 1 / heightRatio; } public void setWidth(int w) { width = w; + widthRatio = (float) alwidth / width; } public void setHeight(int h) { sequencesHeight = h - graphHeight; + heightRatio = (float) alheight / sequencesHeight; } /** @@ -273,14 +279,14 @@ public abstract class OverviewDimensions // boxX, boxY is the x,y location equivalent to startRes, startSeq int xPos = Math.min(startRes, alwidth - vpwidth + 1); - boxX = Math.round((float) xPos * width / alwidth); - boxY = Math.round((float) startSeq * sequencesHeight / alheight); + boxX = Math.round(xPos / widthRatio); + boxY = Math.round(startSeq / heightRatio); // boxWidth is the width in residues translated to pixels - boxWidth = Math.round((float) vpwidth * width / alwidth); + boxWidth = Math.round(vpwidth / widthRatio); // boxHeight is the height in sequences translated to pixels - boxHeight = Math.round((float) vpheight * sequencesHeight / alheight); + boxHeight = Math.round(vpheight / heightRatio); } /** diff --git a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java index c158ce7..de90a21 100644 --- a/src/jalview/viewmodel/OverviewDimensionsHideHidden.java +++ b/src/jalview/viewmodel/OverviewDimensionsHideHidden.java @@ -50,6 +50,8 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public void updateViewportFromMouse(int mousex, int mousey, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + int xAsRes = getLeftXFromCentreX(mousex, hiddenCols); int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs); @@ -61,24 +63,29 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public void adjustViewportFromMouse(int mousex, int mousey, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + // calculate translation in pixel terms: // get mouse location in viewport coords, add translation in viewport // coords, and update viewport as usual - int vpx = Math.round((float) mousex * alwidth / width); - int vpy = Math.round((float) mousey * alheight / sequencesHeight); + int vpx = Math.round(mousex * widthRatio); + int vpy = Math.round(mousey * heightRatio); updateViewportFromTopLeft(vpx + xdiff, vpy + ydiff, hiddenSeqs, hiddenCols); } + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh alwidth, alheight and width/height ratios + */ @Override protected void updateViewportFromTopLeft(int leftx, int topy, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { int xAsRes = leftx; int yAsSeq = topy; - resetAlignmentDims(); if (xAsRes < 0) { @@ -147,7 +154,7 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public AlignmentColsCollectionI getColumns(AlignmentI al) { return new VisibleColsCollection(0, - ranges.getAbsoluteAlignmentWidth() - 1, al); + ranges.getAbsoluteAlignmentWidth() - 1, al.getHiddenColumns()); } @Override @@ -162,19 +169,30 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions { alwidth = ranges.getVisibleAlignmentWidth(); alheight = ranges.getVisibleAlignmentHeight(); + + widthRatio = (float) alwidth / width; + heightRatio = (float) alheight / sequencesHeight; } + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh widthRatio + */ @Override protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden) { - int vpx = Math.round((float) mousex * alwidth / width); + int vpx = Math.round(mousex * widthRatio); return vpx - ranges.getViewportWidth() / 2; } + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh heightRatio + */ @Override protected int getTopYFromCentreY(int mousey, HiddenSequences hidden) { - int vpy = Math.round((float) mousey * alheight / sequencesHeight); + int vpy = Math.round(mousey * heightRatio); return vpy - ranges.getViewportHeight() / 2; } @@ -182,10 +200,12 @@ public class OverviewDimensionsHideHidden extends OverviewDimensions public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + // get alignment position of x and box (can get directly from vpranges) and // calculate difference between the positions - int vpx = Math.round((float) x * alwidth / width); - int vpy = Math.round((float) y * alheight / sequencesHeight); + int vpx = Math.round(x * widthRatio); + int vpy = Math.round(y * heightRatio); xdiff = ranges.getStartRes() - vpx; ydiff = ranges.getStartSeq() - vpy; diff --git a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java index 9dde16e..3aa6e1b 100644 --- a/src/jalview/viewmodel/OverviewDimensionsShowHidden.java +++ b/src/jalview/viewmodel/OverviewDimensionsShowHidden.java @@ -72,13 +72,15 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions public void updateViewportFromMouse(int mousex, int mousey, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + // convert mousex and mousey to alignment units as well as // translating to top left corner of viewport - this is an absolute position int xAsRes = getLeftXFromCentreX(mousex, hiddenCols); int yAsSeq = getTopYFromCentreY(mousey, hiddenSeqs); // convert to visible positions - int visXAsRes = hiddenCols.findColumnPosition(xAsRes); + int visXAsRes = hiddenCols.absoluteToVisibleColumn(xAsRes); yAsSeq = hiddenSeqs.adjustForHiddenSeqs( hiddenSeqs.findIndexWithoutHiddenSeqs(yAsSeq)); yAsSeq = Math.max(yAsSeq, 0); // -1 if before first visible sequence @@ -93,27 +95,32 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions public void adjustViewportFromMouse(int mousex, int mousey, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + // calculate translation in pixel terms: // get mouse location in viewport coords, add translation in viewport // coords, // convert back to pixel coords int vpx = Math.round((float) mousex * alwidth / width); - int visXAsRes = hiddenCols.findColumnPosition(vpx) + xdiff; + int visXAsRes = hiddenCols.absoluteToVisibleColumn(vpx) + xdiff; - int vpy = Math.round((float) mousey * alheight / sequencesHeight); + int vpy = Math.round(mousey * heightRatio); int visYAsRes = hiddenSeqs.findIndexWithoutHiddenSeqs(vpy) + ydiff; // update viewport accordingly updateViewportFromTopLeft(visXAsRes, visYAsRes, hiddenSeqs, hiddenCols); } + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh alwidth, alheight and width/height ratios + */ @Override protected void updateViewportFromTopLeft(int leftx, int topy, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { int visXAsRes = leftx; int visYAsSeq = topy; - resetAlignmentDims(); if (visXAsRes < 0) { @@ -136,7 +143,7 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions int vpwidth = ranges.getViewportWidth(); // check in case we went off the edge of the alignment - int visAlignWidth = hiddenCols.findColumnPosition(alwidth - 1); + int visAlignWidth = hiddenCols.absoluteToVisibleColumn(alwidth - 1); if (visXAsRes + vpwidth - 1 > visAlignWidth) { // went past the end of the alignment, adjust backwards @@ -144,8 +151,8 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions // if last position was before the end of the alignment, need to update if (ranges.getEndRes() < visAlignWidth) { - visXAsRes = hiddenCols.findColumnPosition(hiddenCols - .subtractVisibleColumns(vpwidth - 1, alwidth - 1)); + visXAsRes = hiddenCols.absoluteToVisibleColumn(hiddenCols + .offsetByVisibleColumns(-(vpwidth - 1), alwidth - 1)); } else { @@ -195,8 +202,8 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions HiddenColumns hiddenCols) { // work with absolute values of startRes and endRes - int startRes = hiddenCols.adjustForHiddenColumns(ranges.getStartRes()); - int endRes = hiddenCols.adjustForHiddenColumns(ranges.getEndRes()); + int startRes = hiddenCols.visibleToAbsoluteColumn(ranges.getStartRes()); + int endRes = hiddenCols.visibleToAbsoluteColumn(ranges.getEndRes()); // work with absolute values of startSeq and endSeq int startSeq = hiddenSeqs.adjustForHiddenSeqs(ranges.getStartSeq()); @@ -225,20 +232,32 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions { alwidth = ranges.getAbsoluteAlignmentWidth(); alheight = ranges.getAbsoluteAlignmentHeight(); + + widthRatio = (float) alwidth / width; + heightRatio = (float) alheight / sequencesHeight; } + + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh widthRatio + */ @Override protected int getLeftXFromCentreX(int mousex, HiddenColumns hidden) { int vpx = Math.round((float) mousex * alwidth / width); - return hidden.subtractVisibleColumns(ranges.getViewportWidth() / 2, + return hidden.offsetByVisibleColumns(-ranges.getViewportWidth() / 2, vpx); } + /** + * {@inheritDoc} Callers should have already called resetAlignmentDims to + * refresh heightRatio + */ @Override protected int getTopYFromCentreY(int mousey, HiddenSequences hidden) { - int vpy = Math.round((float) mousey * alheight / sequencesHeight); + int vpy = Math.round(mousey * heightRatio); return hidden.subtractVisibleRows(ranges.getViewportHeight() / 2, vpy); } @@ -246,12 +265,14 @@ public class OverviewDimensionsShowHidden extends OverviewDimensions public void setDragPoint(int x, int y, HiddenSequences hiddenSeqs, HiddenColumns hiddenCols) { + resetAlignmentDims(); + // get alignment position of x and box (can get directly from vpranges) and // calculate difference between the positions - int vpx = Math.round((float) x * alwidth / width); - int vpy = Math.round((float) y * alheight / sequencesHeight); + int vpx = Math.round(x * widthRatio); + int vpy = Math.round(y * heightRatio); - xdiff = ranges.getStartRes() - hiddenCols.findColumnPosition(vpx); + xdiff = ranges.getStartRes() - hiddenCols.absoluteToVisibleColumn(vpx); ydiff = ranges.getStartSeq() - hiddenSeqs.findIndexWithoutHiddenSeqs(vpy); } diff --git a/src/jalview/viewmodel/ViewportRanges.java b/src/jalview/viewmodel/ViewportRanges.java index c7a3fa1..691e492 100644 --- a/src/jalview/viewmodel/ViewportRanges.java +++ b/src/jalview/viewmodel/ViewportRanges.java @@ -609,14 +609,14 @@ public class ViewportRanges extends ViewportProperties } HiddenColumns hidden = al.getHiddenColumns(); - while (x < hidden.adjustForHiddenColumns(startRes)) + while (x < hidden.visibleToAbsoluteColumn(startRes)) { if (!scrollRight(false)) { break; } } - while (x > hidden.adjustForHiddenColumns(endRes)) + while (x > hidden.visibleToAbsoluteColumn(endRes)) { if (!scrollRight(true)) { @@ -638,7 +638,7 @@ public class ViewportRanges extends ViewportProperties boolean changedLocation = false; // convert the x,y location to visible coordinates - int visX = al.getHiddenColumns().findColumnPosition(x); + int visX = al.getHiddenColumns().absoluteToVisibleColumn(x); int visY = al.getHiddenSequences().findIndexWithoutHiddenSeqs(y); // if (vis_x,vis_y) is already visible don't do anything diff --git a/src/jalview/workers/AlignCalcManager.java b/src/jalview/workers/AlignCalcManager.java index 08ef3a2..6f0deab 100644 --- a/src/jalview/workers/AlignCalcManager.java +++ b/src/jalview/workers/AlignCalcManager.java @@ -74,7 +74,7 @@ public class AlignCalcManager implements AlignCalcManagerI .synchronizedList(new ArrayList()); updating = Collections.synchronizedMap( new Hashtable, List>()); - canUpdate = new HashSet(); + canUpdate = new HashSet<>(); } @Override @@ -285,7 +285,7 @@ public class AlignCalcManager implements AlignCalcManagerI public List getRegisteredWorkersOfClass( Class workerClass) { - List workingClass = new ArrayList(); + List workingClass = new ArrayList<>(); synchronized (canUpdate) { for (AlignCalcWorkerI worker : canUpdate) @@ -312,8 +312,8 @@ public class AlignCalcManager implements AlignCalcManagerI public void removeRegisteredWorkersOfClass( Class typeToRemove) { - List removable = new ArrayList(); - Set toremovannot = new HashSet(); + List removable = new ArrayList<>(); + Set toremovannot = new HashSet<>(); synchronized (restartable) { for (AlignCalcWorkerI worker : restartable) @@ -363,7 +363,7 @@ public class AlignCalcManager implements AlignCalcManagerI * first just find those to remove (to avoid * ConcurrentModificationException) */ - List toRemove = new ArrayList(); + List toRemove = new ArrayList<>(); for (AlignCalcWorkerI worker : restartable) { if (worker.involves(ann)) diff --git a/src/jalview/workers/ConsensusThread.java b/src/jalview/workers/ConsensusThread.java index 335529c..d6a4488 100644 --- a/src/jalview/workers/ConsensusThread.java +++ b/src/jalview/workers/ConsensusThread.java @@ -50,7 +50,7 @@ public class ConsensusThread extends AlignCalcWorker try { AlignmentAnnotation consensus = getConsensusAnnotation(); - AlignmentAnnotation gap = getGapAnnotation(); + AlignmentAnnotation gap = getOccupancyAnnotation(); if ((consensus == null && gap == null) || calcMan.isPending(this)) { calcMan.workerComplete(this); @@ -119,7 +119,7 @@ public class ConsensusThread extends AlignCalcWorker { AlignmentAnnotation consensus = getConsensusAnnotation(); consensus.annotations = new Annotation[aWidth]; - AlignmentAnnotation gap = getGapAnnotation(); + AlignmentAnnotation gap = getOccupancyAnnotation(); if (gap != null) { gap.annotations = new Annotation[aWidth]; @@ -137,7 +137,7 @@ public class ConsensusThread extends AlignCalcWorker ProfilesI hconsensus = AAFrequency.calculate(aseqs, width, 0, width, true); - alignViewport.setSequenceConsensusHash(hconsensus); + alignViewport.setConsensusProfiles(hconsensus); setColourSchemeConsensus(hconsensus); } @@ -176,9 +176,9 @@ public class ConsensusThread extends AlignCalcWorker * * @return */ - protected AlignmentAnnotation getGapAnnotation() + protected AlignmentAnnotation getOccupancyAnnotation() { - return alignViewport.getAlignmentGapAnnotation(); + return alignViewport.getOccupancyAnnotation(); } /** @@ -199,10 +199,10 @@ public class ConsensusThread extends AlignCalcWorker && hconsensus != null) { deriveConsensus(consensus, hconsensus); - AlignmentAnnotation gap = getGapAnnotation(); - if (gap != null) + AlignmentAnnotation occupancy = getOccupancyAnnotation(); + if (occupancy != null) { - deriveGap(gap, hconsensus); + deriveOccupancy(occupancy, hconsensus); } } } @@ -219,7 +219,6 @@ public class ConsensusThread extends AlignCalcWorker protected void deriveConsensus(AlignmentAnnotation consensusAnnotation, ProfilesI hconsensus) { - long nseq = getSequences().length; AAFrequency.completeConsensus(consensusAnnotation, hconsensus, hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, @@ -235,11 +234,11 @@ public class ConsensusThread extends AlignCalcWorker * @param hconsensus * the computed consensus data */ - protected void deriveGap(AlignmentAnnotation gapAnnotation, + protected void deriveOccupancy(AlignmentAnnotation gapAnnotation, ProfilesI hconsensus) { long nseq = getSequences().length; - AAFrequency.completeGapAnnot(gapAnnotation, hconsensus, + AAFrequency.completeOccupancyAnnot(gapAnnotation, hconsensus, hconsensus.getStartColumn(), hconsensus.getEndColumn() + 1, nseq); } @@ -252,6 +251,6 @@ public class ConsensusThread extends AlignCalcWorker protected Object getViewportConsensus() { // TODO convert ComplementConsensusThread to use Profile - return alignViewport.getSequenceConsensusHash(); + return alignViewport.getConsensusProfiles(); } } diff --git a/src/jalview/workers/InformationThread.java b/src/jalview/workers/InformationThread.java new file mode 100644 index 0000000..d42598c --- /dev/null +++ b/src/jalview/workers/InformationThread.java @@ -0,0 +1,311 @@ +package jalview.workers; + +import jalview.analysis.AAFrequency; +import jalview.api.AlignViewportI; +import jalview.api.AlignmentViewPanel; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.ProfilesI; +import jalview.datamodel.SequenceGroup; +import jalview.datamodel.SequenceI; +import jalview.util.MessageManager; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class calculates HMM Information Content annotations, based on any HMM + * consensus sequences and their HMM models. HMM consensus sequences may be + * present for the whole alignment, or subgroups of it. + * + */ +public class InformationThread extends AlignCalcWorker +{ + public static final String HMM_CALC_ID = "HMM"; + + /** + * Constructor + * + * @param alignViewport + * @param alignPanel + */ + public InformationThread(AlignViewportI alignViewport, + AlignmentViewPanel alignPanel) + { + super(alignViewport, alignPanel); + } + + /** + * Recomputes Information annotations for any HMM consensus sequences (for + * alignment and/or groups) + */ + @Override + public void run() + { + if (calcMan.isPending(this)) + { + return; + } + calcMan.notifyStart(this); + // long started = System.currentTimeMillis(); + + try + { + if (calcMan.isPending(this)) + { + // another instance of this is waiting to run + calcMan.workerComplete(this); + return; + } + while (!calcMan.notifyWorking(this)) + { + // another thread in progress, wait my turn + try + { + if (ap != null) + { + ap.paintAlignment(false, false); + } + Thread.sleep(200); + } catch (Exception ex) + { + ex.printStackTrace(); + } + } + if (alignViewport.isClosed()) + { + abortAndDestroy(); + return; + } + + AlignmentI alignment = alignViewport.getAlignment(); + int aWidth = alignment == null ? -1 : alignment.getWidth(); + if (aWidth < 0) + { + calcMan.workerComplete(this); + return; + } + + /* + * compute information profiles for any HMM consensus sequences + * for the alignment or sub-groups + */ + computeProfiles(alignment); + + /* + * construct the corresponding annotations + */ + updateAnnotation(); + + if (ap != null) + { + ap.adjustAnnotationHeight(); + ap.paintAlignment(true, true); + } + } catch (OutOfMemoryError error) + { + calcMan.disableWorker(this); + ap.raiseOOMWarning("calculating information", error); + } finally + { + calcMan.workerComplete(this); + } + } + + /** + * Computes HMM profiles for any HMM consensus sequences (for alignment or + * subgroups). Any alignment profile computed is stored on the viewport, any + * group profile computed is stored on the respective sequence group. + * + * @param alignment + * @see AlignViewportI#setHmmProfiles(ProfilesI) + */ + protected void computeProfiles(AlignmentI alignment) + { + int width = alignment.getWidth(); + + /* + * alignment HMM profile + */ + SequenceI seq = alignment.getHmmConsensus(); + if (seq != null) + { + HiddenMarkovModel hmm = seq.getHMM(); + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, + 0, width, alignViewport.isIgnoreBelowBackground(), + alignViewport.isInfoLetterHeight()); + alignViewport.setHmmProfiles(hmmProfiles); + } + + /* + * group HMM profiles + */ + List groups = alignment.getGroups(); + for (SequenceGroup group : groups) + { + seq = group.getHmmConsensus(); + if (seq != null) + { + HiddenMarkovModel hmm = seq.getHMM(); + ProfilesI hmmProfiles = AAFrequency.calculateHMMProfiles(hmm, width, + 0, width, group.isIgnoreBelowBackground(), + group.isUseInfoLetterHeight()); + group.setHmmProfiles(hmmProfiles); + } + } + } + + /** + * gets the sequences on the alignment on the viewport. + * + * @return + */ + protected SequenceI[] getSequences() + { + return alignViewport.getAlignment().getSequencesArray(); + } + + /** + * Get the Gap annotation for the alignment + * + * @return + */ + protected AlignmentAnnotation getGapAnnotation() + { + return alignViewport.getOccupancyAnnotation(); + } + + /** + * Computes Information Content annotation for any HMM consensus sequences + * (for alignment or groups), and updates (or adds) the annotation to the + * sequence and the alignment + */ + @Override + public void updateAnnotation() + { + AlignmentI alignment = alignViewport.getAlignment(); + + float maxInformation = 0f; + List infos = new ArrayList<>(); + + /* + * annotation for alignment HMM consensus if present + */ + SequenceI hmmSeq = alignment.getHmmConsensus(); + ProfilesI profile = alignViewport.getHmmProfiles(); + float m = updateInformationAnnotation(hmmSeq, profile, null, infos); + maxInformation = Math.max(maxInformation, m); + + /* + * annotation for group HMM consensus if present + */ + for (SequenceGroup group : alignment.getGroups()) + { + hmmSeq = group.getHmmConsensus(); + ProfilesI profiles = group.getHmmProfiles(); + m = updateInformationAnnotation(hmmSeq, profiles, group, infos); + maxInformation = Math.max(maxInformation, m); + } + + /* + * maxInformation holds the maximum value of information score; + * set this as graphMax in all annotations to scale them all the same + */ + for (AlignmentAnnotation ann : infos) + { + ann.graphMax = maxInformation; + } + } + + /** + * Updates (and first constructs if necessary) an HMM Profile information + * content annotation for a sequence. The group argument is null + * for the whole alignment annotation, not null for a subgroup annotation. The + * updated annotation is added to the infos list. Answers the + * maximum information content value of any annotation (for use as a scaling + * factor for display). + * + * @param seq + * @param profile + * @param group + * @param infos + * @return + */ + protected float updateInformationAnnotation(SequenceI seq, + ProfilesI profile, SequenceGroup group, + List infos) + { + if (seq == null || profile == null) + { + return 0f; + } + + AlignmentAnnotation ann = findOrCreateAnnotation(seq, group); + + seq.addAlignmentAnnotation(ann); + infos.add(ann); + + float max = AAFrequency.completeInformation(ann, profile, + profile.getStartColumn(), profile.getEndColumn() + 1); + + return max; + } + + /** + * A helper method that first searches for the HMM annotation that matches the + * group reference (null for the whole alignment annotation). If found, its + * sequence reference is updated to the given sequence (the recomputed HMM + * consensus sequence). If not found, it is created. This supports both + * creating the annotation the first time hmmbuild is run, and updating it if + * hmmbuild is re-run. + * + * @param seq + * @param group + * @return + */ + AlignmentAnnotation findOrCreateAnnotation(SequenceI seq, + SequenceGroup group) + { + /* + * can't use Alignment.findOrCreateAnnotation here because we + * want to update, rather than match on, the sequence ref + */ + AlignmentAnnotation info = null; + + AlignmentI alignment = alignViewport.getAlignment(); + AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation(); + if (anns != null) + { + for (AlignmentAnnotation ann : anns) + { + if (HMM_CALC_ID.equals(ann.getCalcId()) && group == ann.groupRef) + { + info = ann; + info.setSequenceRef(seq); + info.label = seq.getName(); // in case group name changed! + break; + } + } + } + + if (info == null) + { + int aWidth = alignment.getWidth(); + String desc = MessageManager + .getString("label.information_description"); + float graphMax = 6.52f; // todo where does this value derive from? + info = new AlignmentAnnotation(seq.getName(), desc, + new Annotation[aWidth], 0f, graphMax, + AlignmentAnnotation.BAR_GRAPH); + info.setCalcId(HMM_CALC_ID); + info.setSequenceRef(seq); + info.groupRef = group; + info.hasText = true; + alignment.addAnnotation(info); + } + + return info; + } +} diff --git a/src/jalview/ws/DBRefFetcher.java b/src/jalview/ws/DBRefFetcher.java index fb8864d..1677eca 100644 --- a/src/jalview/ws/DBRefFetcher.java +++ b/src/jalview/ws/DBRefFetcher.java @@ -61,6 +61,8 @@ public class DBRefFetcher implements Runnable { private static final String NEWLINE = System.lineSeparator(); + public static final String TRIM_RETRIEVED_SEQUENCES = "TRIM_FETCHED_DATASET_SEQS"; + public interface FetchFinishedListenerI { void finished(); @@ -139,7 +141,7 @@ public class DBRefFetcher implements Runnable .getSequenceFetcherSingleton(progressIndicatorFrame); // set default behaviour for transferring excess sequence data to the // dataset - trimDsSeqs = Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true); + trimDsSeqs = Cache.getDefault(TRIM_RETRIEVED_SEQUENCES, true); if (sources == null) { setDatabaseSources(featureSettings, isNucleotide); diff --git a/src/jalview/ws/dbsources/Pfam.java b/src/jalview/ws/dbsources/Pfam.java index 0227e35..8877c34 100644 --- a/src/jalview/ws/dbsources/Pfam.java +++ b/src/jalview/ws/dbsources/Pfam.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import com.stevesoft.pat.Regex; @@ -34,6 +35,9 @@ import com.stevesoft.pat.Regex; */ abstract public class Pfam extends Xfam { + static final String PFAM_BASEURL_KEY = "PFAM_BASEURL"; + + private static final String DEFAULT_PFAM_BASEURL = "https://pfam.xfam.org"; public Pfam() { @@ -48,7 +52,6 @@ abstract public class Pfam extends Xfam @Override public String getAccessionSeparator() { - // TODO Auto-generated method stub return null; } @@ -60,7 +63,6 @@ abstract public class Pfam extends Xfam @Override public Regex getAccessionValidator() { - // TODO Auto-generated method stub return null; } @@ -91,17 +93,14 @@ abstract public class Pfam extends Xfam @Override public String getDbVersion() { - // TODO Auto-generated method stub return null; } - /** - * Returns base URL for selected Pfam alignment type - * - * @return PFAM URL stub for this DbSource - */ @Override - protected abstract String getXFAMURL(); + protected String getURLPrefix() + { + return Cache.getDefault(PFAM_BASEURL_KEY, DEFAULT_PFAM_BASEURL); + } /* * (non-Javadoc) diff --git a/src/jalview/ws/dbsources/PfamFull.java b/src/jalview/ws/dbsources/PfamFull.java index ec9fcbb..0600427 100644 --- a/src/jalview/ws/dbsources/PfamFull.java +++ b/src/jalview/ws/dbsources/PfamFull.java @@ -31,20 +31,8 @@ public class PfamFull extends Pfam super(); } - /* - * (non-Javadoc) - * - * @see jalview.ws.dbsources.Pfam#getPFAMURL() - */ - @Override - protected String getXFAMURL() - { - return "http://pfam.xfam.org/family/"; - - } - @Override - public String getXFAMURLSUFFIX() + public String getURLSuffix() { return "/alignment/full"; } diff --git a/src/jalview/ws/dbsources/PfamSeed.java b/src/jalview/ws/dbsources/PfamSeed.java index 33c39b1..dff8a17 100644 --- a/src/jalview/ws/dbsources/PfamSeed.java +++ b/src/jalview/ws/dbsources/PfamSeed.java @@ -33,19 +33,8 @@ public class PfamSeed extends Pfam super(); } - /* - * (non-Javadoc) - * - * @see jalview.ws.dbsources.Pfam#getPFAMURL() - */ - @Override - protected String getXFAMURL() - { - return "http://pfam.xfam.org/family/"; - } - @Override - public String getXFAMURLSUFFIX() + public String getURLSuffix() { return "/alignment/seed"; } diff --git a/src/jalview/ws/dbsources/Rfam.java b/src/jalview/ws/dbsources/Rfam.java index 97f73d0..1d9d99a 100644 --- a/src/jalview/ws/dbsources/Rfam.java +++ b/src/jalview/ws/dbsources/Rfam.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.DBRefSource; import com.stevesoft.pat.Regex; @@ -31,6 +32,15 @@ import com.stevesoft.pat.Regex; */ abstract public class Rfam extends Xfam { + static final String RFAM_BASEURL_KEY = "RFAM_BASEURL"; + + private static final String DEFAULT_RFAM_BASEURL = "https://rfam.xfam.org"; + + @Override + protected String getURLPrefix() + { + return Cache.getDefault(RFAM_BASEURL_KEY, DEFAULT_RFAM_BASEURL); + } public Rfam() { @@ -46,7 +56,6 @@ abstract public class Rfam extends Xfam @Override public String getAccessionSeparator() { - // TODO Auto-generated method stub return null; } @@ -58,7 +67,6 @@ abstract public class Rfam extends Xfam @Override public Regex getAccessionValidator() { - // TODO Auto-generated method stub return null; } @@ -82,18 +90,9 @@ abstract public class Rfam extends Xfam @Override public String getDbVersion() { - // TODO Auto-generated method stub return null; } - /** - * Returns base URL for selected Rfam alignment type - * - * @return RFAM URL stub for this DbSource - */ - @Override - protected abstract String getXFAMURL(); - /* * (non-Javadoc) * diff --git a/src/jalview/ws/dbsources/RfamFull.java b/src/jalview/ws/dbsources/RfamFull.java index b2ca31a..d815336 100644 --- a/src/jalview/ws/dbsources/RfamFull.java +++ b/src/jalview/ws/dbsources/RfamFull.java @@ -33,20 +33,8 @@ public class RfamFull extends Rfam super(); } - /* - * (non-Javadoc) - * - * @see jalview.ws.dbsources.Rfam#getXFAMURL() - */ - @Override - protected String getXFAMURL() - { - return "http://rfam.xfam.org/family/"; - - } - @Override - public String getXFAMURLSUFFIX() + public String getURLSuffix() { return "/alignment/full"; } diff --git a/src/jalview/ws/dbsources/RfamSeed.java b/src/jalview/ws/dbsources/RfamSeed.java index f714547..a74e829 100644 --- a/src/jalview/ws/dbsources/RfamSeed.java +++ b/src/jalview/ws/dbsources/RfamSeed.java @@ -33,19 +33,8 @@ public class RfamSeed extends Rfam super(); } - /* - * (non-Javadoc) - * - * @see jalview.ws.dbsources.Rfam#getRFAMURL() - */ - @Override - protected String getXFAMURL() - { - return "http://rfam.xfam.org/family/"; - } - @Override - public String getXFAMURLSUFFIX() + public String getURLSuffix() { // to download gzipped file add '?gzip=1' return "/alignment/stockholm"; diff --git a/src/jalview/ws/dbsources/Uniprot.java b/src/jalview/ws/dbsources/Uniprot.java index 73775cf..6b09eb6 100644 --- a/src/jalview/ws/dbsources/Uniprot.java +++ b/src/jalview/ws/dbsources/Uniprot.java @@ -20,6 +20,7 @@ */ package jalview.ws.dbsources; +import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.DBRefEntry; @@ -52,6 +53,8 @@ import com.stevesoft.pat.Regex; */ public class Uniprot extends DbSourceProxyImpl { + private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org"; + private static final String BAR_DELIMITER = "|"; /* @@ -67,6 +70,11 @@ public class Uniprot extends DbSourceProxyImpl super(); } + private String getDomain() + { + return Cache.getDefault("UNIPROT_DOMAIN", DEFAULT_UNIPROT_DOMAIN); + } + /* * (non-Javadoc) * @@ -163,7 +171,7 @@ public class Uniprot extends DbSourceProxyImpl "(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", ""); AlignmentI al = null; - String downloadstring = "http://www.uniprot.org/uniprot/" + queries + String downloadstring = getDomain() + "/uniprot/" + queries + ".xml"; URL url = null; URLConnection urlconn = null; diff --git a/src/jalview/ws/dbsources/Xfam.java b/src/jalview/ws/dbsources/Xfam.java index 26291eb..b83f558 100644 --- a/src/jalview/ws/dbsources/Xfam.java +++ b/src/jalview/ws/dbsources/Xfam.java @@ -42,7 +42,12 @@ public abstract class Xfam extends DbSourceProxyImpl super(); } - protected abstract String getXFAMURL(); + /** + * the base URL for this Xfam-like service + * + * @return + */ + protected abstract String getURLPrefix(); @Override public abstract String getDbVersion(); @@ -57,8 +62,7 @@ public abstract class Xfam extends DbSourceProxyImpl // retrieved. startQuery(); // TODO: trap HTTP 404 exceptions and return null - String xfamUrl = getXFAMURL() + queries.trim().toUpperCase() - + getXFAMURLSUFFIX(); + String xfamUrl = getURL(queries); if (Cache.log != null) { @@ -83,6 +87,12 @@ public abstract class Xfam extends DbSourceProxyImpl return rcds; } + String getURL(String queries) + { + return getURLPrefix() + "/family/" + queries.trim().toUpperCase() + + getURLSuffix(); + } + /** * Pfam and Rfam provide alignments */ @@ -97,7 +107,7 @@ public abstract class Xfam extends DbSourceProxyImpl * * @return "" for most Xfam sources */ - public String getXFAMURLSUFFIX() + public String getURLSuffix() { return ""; } diff --git a/src/jalview/ws/jws1/JPredThread.java b/src/jalview/ws/jws1/JPredThread.java index a239625..23d9eb0 100644 --- a/src/jalview/ws/jws1/JPredThread.java +++ b/src/jalview/ws/jws1/JPredThread.java @@ -235,8 +235,7 @@ class JPredThread extends JWS1Thread implements WSClientI { // Adjust input view for gaps // propagate insertions into profile - alhidden = HiddenColumns.propagateInsertions(profileseq, al, - input); + alhidden = al.propagateInsertions(profileseq, input); } } } diff --git a/src/jalview/ws/jws2/MsaWSThread.java b/src/jalview/ws/jws2/MsaWSThread.java index db6e03f..c4fc66b 100644 --- a/src/jalview/ws/jws2/MsaWSThread.java +++ b/src/jalview/ws/jws2/MsaWSThread.java @@ -75,7 +75,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI /** * input */ - ArrayList seqs = new ArrayList(); + ArrayList seqs = new ArrayList<>(); /** * output @@ -139,7 +139,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI compbio.data.sequence.FastaSequence seq; for (int i = 0, n = 0; i < seqs.length; i++) { - String newname = jalview.analysis.SeqsetUtils.unique_name(i); // same // for // any @@ -379,7 +378,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI public List getJabaArguments() { - List newargs = new ArrayList(); + List newargs = new ArrayList<>(); if (preset != null && preset instanceof JabaWsParamSet) { newargs.addAll(((JabaWsParamSet) preset).getjabaArguments()); @@ -931,7 +930,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI void displayResults(boolean newFrame) { // view input or result data for each block - List alorders = new ArrayList(); + List alorders = new ArrayList<>(); SequenceI[][] results = new SequenceI[jobs.length][]; AlignmentOrder[] orders = new AlignmentOrder[jobs.length]; String lastProgram = null; @@ -981,7 +980,6 @@ class MsaWSThread extends AWS2Thread implements WSClientI if (newFrame) { displayInNewFrame(al, alorders, hidden); - } else { @@ -1077,7 +1075,7 @@ class MsaWSThread extends AWS2Thread implements WSClientI else { // construct a non-redundant ordering set - List names = new ArrayList(); + List names = new ArrayList<>(); for (int i = 0, l = alorders.size(); i < l; i++) { String orderName = " Region " + i; diff --git a/src/jalview/ws/params/ValueConstrainI.java b/src/jalview/ws/params/ValueConstrainI.java index da46745..47f454a 100644 --- a/src/jalview/ws/params/ValueConstrainI.java +++ b/src/jalview/ws/params/ValueConstrainI.java @@ -29,7 +29,7 @@ public interface ValueConstrainI public enum ValueType { - Integer, Float, String + Integer, Float, String, Double }; ValueType getType(); diff --git a/src/jalview/ws/params/simple/DoubleParameter.java b/src/jalview/ws/params/simple/DoubleParameter.java new file mode 100644 index 0000000..d6ccf46 --- /dev/null +++ b/src/jalview/ws/params/simple/DoubleParameter.java @@ -0,0 +1,89 @@ +package jalview.ws.params.simple; + +import jalview.ws.params.ParameterI; +import jalview.ws.params.ValueConstrainI; + +/** + * + * @author TZVanaalten + * + */ +public class DoubleParameter extends Option implements ParameterI +{ + Double defval; + + Double min, max; + + @Override + public ValueConstrainI getValidValue() + { + return new ValueConstrainI() + { + + @Override + public ValueType getType() + { + return ValueType.Double; + } + + @Override + public Number getMin() + { + if (min < max) + { + return min; + } + else + { + return null; + } + } + + @Override + public Number getMax() + { + if (min < max) + { + return max; + } + else + { + return null; + } + } + }; + } + + public DoubleParameter(DoubleParameter parm) + { + super(parm); + max = parm.max; + min = parm.min; + } + + public DoubleParameter(String name, String description, boolean required, + Double defValue, Double min, Double max) + { + super(name, description, required, String.valueOf(defValue), null, null, + null); + defval = defValue; + this.min = min; + this.max = max; + } + + public DoubleParameter(String name, String description, boolean required, + Double defValue, Double value, Double min, Double max) + { + super(name, description, required, String.valueOf(defValue), + String.valueOf(value), null, null); + defval = defValue; + this.min = min; + this.max = max; + } + + @Override + public DoubleParameter copy() + { + return new DoubleParameter(this); + } +} diff --git a/src/jalview/ws/params/simple/LogarithmicParameter.java b/src/jalview/ws/params/simple/LogarithmicParameter.java new file mode 100644 index 0000000..91ed03a --- /dev/null +++ b/src/jalview/ws/params/simple/LogarithmicParameter.java @@ -0,0 +1,101 @@ +package jalview.ws.params.simple; + +import jalview.ws.params.ParameterI; +import jalview.ws.params.ValueConstrainI; + +/** + * + * @author TZVanaalten + * + */ +public class LogarithmicParameter extends Option implements ParameterI +{ + Double defval; + + Double min, max; + + Double base; + + @Override + public ValueConstrainI getValidValue() + { + return new ValueConstrainI() + { + + @Override + public ValueType getType() + { + return ValueType.Double; + } + + @Override + public Number getMin() + { + if (min < max) + { + return min; + } + else + { + return null; + } + } + + @Override + public Number getMax() + { + if (min < max) + { + return max; + } + else + { + return null; + } + } + }; + } + + public LogarithmicParameter(LogarithmicParameter parm) + { + super(parm); + max = parm.max; + min = parm.min; + base = parm.base; + } + + public LogarithmicParameter(String name, String description, + boolean required, Double defValue, Double min, Double max, + Double base) + { + super(name, description, required, String.valueOf(defValue), null, null, + null); + defval = defValue; + this.min = min * 1000000; + this.max = max * 1000000; + this.base = base; + } + + public LogarithmicParameter(String name, String description, + boolean required, Double defValue, Double value, Double min, + Double max, Double base) + { + super(name, description, required, String.valueOf(defValue), + String.valueOf(value), null, null); + defval = defValue; + this.min = min * 1000000; + this.max = max * 1000000; + this.base = base; + } + + @Override + public LogarithmicParameter copy() + { + return new LogarithmicParameter(this); + } + + public Double getBase() + { + return base; + } +} diff --git a/src/jalview/ws/params/simple/StringParameter.java b/src/jalview/ws/params/simple/StringParameter.java new file mode 100644 index 0000000..1d6a37e --- /dev/null +++ b/src/jalview/ws/params/simple/StringParameter.java @@ -0,0 +1,118 @@ +package jalview.ws.params.simple; + +import jalview.ws.params.ParameterI; +import jalview.ws.params.ValueConstrainI; + +import java.net.URL; +import java.util.List; + +public class StringParameter extends Option implements ParameterI +{ + + @Override + public URL getFurtherDetails() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isRequired() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public String getDescription() + { + // TODO Auto-generated method stub + return description; + } + + @Override + public List getPossibleValues() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() + { + // TODO Auto-generated method stub + return name; + } + + @Override + public String getValue() + { + // TODO Auto-generated method stub + return value; + } + + @Override + public void setValue(String selectedItem) + { + value = selectedItem; + + } + + @Override + public ValueConstrainI getValidValue() + { + // TODO Auto-generated method stub + return new StringValueConstrain(); + } + + @Override + public ParameterI copy() + { + return new StringParameter(this); + } + + private class StringValueConstrain implements ValueConstrainI + { + + @Override + public ValueType getType() + { + return ValueType.String; + } + + @Override + public Number getMax() + { + return null; + } + + @Override + public Number getMin() + { + return null; + } + + } + + public StringParameter(StringParameter parm) + { + this.name = parm.name; + this.defvalue = parm.defvalue; + } + + public StringParameter(String name, String description, boolean required, + String defValue) + { + super(name, description, required, String.valueOf(defValue), null, null, + null); + this.defvalue = defValue; + } + + public StringParameter(String name, String description, boolean required, + String defValue, String value) + { + super(name, description, required, String.valueOf(defValue), + String.valueOf(value), null, null); + this.defvalue = defValue; + } +} diff --git a/src/jalview/ws/sifts/SiftsClient.java b/src/jalview/ws/sifts/SiftsClient.java index 68af7c3..b5f9653 100644 --- a/src/jalview/ws/sifts/SiftsClient.java +++ b/src/jalview/ws/sifts/SiftsClient.java @@ -92,14 +92,24 @@ public class SiftsClient implements SiftsClientI private CoordinateSys seqCoordSys = CoordinateSys.UNIPROT; + /** + * PDB sequence position to sequence coordinate mapping as derived from SIFTS + * record for the identified SeqCoordSys Used for lift-over from sequence + * derived from PDB (with first extracted PDBRESNUM as 'start' to the sequence + * being annotated with PDB data + */ + private jalview.datamodel.Mapping seqFromPdbMapping; + private static final int BUFFER_SIZE = 4096; - public static final int UNASSIGNED = -1; + public static final int UNASSIGNED = Integer.MIN_VALUE; private static final int PDB_RES_POS = 0; private static final int PDB_ATOM_POS = 1; + private static final int PDBE_POS = 2; + private static final String NOT_OBSERVED = "Not_Observed"; private static final String SIFTS_FTP_BASE_URL = "http://ftp.ebi.ac.uk/pub/databases/msd/sifts/xml/"; @@ -413,6 +423,11 @@ public class SiftsClient implements SiftsClientI public StructureMapping getSiftsStructureMapping(SequenceI seq, String pdbFile, String chain) throws SiftsException { + SequenceI aseq = seq; + while (seq.getDatasetSequence() != null) + { + seq = seq.getDatasetSequence(); + } structId = (chain == null) ? pdbId : pdbId + "|" + chain; System.out.println("Getting SIFTS mapping for " + structId + ": seq " + seq.getName()); @@ -435,8 +450,9 @@ public class SiftsClient implements SiftsClientI HashMap mapping = getGreedyMapping(chain, seq, ps); String mappingOutput = mappingDetails.toString(); - StructureMapping siftsMapping = new StructureMapping(seq, pdbFile, - pdbId, chain, mapping, mappingOutput); + StructureMapping siftsMapping = new StructureMapping(aseq, pdbFile, + pdbId, chain, mapping, mappingOutput, seqFromPdbMapping); + return siftsMapping; } @@ -444,8 +460,8 @@ public class SiftsClient implements SiftsClientI public HashMap getGreedyMapping(String entityId, SequenceI seq, java.io.PrintStream os) throws SiftsException { - List omitNonObserved = new ArrayList(); - int nonObservedShiftIndex = 0; + List omitNonObserved = new ArrayList<>(); + int nonObservedShiftIndex = 0,pdbeNonObserved=0; // System.out.println("Generating mappings for : " + entityId); Entity entity = null; entity = getEntityById(entityId); @@ -476,7 +492,7 @@ public class SiftsClient implements SiftsClientI TreeMap resNumMap = new TreeMap(); List segments = entity.getSegment(); SegmentHelperPojo shp = new SegmentHelperPojo(seq, mapping, resNumMap, - omitNonObserved, nonObservedShiftIndex); + omitNonObserved, nonObservedShiftIndex,pdbeNonObserved); processSegments(segments, shp); try { @@ -498,15 +514,61 @@ public class SiftsClient implements SiftsClientI { throw new SiftsException("SIFTS mapping failed"); } + // also construct a mapping object between the seq-coord sys and the PDB seq's coord sys Integer[] keys = mapping.keySet().toArray(new Integer[0]); Arrays.sort(keys); seqStart = keys[0]; seqEnd = keys[keys.length - 1]; - + List from=new ArrayList<>(),to=new ArrayList<>(); + int[]_cfrom=null,_cto=null; String matchedSeq = originalSeq; - if (seqStart != UNASSIGNED) + if (seqStart != UNASSIGNED) // fixme! seqStart can map to -1 for a pdb sequence that starts <-1 { + for (int seqps:keys) + { + int pdbpos = mapping.get(seqps)[PDBE_POS]; + if (pdbpos == UNASSIGNED) + { + // not correct - pdbpos might be -1, but leave it for now + continue; + } + if (_cfrom==null || seqps!=_cfrom[1]+1) + { + _cfrom = new int[] { seqps,seqps}; + from.add(_cfrom); + _cto = null; // discontinuity + } else { + _cfrom[1]= seqps; + } + if (_cto==null || pdbpos!=1+_cto[1]) + { + _cto = new int[] { pdbpos,pdbpos}; + to.add(_cto); + } else { + _cto[1] = pdbpos; + } + } + _cfrom = new int[from.size() * 2]; + _cto = new int[to.size() * 2]; + int p = 0; + for (int[] range : from) + { + _cfrom[p++] = range[0]; + _cfrom[p++] = range[1]; + } + ; + p = 0; + for (int[] range : to) + { + _cto[p++] = range[0]; + _cto[p++] = range[1]; + } + ; + + seqFromPdbMapping = new jalview.datamodel.Mapping(null, _cto, _cfrom, + 1, + 1); pdbStart = mapping.get(seqStart)[PDB_RES_POS]; pdbEnd = mapping.get(seqEnd)[PDB_RES_POS]; int orignalSeqStart = seq.getStart(); @@ -559,6 +621,8 @@ public class SiftsClient implements SiftsClientI TreeMap resNumMap = shp.getResNumMap(); List omitNonObserved = shp.getOmitNonObserved(); int nonObservedShiftIndex = shp.getNonObservedShiftIndex(); + int pdbeNonObservedCount = shp.getPdbeNonObserved(); + int firstPDBResNum = UNASSIGNED; for (Segment segment : segments) { // System.out.println("Mapping segments : " + segment.getSegId() + "\\"s @@ -566,6 +630,9 @@ public class SiftsClient implements SiftsClientI List residues = segment.getListResidue().getResidue(); for (Residue residue : residues) { + boolean isObserved = isResidueObserved(residue); + int pdbeIndex = getLeadingIntegerValue(residue.getDbResNum(), + UNASSIGNED); int currSeqIndex = UNASSIGNED; List cRefDbs = residue.getCrossRefDb(); CrossRefDb pdbRefDb = null; @@ -574,6 +641,19 @@ public class SiftsClient implements SiftsClientI if (cRefDb.getDbSource().equalsIgnoreCase(DBRefSource.PDB)) { pdbRefDb = cRefDb; + if (firstPDBResNum == UNASSIGNED) + { + firstPDBResNum = getLeadingIntegerValue(cRefDb.getDbResNum(), + UNASSIGNED); + } + else + { + if (isObserved) + { + // after we find the first observed residue we just increment + firstPDBResNum++; + } + } } if (cRefDb.getDbCoordSys().equalsIgnoreCase(seqCoordSys.getName()) && isAccessionMatched(cRefDb.getDbAccessionId())) @@ -586,11 +666,45 @@ public class SiftsClient implements SiftsClientI } } } + if (!isObserved) + { + ++pdbeNonObservedCount; + } + if (seqCoordSys == seqCoordSys.PDB) // FIXME: is seqCoordSys ever PDBe + // ??? + { + // if the sequence has a primary reference to the PDB, then we are + // dealing with a sequence extracted directly from the PDB. In that + // case, numbering is PDBe - non-observed residues + currSeqIndex = seq.getStart() - 1 + pdbeIndex; + } + if (!isObserved) + { + if (seqCoordSys != CoordinateSys.UNIPROT) // FIXME: PDB or PDBe only + // here + { + // mapping to PDB or PDBe so we need to bookkeep for the + // non-observed + // SEQRES positions + omitNonObserved.add(currSeqIndex); + ++nonObservedShiftIndex; + } + } if (currSeqIndex == UNASSIGNED) { + // change in logic - unobserved residues with no currSeqIndex + // corresponding are still counted in both nonObservedShiftIndex and + // pdbeIndex... continue; } - if (currSeqIndex >= seq.getStart() && currSeqIndex <= seq.getEnd()) + // if (currSeqIndex >= seq.getStart() && currSeqIndex <= seqlength) // + // true + // numbering + // is + // not + // up + // to + // seq.getEnd() { int resNum = (pdbRefDb == null) @@ -599,22 +713,18 @@ public class SiftsClient implements SiftsClientI : getLeadingIntegerValue(pdbRefDb.getDbResNum(), UNASSIGNED); - if (isResidueObserved(residue) - || seqCoordSys == CoordinateSys.UNIPROT) + if (isObserved) { char resCharCode = ResidueProperties .getSingleCharacterCode(ResidueProperties .getCanonicalAminoAcid(residue.getDbResName())); resNumMap.put(currSeqIndex, String.valueOf(resCharCode)); + + int[] mappingcols = new int[] { Integer.valueOf(resNum), + UNASSIGNED, isObserved ? firstPDBResNum : UNASSIGNED }; + + mapping.put(currSeqIndex - nonObservedShiftIndex, mappingcols); } - else - { - omitNonObserved.add(currSeqIndex); - ++nonObservedShiftIndex; - } - mapping.put(currSeqIndex - nonObservedShiftIndex, - new int[] - { Integer.valueOf(resNum), UNASSIGNED }); } } } @@ -904,17 +1014,36 @@ public class SiftsClient implements SiftsClientI private int nonObservedShiftIndex; + /** + * count of number of 'not observed' positions in the PDB record's SEQRES + * (total number of residues with coordinates == length(SEQRES) - + * pdbeNonObserved + */ + private int pdbeNonObserved; + public SegmentHelperPojo(SequenceI seq, HashMap mapping, TreeMap resNumMap, - List omitNonObserved, int nonObservedShiftIndex) + List omitNonObserved, int nonObservedShiftIndex, + int pdbeNonObserved) { setSeq(seq); setMapping(mapping); setResNumMap(resNumMap); setOmitNonObserved(omitNonObserved); setNonObservedShiftIndex(nonObservedShiftIndex); + setPdbeNonObserved(pdbeNonObserved); + } + public void setPdbeNonObserved(int pdbeNonObserved2) + { + this.pdbeNonObserved = pdbeNonObserved2; + } + + public int getPdbeNonObserved() + { + return pdbeNonObserved; + } public SequenceI getSeq() { return seq; @@ -964,6 +1093,7 @@ public class SiftsClient implements SiftsClientI { this.nonObservedShiftIndex = nonObservedShiftIndex; } + } @Override diff --git a/test/jalview/analysis/AAFrequencyTest.java b/test/jalview/analysis/AAFrequencyTest.java index 75fb39e..2b6c512 100644 --- a/test/jalview/analysis/AAFrequencyTest.java +++ b/test/jalview/analysis/AAFrequencyTest.java @@ -25,17 +25,27 @@ import static org.testng.AssertJUnit.assertNull; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.Profile; import jalview.datamodel.ProfileI; +import jalview.datamodel.Profiles; import jalview.datamodel.ProfilesI; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; + +import java.io.IOException; +import java.net.MalformedURLException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class AAFrequencyTest { + HiddenMarkovModel hmm; @BeforeClass(alwaysRun = true) public void setUpJvOptionPane() @@ -44,6 +54,17 @@ public class AAFrequencyTest JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } + @BeforeClass(alwaysRun = true) + public void setUp() throws IOException, MalformedURLException + { + /* + * load a dna (ACGT) HMM file to a HiddenMarkovModel + */ + HMMFile hmmFile = new HMMFile(new FileParse( + "test/jalview/io/test_MADE1_hmm.txt", DataSourceType.FILE)); + hmm = hmmFile.getHMM(); + } + @Test(groups = { "Functional" }) public void testCalculate_noProfile() { @@ -232,4 +253,94 @@ public class AAFrequencyTest assertEquals("T 75%", ann.description); assertEquals("T", ann.displayCharacter); } + + @Test(groups = { "Functional" }) + public void testExtractHMMProfile() + throws MalformedURLException, IOException + { + int[] expected = { 0, 4, 100, 'T', 71, 'C', 12, 'G', 9, 'A', 9 }; + int[] actual = AAFrequency.extractHMMProfile(hmm, 17, false, false); + for (int i = 0; i < actual.length; i++) + { + if (i == 2) + { + assertEquals(actual[i], expected[i]); + } + else + { + assertEquals(actual[i], expected[i]); + } + } + + int[] expected2 = { 0, 4, 100, 'A', 85, 'C', 0, 'G', 0, 'T', 0 }; + int[] actual2 = AAFrequency.extractHMMProfile(hmm, 2, true, false); + for (int i = 0; i < actual2.length; i++) + { + if (i == 2) + { + assertEquals(actual[i], expected[i]); + } + else + { + assertEquals(actual[i], expected[i]); + } + } + + assertNull(AAFrequency.extractHMMProfile(null, 98978867, true, false)); + } + + @Test(groups = { "Functional" }) + public void testGetAnalogueCount() + { + /* + * 'T' in column 0 has emission probability 0.7859, scales to 7859 + */ + int count = AAFrequency.getAnalogueCount(hmm, 0, 'T', false, false); + assertEquals(7859, count); + + /* + * same with 'use info height': value is multiplied by log ratio + * log(value / background) / log(2) = log(0.7859/0.25)/0.693 + * = log(3.1)/0.693 = 1.145/0.693 = 1.66 + * so value becomes 1.2987 and scales up to 12987 + */ + count = AAFrequency.getAnalogueCount(hmm, 0, 'T', false, true); + assertEquals(12987, count); + + /* + * 'G' in column 20 has emission probability 0.75457, scales to 7546 + */ + count = AAFrequency.getAnalogueCount(hmm, 20, 'G', false, false); + assertEquals(7546, count); + + /* + * 'G' in column 1077 has emission probability 0.0533, here + * ignored (set to 0) since below background of 0.25 + */ + count = AAFrequency.getAnalogueCount(hmm, 1077, 'G', true, false); + assertEquals(0, count); + } + + @Test(groups = { "Functional" }) + public void testCompleteInformation() + { + ProfileI prof1 = new Profile(1, 0, 100, "A"); + ProfileI prof2 = new Profile(1, 0, 100, "-"); + + ProfilesI profs = new Profiles(new ProfileI[] { prof1, prof2 }); + Annotation ann1 = new Annotation(6.5f); + Annotation ann2 = new Annotation(0f); + Annotation[] annots = new Annotation[] { ann1, ann2 }; + SequenceI seq = new Sequence("", "AA", 0, 0); + seq.setHMM(hmm); + AlignmentAnnotation annot = new AlignmentAnnotation("", "", annots); + annot.setSequenceRef(seq); + AAFrequency.completeInformation(annot, profs, 0, 1); + float ic = annot.annotations[0].value; + assertEquals(0.91532f, ic, 0.0001f); + ic = annot.annotations[1].value; + assertEquals(0f, ic, 0.0001f); + int i = 0; + } + } diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index 37b93fd..92bf0ce 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -48,6 +48,7 @@ import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileFormatI; import jalview.io.FormatAdapter; +import jalview.io.gff.SequenceOntologyI; import jalview.util.MapList; import jalview.util.MappingUtils; @@ -2082,6 +2083,7 @@ public class AlignmentUtilsTests List codon1Variants = new ArrayList<>(); List codon2Variants = new ArrayList<>(); List codon3Variants = new ArrayList<>(); + List codonVariants[] = new ArrayList[3]; codonVariants[0] = codon1Variants; codonVariants[1] = codon2Variants; @@ -2734,7 +2736,7 @@ public class AlignmentUtilsTests * Case 2: CDS 3 times length of peptide + stop codon * (note code does not currently check trailing codon is a stop codon) */ - dna = new Sequence("dna", "AACGacgtCTCCTTGA"); + dna = new Sequence("dna", "AACGacgtCTCCTCCC"); dna.createDatasetSequence(); dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null)); dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 16, null)); @@ -2747,17 +2749,42 @@ public class AlignmentUtilsTests Arrays.deepToString(ml.getFromRanges().toArray())); /* - * Case 3: CDS not 3 times length of peptide - no mapping is made + * Case 3: CDS longer than 3 * peptide + stop codon - no mapping is made + */ + dna = new Sequence("dna", "AACGacgtCTCCTTGATCA"); + dna.createDatasetSequence(); + dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null)); + dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 19, null)); + ml = AlignmentUtils.mapCdsToProtein(dna, peptide); + assertNull(ml); + + /* + * Case 4: CDS shorter than 3 * peptide - no mapping is made + */ + dna = new Sequence("dna", "AACGacgtCTCC"); + dna.createDatasetSequence(); + dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null)); + dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 12, null)); + ml = AlignmentUtils.mapCdsToProtein(dna, peptide); + assertNull(ml); + + /* + * Case 5: CDS 3 times length of peptide + part codon - mapping is truncated */ dna = new Sequence("dna", "AACGacgtCTCCTTG"); dna.createDatasetSequence(); dna.addSequenceFeature(new SequenceFeature("CDS", "", 1, 4, null)); dna.addSequenceFeature(new SequenceFeature("CDS", "", 9, 15, null)); ml = AlignmentUtils.mapCdsToProtein(dna, peptide); - assertNull(ml); + assertEquals(3, ml.getFromRatio()); + assertEquals(1, ml.getToRatio()); + assertEquals("[[1, 3]]", + Arrays.deepToString(ml.getToRanges().toArray())); + assertEquals("[[1, 4], [9, 13]]", + Arrays.deepToString(ml.getFromRanges().toArray())); /* - * Case 4: incomplete start codon corresponding to X in peptide + * Case 6: incomplete start codon corresponding to X in peptide */ dna = new Sequence("dna", "ACGacgtCTCCTTGG"); dna.createDatasetSequence(); @@ -2772,4 +2799,152 @@ public class AlignmentUtilsTests assertEquals("[[3, 3], [8, 12]]", Arrays.deepToString(ml.getFromRanges().toArray())); } + + /** + * Tests for the method that locates the CDS sequence that has a mapping to + * the given protein. That is, given a transcript-to-peptide mapping, find the + * cds-to-peptide mapping that relates to both, and return the CDS sequence. + */ + @Test + public void testFindCdsForProtein() + { + List mappings = new ArrayList<>(); + AlignedCodonFrame acf1 = new AlignedCodonFrame(); + mappings.add(acf1); + + SequenceI dna1 = new Sequence("dna1", "cgatATcgGCTATCTATGacg"); + dna1.createDatasetSequence(); + + // NB we currently exclude STOP codon from CDS sequences + // the test would need to change if this changes in future + SequenceI cds1 = new Sequence("cds1", "ATGCTATCT"); + cds1.createDatasetSequence(); + + SequenceI pep1 = new Sequence("pep1", "MLS"); + pep1.createDatasetSequence(); + List seqMappings = new ArrayList<>(); + MapList mapList = new MapList( + new int[] + { 5, 6, 9, 15 }, new int[] { 1, 3 }, 3, 1); + Mapping dnaToPeptide = new Mapping(pep1.getDatasetSequence(), mapList); + + // add dna to peptide mapping + seqMappings.add(acf1); + acf1.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), + mapList); + + /* + * first case - no dna-to-CDS mapping exists - search fails + */ + SequenceI seq = AlignmentUtils.findCdsForProtein(mappings, dna1, + seqMappings, dnaToPeptide); + assertNull(seq); + + /* + * second case - CDS-to-peptide mapping exists but no dna-to-CDS + * - search fails + */ + // todo this test fails if the mapping is added to acf1, not acf2 + // need to tidy up use of lists of mappings in AlignedCodonFrame + AlignedCodonFrame acf2 = new AlignedCodonFrame(); + mappings.add(acf2); + MapList cdsToPeptideMapping = new MapList(new int[] + { 1, 9 }, new int[] { 1, 3 }, 3, 1); + acf2.addMap(cds1.getDatasetSequence(), pep1.getDatasetSequence(), + cdsToPeptideMapping); + assertNull(AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings, + dnaToPeptide)); + + /* + * third case - add dna-to-CDS mapping - CDS is now found! + */ + MapList dnaToCdsMapping = new MapList(new int[] { 5, 6, 9, 15 }, + new int[] + { 1, 9 }, 1, 1); + acf1.addMap(dna1.getDatasetSequence(), cds1.getDatasetSequence(), + dnaToCdsMapping); + seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings, + dnaToPeptide); + assertSame(seq, cds1.getDatasetSequence()); + } + + /** + * Tests for the method that locates the CDS sequence that has a mapping to + * the given protein. That is, given a transcript-to-peptide mapping, find the + * cds-to-peptide mapping that relates to both, and return the CDS sequence. + * This test is for the case where transcript and CDS are the same length. + */ + @Test + public void testFindCdsForProtein_noUTR() + { + List mappings = new ArrayList<>(); + AlignedCodonFrame acf1 = new AlignedCodonFrame(); + mappings.add(acf1); + + SequenceI dna1 = new Sequence("dna1", "ATGCTATCTTAA"); + dna1.createDatasetSequence(); + + // NB we currently exclude STOP codon from CDS sequences + // the test would need to change if this changes in future + SequenceI cds1 = new Sequence("cds1", "ATGCTATCT"); + cds1.createDatasetSequence(); + + SequenceI pep1 = new Sequence("pep1", "MLS"); + pep1.createDatasetSequence(); + List seqMappings = new ArrayList<>(); + MapList mapList = new MapList( + new int[] + { 1, 9 }, new int[] { 1, 3 }, 3, 1); + Mapping dnaToPeptide = new Mapping(pep1.getDatasetSequence(), mapList); + + // add dna to peptide mapping + seqMappings.add(acf1); + acf1.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), + mapList); + + /* + * first case - transcript lacks CDS features - it appears to be + * the CDS sequence and is returned + */ + SequenceI seq = AlignmentUtils.findCdsForProtein(mappings, dna1, + seqMappings, dnaToPeptide); + assertSame(seq, dna1.getDatasetSequence()); + + /* + * second case - transcript has CDS feature - this means it is + * not returned as a match for CDS (CDS sequences don't have CDS features) + */ + dna1.addSequenceFeature( + new SequenceFeature(SequenceOntologyI.CDS, "cds", 1, 12, null)); + seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings, + dnaToPeptide); + assertNull(seq); + + /* + * third case - CDS-to-peptide mapping exists but no dna-to-CDS + * - search fails + */ + // todo this test fails if the mapping is added to acf1, not acf2 + // need to tidy up use of lists of mappings in AlignedCodonFrame + AlignedCodonFrame acf2 = new AlignedCodonFrame(); + mappings.add(acf2); + MapList cdsToPeptideMapping = new MapList(new int[] + { 1, 9 }, new int[] { 1, 3 }, 3, 1); + acf2.addMap(cds1.getDatasetSequence(), pep1.getDatasetSequence(), + cdsToPeptideMapping); + assertNull(AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings, + dnaToPeptide)); + + /* + * fourth case - add dna-to-CDS mapping - CDS is now found! + */ + MapList dnaToCdsMapping = new MapList(new int[] { 1, 9 }, + new int[] + { 1, 9 }, 1, 1); + acf1.addMap(dna1.getDatasetSequence(), cds1.getDatasetSequence(), + dnaToCdsMapping); + seq = AlignmentUtils.findCdsForProtein(mappings, dna1, seqMappings, + dnaToPeptide); + assertSame(seq, cds1.getDatasetSequence()); + } } diff --git a/test/jalview/analysis/CrossRefTest.java b/test/jalview/analysis/CrossRefTest.java index 95be1ff..0265af3 100644 --- a/test/jalview/analysis/CrossRefTest.java +++ b/test/jalview/analysis/CrossRefTest.java @@ -106,7 +106,7 @@ public class CrossRefTest public void testFindXrefSourcesForSequence_proteinToDna() { SequenceI seq = new Sequence("Seq1", "MGKYQARLSS"); - List sources = new ArrayList(); + List sources = new ArrayList<>(); AlignmentI al = new Alignment(new SequenceI[] {}); /* @@ -132,8 +132,9 @@ public class CrossRefTest sources = new CrossRef(new SequenceI[] { seq }, al) .findXrefSourcesForSequences(false); // method is patched to remove EMBL from the sources to match - assertEquals(3, sources.size()); - assertEquals("[EMBLCDS, GENEDB, ENSEMBL]", sources.toString()); + assertEquals(4, sources.size()); + assertEquals("[EMBLCDS, GENEDB, ENSEMBL, ENSEMBLGENOMES]", + sources.toString()); /* * add a sequence to the alignment which has a dbref to UNIPROT|A1234 @@ -270,7 +271,7 @@ public class CrossRefTest pep1.addDBRef(new DBRefEntry("UNIPROT", "0", "Q9ZTS2")); AlignmentI al = new Alignment(new SequenceI[] { dna1, pep1 }); - List result = new ArrayList(); + List result = new ArrayList<>(); /* * first search for a dbref nowhere on the alignment: diff --git a/test/jalview/analysis/DnaTest.java b/test/jalview/analysis/DnaTest.java index d2fa99a..6a31b31 100644 --- a/test/jalview/analysis/DnaTest.java +++ b/test/jalview/analysis/DnaTest.java @@ -38,6 +38,7 @@ import jalview.io.FileFormat; import jalview.io.FormatAdapter; import java.io.IOException; +import java.util.Iterator; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -135,7 +136,9 @@ public class DnaTest FileFormat.Fasta); HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(alf, cs); - Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); + Iterator contigs = cs.getVisContigsIterator(0, alf.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); assertNotNull("Couldn't do a full width translation of test data.", translated); @@ -163,7 +166,8 @@ public class DnaTest cs.hideColumns(0, ipos - 1); } cs.hideColumns(ipos + vwidth, alf.getWidth()); - int[] vcontigs = cs.getVisibleContigs(0, alf.getWidth()); + Iterator vcontigs = cs.getVisContigsIterator(0, + alf.getWidth(), false); AlignViewportI av = new AlignViewport(alf, cs); Dna dna = new Dna(av, vcontigs); AlignmentI transAlf = dna.translateCdna(); @@ -190,7 +194,9 @@ public class DnaTest DataSourceType.PASTE, FileFormat.Fasta); HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(alf, cs); - Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); + Iterator contigs = cs.getVisContigsIterator(0, alf.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); String aa = translated.getSequenceAt(0).getSequenceAsString(); assertEquals( @@ -213,7 +219,9 @@ public class DnaTest cs.hideColumns(24, 35); // hide codons 9-12 cs.hideColumns(177, 191); // hide codons 60-64 AlignViewportI av = new AlignViewport(alf, cs); - Dna dna = new Dna(av, new int[] { 0, alf.getWidth() - 1 }); + Iterator contigs = cs.getVisContigsIterator(0, alf.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); String aa = translated.getSequenceAt(0).getSequenceAsString(); assertEquals("AACDDGGGGHHIIIKKLLLLLLMNNPPPPQQRRRRRRSSSSSSTTTTVVVVW", aa); @@ -298,7 +306,9 @@ public class DnaTest .generate(12, 8, 97, 5, 5); HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(cdna, cs); - Dna dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 }); + Iterator contigs = cs.getVisContigsIterator(0, cdna.getWidth(), + false); + Dna dna = new Dna(av, contigs); AlignmentI translated = dna.translateCdna(); /* @@ -313,7 +323,8 @@ public class DnaTest } AlignmentI cdnaReordered = new Alignment(sorted); av = new AlignViewport(cdnaReordered, cs); - dna = new Dna(av, new int[] { 0, cdna.getWidth() - 1 }); + contigs = cs.getVisContigsIterator(0, cdna.getWidth(), false); + dna = new Dna(av, contigs); AlignmentI translated2 = dna.translateCdna(); /* @@ -544,7 +555,9 @@ public class DnaTest HiddenColumns cs = new HiddenColumns(); AlignViewportI av = new AlignViewport(al, cs); - Dna testee = new Dna(av, new int[] { 0, al.getWidth() - 1 }); + Iterator contigs = cs.getVisContigsIterator(0, al.getWidth(), + false); + Dna testee = new Dna(av, contigs); AlignmentI reversed = testee.reverseCdna(false); assertEquals(1, reversed.getHeight()); assertEquals(seqRev, reversed.getSequenceAt(0).getSequenceAsString()); diff --git a/test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java b/test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java index 16ca70d..a1623f6 100644 --- a/test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java +++ b/test/jalview/analysis/scoremodels/FeatureDistanceModelTest.java @@ -23,6 +23,7 @@ package jalview.analysis.scoremodels; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import jalview.api.AlignViewportI; import jalview.api.analysis.ScoreModelI; import jalview.api.analysis.SimilarityParamsI; import jalview.datamodel.Alignment; @@ -32,7 +33,6 @@ import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.gui.JvOptionPane; import jalview.io.DataSourceType; import jalview.io.FileLoader; @@ -280,7 +280,7 @@ public class FeatureDistanceModelTest public void testFindDistances_withParams() { AlignFrame af = setupAlignmentView(); - AlignViewport viewport = af.getViewport(); + AlignViewportI viewport = af.getViewport(); AlignmentView view = viewport.getAlignmentView(false); ScoreModelI sm = new FeatureDistanceModel(); diff --git a/test/jalview/datamodel/AlignmentAnnotationTests.java b/test/jalview/datamodel/AlignmentAnnotationTests.java index e47e9d6..19a725e 100644 --- a/test/jalview/datamodel/AlignmentAnnotationTests.java +++ b/test/jalview/datamodel/AlignmentAnnotationTests.java @@ -20,8 +20,8 @@ */ package jalview.datamodel; +import static org.testng.Assert.assertNull; import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertNull; import jalview.analysis.AlignSeq; import jalview.gui.JvOptionPane; @@ -335,4 +335,92 @@ public class AlignmentAnnotationTests Assert.assertTrue(ann.isQuantitative(), "Mixed 'E' annotation set should be quantitative."); } + + @Test(groups = "Functional") + public void testMakeVisibleAnnotation() + { + HiddenColumns h = new HiddenColumns(); + Annotation[] anns = new Annotation[] { null, null, new Annotation(1), + new Annotation(2), new Annotation(3), null, null, new Annotation(4), + new Annotation(5), new Annotation(6), new Annotation(7), + new Annotation(8) }; + AlignmentAnnotation ann = new AlignmentAnnotation("an", "some an", + anns); + + // null annotations + AlignmentAnnotation emptyann = new AlignmentAnnotation("an", "some ann", + null); + emptyann.makeVisibleAnnotation(h); + assertNull(emptyann.annotations); + + emptyann.makeVisibleAnnotation(3, 4, h); + assertNull(emptyann.annotations); + + // without bounds, does everything + ann.makeVisibleAnnotation(h); + assertEquals(12, ann.annotations.length); + assertNull(ann.annotations[0]); + assertNull(ann.annotations[1]); + assertEquals(1.0f, ann.annotations[2].value); + assertEquals(2.0f, ann.annotations[3].value); + assertEquals(3.0f, ann.annotations[4].value); + assertNull(ann.annotations[5]); + assertNull(ann.annotations[6]); + assertEquals(4.0f, ann.annotations[7].value); + assertEquals(5.0f, ann.annotations[8].value); + assertEquals(6.0f, ann.annotations[9].value); + assertEquals(7.0f, ann.annotations[10].value); + assertEquals(8.0f, ann.annotations[11].value); + + // without hidden cols, just truncates + ann.makeVisibleAnnotation(3, 5, h); + assertEquals(3, ann.annotations.length); + assertEquals(2.0f, ann.annotations[0].value); + assertEquals(3.0f, ann.annotations[1].value); + assertNull(ann.annotations[2]); + + anns = new Annotation[] { null, null, new Annotation(1), + new Annotation(2), new Annotation(3), null, null, new Annotation(4), + new Annotation(5), new Annotation(6), new Annotation(7), + new Annotation(8) }; + ann = new AlignmentAnnotation("an", "some an", anns); + h.hideColumns(4, 7); + ann.makeVisibleAnnotation(1, 9, h); + assertEquals(5, ann.annotations.length); + assertNull(ann.annotations[0]); + assertEquals(1.0f, ann.annotations[1].value); + assertEquals(2.0f, ann.annotations[2].value); + assertEquals(5.0f, ann.annotations[3].value); + assertEquals(6.0f, ann.annotations[4].value); + + anns = new Annotation[] { null, null, new Annotation(1), + new Annotation(2), new Annotation(3), null, null, new Annotation(4), + new Annotation(5), new Annotation(6), new Annotation(7), + new Annotation(8) }; + ann = new AlignmentAnnotation("an", "some an", anns); + h.hideColumns(1, 2); + ann.makeVisibleAnnotation(1, 9, h); + assertEquals(3, ann.annotations.length); + assertEquals(2.0f, ann.annotations[0].value); + assertEquals(5.0f, ann.annotations[1].value); + assertEquals(6.0f, ann.annotations[2].value); + + anns = new Annotation[] { null, null, new Annotation(1), + new Annotation(2), new Annotation(3), null, null, new Annotation(4), + new Annotation(5), new Annotation(6), new Annotation(7), + new Annotation(8), new Annotation(9), new Annotation(10), + new Annotation(11), new Annotation(12), new Annotation(13), + new Annotation(14), new Annotation(15) }; + ann = new AlignmentAnnotation("an", "some an", anns); + h = new HiddenColumns(); + h.hideColumns(5, 18); + h.hideColumns(20, 21); + ann.makeVisibleAnnotation(1, 21, h); + assertEquals(5, ann.annotations.length); + assertEquals(1.0f, ann.annotations[1].value); + assertEquals(2.0f, ann.annotations[2].value); + assertEquals(3.0f, ann.annotations[3].value); + assertNull(ann.annotations[0]); + assertNull(ann.annotations[4]); + } } diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index 4b5d096..0f6b129 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -34,6 +34,7 @@ import jalview.io.DataSourceType; import jalview.io.FileFormat; import jalview.io.FileFormatI; import jalview.io.FormatAdapter; +import jalview.util.Comparison; import jalview.util.MapList; import java.io.IOException; @@ -247,7 +248,9 @@ public class AlignmentTest if (raiseAssert) { Assert.fail(message - + " DBRefEntry for sequence in alignment had map to sequence not in dataset"); + + " DBRefEntry " + dbr + " for sequence " + + seqds + + " in alignment has map to sequence not in dataset"); } return false; } @@ -668,6 +671,17 @@ public class AlignmentTest // third found.. so assertFalse(iter.hasNext()); + // search for annotation on one sequence with a particular label - expect + // one + SequenceI sqfound; + anns = al.findAnnotations(sqfound = al.getSequenceAt(1), null, + "Secondary Structure"); + iter = anns.iterator(); + assertTrue(iter.hasNext()); + // expect reference to sequence 1 in the alignment + assertTrue(sqfound == iter.next().sequenceRef); + assertFalse(iter.hasNext()); + // null on all parameters == find all annotations anns = al.findAnnotations(null, null, null); iter = anns.iterator(); @@ -1321,4 +1335,153 @@ public class AlignmentTest // todo test coverage for annotations, mappings, groups, // hidden sequences, properties } + + /** + * test that calcId == null on findOrCreate doesn't raise an NPE, and yields + * an annotation with a null calcId + * + */ + @Test(groups = "Functional") + public void testFindOrCreateForNullCalcId() + { + SequenceI seq = new Sequence("seq1", "FRMLPSRT-A--L-"); + AlignmentI alignment = new Alignment(new SequenceI[] { seq }); + + AlignmentAnnotation ala = alignment.findOrCreateAnnotation( + "Temperature Factor", null, false, seq, null); + assertNotNull(ala); + assertEquals(seq, ala.sequenceRef); + assertEquals("", ala.getCalcId()); + } + + @Test(groups = "Functional") + public void testPropagateInsertions() + { + // create an alignment with no gaps - this will be the profile seq and other + // JPRED seqs + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(25, 10, 1234, 0, 0); + + // get the profileseq + SequenceI profileseq = al.getSequenceAt(0); + SequenceI gappedseq = new Sequence(profileseq); + gappedseq.insertCharAt(5, al.getGapCharacter()); + gappedseq.insertCharAt(6, al.getGapCharacter()); + gappedseq.insertCharAt(7, al.getGapCharacter()); + gappedseq.insertCharAt(8, al.getGapCharacter()); + + // force different kinds of padding + al.getSequenceAt(3).deleteChars(2, 23); + al.getSequenceAt(4).deleteChars(2, 27); + al.getSequenceAt(5).deleteChars(10, 27); + + // create an alignment view with the gapped sequence + SequenceI[] seqs = new SequenceI[1]; + seqs[0] = gappedseq; + AlignmentI newal = new Alignment(seqs); + HiddenColumns hidden = new HiddenColumns(); + hidden.hideColumns(15, 17); + + AlignmentView view = new AlignmentView(newal, hidden, null, true, false, + false); + + // confirm that original contigs are as expected + Iterator visible = hidden.getVisContigsIterator(0, 25, false); + int[] region = visible.next(); + assertEquals("[0, 14]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[18, 24]", Arrays.toString(region)); + + // propagate insertions + HiddenColumns result = al.propagateInsertions(profileseq, view); + + // confirm that the contigs have changed to account for the gaps + visible = result.getVisContigsIterator(0, 25, false); + region = visible.next(); + assertEquals("[0, 10]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[14, 24]", Arrays.toString(region)); + + // confirm the alignment has been changed so that the other sequences have + // gaps inserted where the columns are hidden + assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[10])); + assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[11])); + assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[12])); + assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[13])); + assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[14])); + + } + + @Test(groups = "Functional") + public void testPropagateInsertionsOverlap() + { + // test propagateInsertions where gaps and hiddenColumns overlap + + // create an alignment with no gaps - this will be the profile seq and other + // JPRED seqs + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(20, 10, 1234, 0, 0); + + // get the profileseq + SequenceI profileseq = al.getSequenceAt(0); + SequenceI gappedseq = new Sequence(profileseq); + gappedseq.insertCharAt(5, al.getGapCharacter()); + gappedseq.insertCharAt(6, al.getGapCharacter()); + gappedseq.insertCharAt(7, al.getGapCharacter()); + gappedseq.insertCharAt(8, al.getGapCharacter()); + + // create an alignment view with the gapped sequence + SequenceI[] seqs = new SequenceI[1]; + seqs[0] = gappedseq; + AlignmentI newal = new Alignment(seqs); + + // hide columns so that some overlap with the gaps + HiddenColumns hidden = new HiddenColumns(); + hidden.hideColumns(7, 10); + + AlignmentView view = new AlignmentView(newal, hidden, null, true, false, + false); + + // confirm that original contigs are as expected + Iterator visible = hidden.getVisContigsIterator(0, 20, false); + int[] region = visible.next(); + assertEquals("[0, 6]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[11, 19]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // propagate insertions + HiddenColumns result = al.propagateInsertions(profileseq, view); + + // confirm that the contigs have changed to account for the gaps + visible = result.getVisContigsIterator(0, 20, false); + region = visible.next(); + assertEquals("[0, 4]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[7, 19]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // confirm the alignment has been changed so that the other sequences have + // gaps inserted where the columns are hidden + assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[4])); + assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[5])); + assertTrue(Comparison.isGap(al.getSequenceAt(1).getSequence()[6])); + assertFalse(Comparison.isGap(al.getSequenceAt(1).getSequence()[7])); + } + + @Test(groups = { "Functional" }) + public void testPadGaps() + { + SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); + SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); + SequenceI seq3 = new Sequence("seq2", "-PQR"); + AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); + a.setGapCharacter('.'); // this replaces existing gaps + assertEquals("ABCDEF..", seq1.getSequenceAsString()); + a.padGaps(); + // trailing gaps are pruned, short sequences padded with gap character + assertEquals("ABCDEF.", seq1.getSequenceAsString()); + assertEquals(".JKLMNO", seq2.getSequenceAsString()); + assertEquals(".PQR...", seq3.getSequenceAsString()); + } } diff --git a/test/jalview/datamodel/AlignmentViewTest.java b/test/jalview/datamodel/AlignmentViewTest.java index b201c7e..9be344c 100644 --- a/test/jalview/datamodel/AlignmentViewTest.java +++ b/test/jalview/datamodel/AlignmentViewTest.java @@ -23,10 +23,10 @@ package jalview.datamodel; import static org.testng.Assert.assertEquals; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.gui.JvOptionPane; import jalview.io.DataSourceType; import jalview.io.FileLoader; +import jalview.viewmodel.AlignmentViewport; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -60,7 +60,7 @@ public class AlignmentViewTest { AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( ">s1\n0123456789\n", DataSourceType.PASTE); - AlignViewport av = af.getViewport(); + AlignmentViewport av = af.getViewport(); AlignmentView view = av.getAlignmentView(true); /* diff --git a/test/jalview/datamodel/ColumnSelectionTest.java b/test/jalview/datamodel/ColumnSelectionTest.java index e99e952..8709961 100644 --- a/test/jalview/datamodel/ColumnSelectionTest.java +++ b/test/jalview/datamodel/ColumnSelectionTest.java @@ -32,6 +32,7 @@ import java.util.Arrays; import java.util.BitSet; import java.util.Collections; import java.util.ConcurrentModificationException; +import java.util.Iterator; import java.util.List; import org.testng.annotations.BeforeClass; @@ -132,9 +133,9 @@ public class ColumnSelectionTest // hide column 5 (and adjacent): cs.hideSelectedColumns(5, al.getHiddenColumns()); // 4,5,6 now hidden: - List hidden = al.getHiddenColumns().getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); + Iterator regions = al.getHiddenColumns().iterator(); + assertEquals(1, al.getHiddenColumns().getNumberOfRegions()); + assertEquals("[4, 6]", Arrays.toString(regions.next())); // none now selected: assertTrue(cs.getSelected().isEmpty()); @@ -145,9 +146,9 @@ public class ColumnSelectionTest cs.addElement(5); cs.addElement(6); cs.hideSelectedColumns(4, al.getHiddenColumns()); - hidden = al.getHiddenColumns().getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); + regions = al.getHiddenColumns().iterator(); + assertEquals(1, al.getHiddenColumns().getNumberOfRegions()); + assertEquals("[4, 6]", Arrays.toString(regions.next())); assertTrue(cs.getSelected().isEmpty()); // repeat, hiding column (4, 5 and) 6 @@ -157,9 +158,9 @@ public class ColumnSelectionTest cs.addElement(5); cs.addElement(6); cs.hideSelectedColumns(6, al.getHiddenColumns()); - hidden = al.getHiddenColumns().getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); + regions = al.getHiddenColumns().iterator(); + assertEquals(1, al.getHiddenColumns().getNumberOfRegions()); + assertEquals("[4, 6]", Arrays.toString(regions.next())); assertTrue(cs.getSelected().isEmpty()); // repeat, with _only_ adjacent columns selected @@ -168,9 +169,9 @@ public class ColumnSelectionTest cs.addElement(4); cs.addElement(6); cs.hideSelectedColumns(5, al.getHiddenColumns()); - hidden = al.getHiddenColumns().getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[4, 6]", Arrays.toString(hidden.get(0))); + regions = al.getHiddenColumns().iterator(); + assertEquals(1, al.getHiddenColumns().getNumberOfRegions()); + assertEquals("[4, 6]", Arrays.toString(regions.next())); assertTrue(cs.getSelected().isEmpty()); } @@ -196,12 +197,12 @@ public class ColumnSelectionTest cs.hideSelectedColumns(al); assertTrue(cs.getSelected().isEmpty()); - List hidden = cols.getHiddenColumnsCopy(); - assertEquals(4, hidden.size()); - assertEquals("[2, 4]", Arrays.toString(hidden.get(0))); - assertEquals("[7, 9]", Arrays.toString(hidden.get(1))); - assertEquals("[15, 18]", Arrays.toString(hidden.get(2))); - assertEquals("[20, 22]", Arrays.toString(hidden.get(3))); + Iterator regions = cols.iterator(); + assertEquals(4, cols.getNumberOfRegions()); + assertEquals("[2, 4]", Arrays.toString(regions.next())); + assertEquals("[7, 9]", Arrays.toString(regions.next())); + assertEquals("[15, 18]", Arrays.toString(regions.next())); + assertEquals("[20, 22]", Arrays.toString(regions.next())); } /** diff --git a/test/jalview/datamodel/HMMNodeTest.java b/test/jalview/datamodel/HMMNodeTest.java new file mode 100644 index 0000000..f2aef06 --- /dev/null +++ b/test/jalview/datamodel/HMMNodeTest.java @@ -0,0 +1,42 @@ +package jalview.datamodel; + +import static org.testng.Assert.assertEquals; + +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; + +import java.io.IOException; +import java.net.MalformedURLException; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class HMMNodeTest +{ + private HiddenMarkovModel hmm; + + @BeforeClass(alwaysRun = true) + public void setUp() throws MalformedURLException, IOException + { + /* + * load hmm model of a Kinase domain to a HiddenMarkovModel + */ + HMMFile file = new HMMFile(new FileParse( + "test/jalview/io/test_PKinase_hmm.txt", DataSourceType.FILE)); + hmm = file.getHMM(); + } + + @Test(groups="Functional") + public void testGetMaxMatchEmissionIdex() + { + assertEquals(hmm.getAlphabetType(), "amino"); + String symbols = hmm.getSymbols(); + + assertEquals(hmm.getNode(1).getMaxMatchEmissionIndex(), + symbols.indexOf('Y')); + + assertEquals(hmm.getNode(17).getMaxMatchEmissionIndex(), + symbols.indexOf('K')); + } +} diff --git a/test/jalview/datamodel/HiddenColumnsCursorTest.java b/test/jalview/datamodel/HiddenColumnsCursorTest.java new file mode 100644 index 0000000..97402b8 --- /dev/null +++ b/test/jalview/datamodel/HiddenColumnsCursorTest.java @@ -0,0 +1,157 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertNull; +import static org.testng.AssertJUnit.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.testng.annotations.Test; + +public class HiddenColumnsCursorTest +{ + + @Test(groups = { "Functional" }) + public void testConstructor() + { + HiddenColumnsCursor cursor = new HiddenColumnsCursor(); + assertNull(cursor.findRegionForColumn(0, false)); + + List hlist = new ArrayList<>(); + cursor = new HiddenColumnsCursor(hlist); + assertNull(cursor.findRegionForColumn(0, false)); + + cursor = new HiddenColumnsCursor(hlist, 3, 12); + assertNull(cursor.findRegionForColumn(0, false)); + + hlist.add(new int[] { 3, 7 }); + hlist.add(new int[] { 15, 25 }); + cursor = new HiddenColumnsCursor(hlist); + HiddenCursorPosition p = cursor.findRegionForColumn(8, false); + assertEquals(1, p.getRegionIndex()); + + cursor = new HiddenColumnsCursor(hlist, 1, 5); + p = cursor.findRegionForColumn(8, false); + assertEquals(1, p.getRegionIndex()); + } + + /** + * Test the method which finds the corresponding region given a column + */ + @Test(groups = { "Functional" }) + public void testFindRegionForColumn() + { + HiddenColumnsCursor cursor = new HiddenColumnsCursor(); + + HiddenCursorPosition pos = cursor.findRegionForColumn(20, false); + assertNull(pos); + + List hidden = new ArrayList<>(); + hidden.add(new int[] { 53, 76 }); + hidden.add(new int[] { 104, 125 }); + + cursor = new HiddenColumnsCursor(hidden); + + int regionIndex = cursor.findRegionForColumn(126, false).getRegionIndex(); + assertEquals(2, regionIndex); + + regionIndex = cursor.findRegionForColumn(125, false).getRegionIndex(); + assertEquals(1, regionIndex); + + regionIndex = cursor.findRegionForColumn(108, false).getRegionIndex(); + assertEquals(1, regionIndex); + + regionIndex = cursor.findRegionForColumn(104, false).getRegionIndex(); + assertEquals(1, regionIndex); + + regionIndex = cursor.findRegionForColumn(103, false).getRegionIndex(); + assertEquals(1, regionIndex); + + regionIndex = cursor.findRegionForColumn(77, false).getRegionIndex(); + assertEquals(1, regionIndex); + + regionIndex = cursor.findRegionForColumn(76, false).getRegionIndex(); + assertEquals(0, regionIndex); + + regionIndex = cursor.findRegionForColumn(53, false).getRegionIndex(); + assertEquals(0, regionIndex); + + regionIndex = cursor.findRegionForColumn(52, false).getRegionIndex(); + assertEquals(0, regionIndex); + + regionIndex = cursor.findRegionForColumn(0, false).getRegionIndex(); + assertEquals(0, regionIndex); + + hidden.add(new int[] { 138, 155 }); + + cursor = new HiddenColumnsCursor(hidden); + + regionIndex = cursor.findRegionForColumn(160, false).getRegionIndex(); + assertEquals(3, regionIndex); + + regionIndex = cursor.findRegionForColumn(100, false).getRegionIndex(); + assertEquals(1, regionIndex); + } + + /** + * Test the method which counts the number of hidden columns before a column + */ + @Test(groups = { "Functional" }) + public void testFindRegionForColumn_Visible() + { + HiddenColumnsCursor cursor = new HiddenColumnsCursor(); + + HiddenCursorPosition pos = cursor.findRegionForColumn(20, true); + assertNull(pos); + + List hidden = new ArrayList<>(); + hidden.add(new int[] { 53, 76 }); + hidden.add(new int[] { 104, 125 }); + + cursor = new HiddenColumnsCursor(hidden); + + int offset = cursor.findRegionForColumn(80, true).getHiddenSoFar(); + assertEquals(46, offset); + + offset = cursor.findRegionForColumn(79, true).getHiddenSoFar(); + assertEquals(24, offset); + + offset = cursor.findRegionForColumn(53, true).getHiddenSoFar(); + assertEquals(24, offset); + + offset = cursor.findRegionForColumn(52, true).getHiddenSoFar(); + assertEquals(0, offset); + + offset = cursor.findRegionForColumn(10, true).getHiddenSoFar(); + assertEquals(0, offset); + + offset = cursor.findRegionForColumn(0, true).getHiddenSoFar(); + assertEquals(0, offset); + + offset = cursor.findRegionForColumn(79, true).getHiddenSoFar(); + assertEquals(24, offset); + + offset = cursor.findRegionForColumn(80, true).getHiddenSoFar(); + assertEquals(46, offset); + } +} diff --git a/test/jalview/datamodel/HiddenColumnsTest.java b/test/jalview/datamodel/HiddenColumnsTest.java index 7c88d71..2916199 100644 --- a/test/jalview/datamodel/HiddenColumnsTest.java +++ b/test/jalview/datamodel/HiddenColumnsTest.java @@ -26,26 +26,15 @@ import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import jalview.analysis.AlignmentGenerator; -import jalview.gui.JvOptionPane; import java.util.Arrays; import java.util.BitSet; -import java.util.List; -import java.util.Random; +import java.util.Iterator; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class HiddenColumnsTest { - - @BeforeClass(alwaysRun = true) - public void setUpJvOptionPane() - { - JvOptionPane.setInteractiveMode(false); - JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); - } - /** * Test the method which counts the number of hidden columns */ @@ -77,22 +66,22 @@ public class HiddenColumnsTest public void testFindColumnPosition() { HiddenColumns cs = new HiddenColumns(); - assertEquals(5, cs.findColumnPosition(5)); + assertEquals(5, cs.absoluteToVisibleColumn(5)); // hiding column 6 makes no difference cs.hideColumns(6, 6); - assertEquals(5, cs.findColumnPosition(5)); + assertEquals(5, cs.absoluteToVisibleColumn(5)); // hiding column 4 moves column 5 to column 4 cs.hideColumns(4, 4); - assertEquals(4, cs.findColumnPosition(5)); + assertEquals(4, cs.absoluteToVisibleColumn(5)); // hiding column 4 moves column 4 to position 3 - assertEquals(3, cs.findColumnPosition(4)); + assertEquals(3, cs.absoluteToVisibleColumn(4)); // hiding columns 1 and 2 moves column 5 to column 2 cs.hideColumns(1, 2); - assertEquals(2, cs.findColumnPosition(5)); + assertEquals(2, cs.absoluteToVisibleColumn(5)); // check with > 1 hidden column regions // where some columns are in the hidden regions @@ -102,105 +91,82 @@ public class HiddenColumnsTest cs2.hideColumns(40, 44); // hiding columns 5-10 and 20-27 moves column 8 to column 4 - assertEquals(4, cs2.findColumnPosition(8)); + assertEquals(4, cs2.absoluteToVisibleColumn(8)); // and moves column 24 to 13 - assertEquals(13, cs2.findColumnPosition(24)); + assertEquals(13, cs2.absoluteToVisibleColumn(24)); // and moves column 28 to 14 - assertEquals(14, cs2.findColumnPosition(28)); + assertEquals(14, cs2.absoluteToVisibleColumn(28)); // and moves column 40 to 25 - assertEquals(25, cs2.findColumnPosition(40)); + assertEquals(25, cs2.absoluteToVisibleColumn(40)); // check when hidden columns start at 0 that the visible column // is returned as 0 HiddenColumns cs3 = new HiddenColumns(); cs3.hideColumns(0, 4); - assertEquals(0, cs3.findColumnPosition(2)); + assertEquals(0, cs3.absoluteToVisibleColumn(2)); + // check that column after the last hidden region doesn't crash + assertEquals(46, cs2.absoluteToVisibleColumn(65)); } - /** - * Test the method that finds the visible column position a given distance - * before another column - */ @Test(groups = { "Functional" }) - public void testFindColumnNToLeft() + public void testVisibleContigsIterator() { HiddenColumns cs = new HiddenColumns(); - // test that without hidden columns, findColumnNToLeft returns - // position n to left of provided position - int pos = cs.subtractVisibleColumns(3, 10); - assertEquals(7, pos); - - // 0 returns same position - pos = cs.subtractVisibleColumns(0, 10); - assertEquals(10, pos); - - // overflow to left returns negative number - pos = cs.subtractVisibleColumns(3, 0); - assertEquals(-3, pos); - - // test that with hidden columns to left of result column - // behaviour is the same as above - cs.hideColumns(1, 3); - - // position n to left of provided position - pos = cs.subtractVisibleColumns(3, 10); - assertEquals(7, pos); - - // 0 returns same position - pos = cs.subtractVisibleColumns(0, 10); - assertEquals(10, pos); - - // test with one set of hidden columns between start and required position - cs.hideColumns(12, 15); - pos = cs.subtractVisibleColumns(8, 17); - assertEquals(5, pos); - - // test with two sets of hidden columns between start and required position - cs.hideColumns(20, 21); - pos = cs.subtractVisibleColumns(8, 23); - assertEquals(9, pos); - - // repeat last 2 tests with no hidden columns to left of required position - ColumnSelection colsel = new ColumnSelection(); - cs.revealAllHiddenColumns(colsel); - - // test with one set of hidden columns between start and required position - cs.hideColumns(12, 15); - pos = cs.subtractVisibleColumns(8, 17); - assertEquals(5, pos); - - // test with two sets of hidden columns between start and required position - cs.hideColumns(20, 21); - pos = cs.subtractVisibleColumns(8, 23); - assertEquals(9, pos); - - } + Iterator visible = cs.getVisContigsIterator(3, 10, false); + int[] region = visible.next(); + assertEquals("[3, 9]", Arrays.toString(region)); + assertFalse(visible.hasNext()); - @Test(groups = { "Functional" }) - public void testGetVisibleContigs() - { - HiddenColumns cs = new HiddenColumns(); cs.hideColumns(3, 6); cs.hideColumns(8, 9); cs.hideColumns(12, 12); - // start position is inclusive, end position exclusive: - int[] visible = cs.getVisibleContigs(1, 13); - assertEquals("[1, 2, 7, 7, 10, 11]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(4, 14); - assertEquals("[7, 7, 10, 11, 13, 13]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(3, 10); - assertEquals("[7, 7]", Arrays.toString(visible)); - - visible = cs.getVisibleContigs(4, 6); - assertEquals("[]", Arrays.toString(visible)); + // Test both ends visible region + + // start position is inclusive, end position exclusive + visible = cs.getVisContigsIterator(1, 13, false); + region = visible.next(); + assertEquals("[1, 2]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[7, 7]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[10, 11]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // Test start hidden, end visible + visible = cs.getVisContigsIterator(4, 14, false); + region = visible.next(); + assertEquals("[7, 7]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[10, 11]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[13, 13]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // Test start hidden, end hidden + visible = cs.getVisContigsIterator(3, 10, false); + region = visible.next(); + assertEquals("[7, 7]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // Test start visible, end hidden + visible = cs.getVisContigsIterator(0, 13, false); + region = visible.next(); + assertEquals("[0, 2]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[7, 7]", Arrays.toString(region)); + region = visible.next(); + assertEquals("[10, 11]", Arrays.toString(region)); + assertFalse(visible.hasNext()); + + // Test empty result + visible = cs.getVisContigsIterator(4, 6, false); + assertFalse(visible.hasNext()); } @Test(groups = { "Functional" }) @@ -216,14 +182,31 @@ public class HiddenColumnsTest assertFalse(cs.equals(cs2)); assertFalse(cs2.equals(cs)); + // with the wrong kind of object + assertFalse(cs.equals(new HiddenColumnsCursor())); + + // with a different hiddenColumns object - by size + HiddenColumns cs3 = new HiddenColumns(); + cs3.hideColumns(2, 3); + assertFalse(cs.equals(cs3)); + // with hidden columns added in a different order cs2.hideColumns(6, 9); + assertFalse(cs.equals(cs2)); + assertFalse(cs2.equals(cs)); + cs2.hideColumns(5, 8); assertTrue(cs.equals(cs2)); assertTrue(cs.equals(cs)); assertTrue(cs2.equals(cs)); assertTrue(cs2.equals(cs2)); + + // different ranges, same size + cs.hideColumns(10, 12); + cs2.hideColumns(10, 15); + assertFalse(cs.equals(cs2)); + } @Test(groups = "Functional") @@ -232,102 +215,50 @@ public class HiddenColumnsTest HiddenColumns cs = new HiddenColumns(); cs.hideColumns(10, 11); cs.hideColumns(5, 7); + Iterator regions = cs.iterator(); assertEquals("[5, 7]", - Arrays.toString(cs.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); HiddenColumns cs2 = new HiddenColumns(cs); + regions = cs2.iterator(); assertTrue(cs2.hasHiddenColumns()); - assertEquals(2, cs2.getHiddenColumnsCopy().size()); + assertEquals(2, cs2.getNumberOfRegions()); // hidden columns are held in column order assertEquals("[5, 7]", - Arrays.toString(cs2.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); assertEquals("[10, 11]", - Arrays.toString(cs2.getHiddenColumnsCopy().get(1))); + Arrays.toString(regions.next())); } - /** - * Test the code used to locate the reference sequence ruler origin - */ - @Test(groups = { "Functional" }) - public void testLocateVisibleBoundsofSequence() + @Test(groups = "Functional") + public void testCopyConstructor2() { - // create random alignment - AlignmentGenerator gen = new AlignmentGenerator(false); - AlignmentI al = gen.generate(50, 20, 123, 5, 5); + HiddenColumns cs = new HiddenColumns(); + cs.hideColumns(10, 11); + cs.hideColumns(5, 7); - HiddenColumns cs = al.getHiddenColumns(); - ColumnSelection colsel = new ColumnSelection(); + HiddenColumns cs2 = new HiddenColumns(cs, 3, 9, 1); + assertTrue(cs2.hasHiddenColumns()); + Iterator regions = cs2.iterator(); - SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---"); - assertEquals(2, seq.findIndex(seq.getStart())); - - // no hidden columns - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - // hidden column on gap after end of sequence - should not affect bounds - colsel.hideSelectedColumns(13, al.getHiddenColumns()); - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + // only [5,7] returned, offset by 1 + assertEquals("[4, 6]", + Arrays.toString(regions.next())); + assertEquals(3, cs2.getSize()); - cs.revealAllHiddenColumns(colsel); - // hidden column on gap before beginning of sequence - should vis bounds by - // one - colsel.hideSelectedColumns(0, al.getHiddenColumns()); - assertEquals( - Arrays.toString(new int[] { seq.findIndex(seq.getStart()) - 2, - seq.findIndex(seq.getEnd()) - 2, seq.getStart(), - seq.getEnd(), seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - - cs.revealAllHiddenColumns(colsel); - // hide columns around most of sequence - leave one residue remaining - cs.hideColumns(1, 3); - cs.hideColumns(6, 11); - assertEquals("-D", - cs.getVisibleSequenceStrings(0, 5, new SequenceI[] { seq })[0]); - assertEquals( - Arrays.toString(new int[] { 1, 1, 3, 3, - seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); - cs.revealAllHiddenColumns(colsel); + cs2 = new HiddenColumns(cs, 8, 15, 4); + regions = cs2.iterator(); + assertTrue(cs2.hasHiddenColumns()); - // hide whole sequence - should just get location of hidden region - // containing sequence - cs.hideColumns(1, 11); - assertEquals( - Arrays.toString(new int[] { 0, 1, 0, 0, - seq.findIndex(seq.getStart()) - 1, - seq.findIndex(seq.getEnd()) - 1 }), - Arrays.toString(cs.locateVisibleBoundsOfSequence(seq))); + // only [10,11] returned, offset by 4 + assertEquals("[6, 7]", + Arrays.toString(regions.next())); + assertEquals(2, cs2.getSize()); + cs2 = new HiddenColumns(cs, 6, 10, 4); + assertFalse(cs2.hasHiddenColumns()); } - @Test(groups = { "Functional" }) - public void testLocateVisibleBoundsPathologicals() - { - // test some pathological cases we missed - AlignmentI al = new Alignment(new SequenceI[] { new Sequence( - "refseqGaptest", "KTDVTI----------NFI-----G----L") }); - HiddenColumns cs = new HiddenColumns(); - cs.hideInsertionsFor(al.getSequenceAt(0)); - assertEquals( - "G", - "" - + al.getSequenceAt(0).getCharAt( - cs.adjustForHiddenColumns(9))); - - } @Test(groups = { "Functional" }) public void testHideColumns() @@ -339,80 +270,103 @@ public class HiddenColumnsTest ColumnSelection colsel = new ColumnSelection(); HiddenColumns cs = al.getHiddenColumns(); colsel.hideSelectedColumns(5, al.getHiddenColumns()); - List hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[5, 5]", Arrays.toString(hidden.get(0))); + Iterator regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[5, 5]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 1); colsel.hideSelectedColumns(3, al.getHiddenColumns()); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(2, hidden.size()); + regions = cs.iterator(); + assertEquals(2, cs.getNumberOfRegions()); // two hidden ranges, in order: - assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size()); - assertEquals("[3, 3]", Arrays.toString(hidden.get(0))); - assertEquals("[5, 5]", Arrays.toString(hidden.get(1))); + assertEquals("[3, 3]", Arrays.toString(regions.next())); + assertEquals("[5, 5]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 2); // hiding column 4 expands [3, 3] to [3, 4] // and merges to [5, 5] to make [3, 5] colsel.hideSelectedColumns(4, al.getHiddenColumns()); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[3, 5]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[3, 5]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 3); // clear hidden columns (note they are added to selected) cs.revealAllHiddenColumns(colsel); // it is now actually null but getter returns an empty list - assertTrue(cs.getHiddenColumnsCopy().isEmpty()); + assertEquals(0, cs.getNumberOfRegions()); + assertEquals(cs.getSize(), 0); cs.hideColumns(3, 6); - hidden = cs.getHiddenColumnsCopy(); - int[] firstHiddenRange = hidden.get(0); + regions = cs.iterator(); + int[] firstHiddenRange = regions.next(); assertEquals("[3, 6]", Arrays.toString(firstHiddenRange)); + assertEquals(cs.getSize(), 4); // adding a subrange of already hidden should do nothing cs.hideColumns(4, 5); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); assertEquals("[3, 6]", - Arrays.toString(cs.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 4); cs.hideColumns(3, 5); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); assertEquals("[3, 6]", - Arrays.toString(cs.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 4); cs.hideColumns(4, 6); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); assertEquals("[3, 6]", - Arrays.toString(cs.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 4); cs.hideColumns(3, 6); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); assertEquals("[3, 6]", - Arrays.toString(cs.getHiddenColumnsCopy().get(0))); + Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 4); cs.revealAllHiddenColumns(colsel); cs.hideColumns(2, 4); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[2, 4]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[2, 4]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 3); // extend contiguous with 2 positions overlap cs.hideColumns(3, 5); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[2, 5]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[2, 5]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 4); // extend contiguous with 1 position overlap cs.hideColumns(5, 6); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[2, 6]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[2, 6]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 5); // extend contiguous with overlap both ends: cs.hideColumns(1, 7); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[1, 7]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[1, 7]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 7); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(15, 18); + cs.hideColumns(2, 4); + cs.hideColumns(7, 9); + regions = cs.iterator(); + assertEquals(3, cs.getNumberOfRegions()); + assertEquals("[2, 4]", Arrays.toString(regions.next())); + assertEquals("[7, 9]", Arrays.toString(regions.next())); + assertEquals("[15, 18]", Arrays.toString(regions.next())); + assertEquals(cs.getSize(), 10); } /** @@ -424,11 +378,18 @@ public class HiddenColumnsTest { ColumnSelection colsel = new ColumnSelection(); HiddenColumns cs = new HiddenColumns(); + + // test with null hidden columns + cs.revealHiddenColumns(5, colsel); + assertTrue(colsel.getSelected().isEmpty()); + cs.hideColumns(5, 8); colsel.addElement(10); cs.revealHiddenColumns(5, colsel); - // hidden columns list now null but getter returns empty list: - assertTrue(cs.getHiddenColumnsCopy().isEmpty()); + + // hiddenColumns now empty + assertEquals(0, cs.getSize()); + // revealed columns are marked as selected (added to selection): assertEquals("[10, 5, 6, 7, 8]", colsel.getSelected().toString()); @@ -436,36 +397,67 @@ public class HiddenColumnsTest colsel = new ColumnSelection(); cs = new HiddenColumns(); cs.hideColumns(5, 8); - List hidden = cs.getHiddenColumnsCopy(); + + int prevSize = cs.getSize(); cs.revealHiddenColumns(6, colsel); - assertEquals(hidden.size(), cs.getHiddenColumnsCopy().size()); + assertEquals(prevSize, cs.getSize()); + assertTrue(colsel.getSelected().isEmpty()); + + // reveal hidden columns when there is more than one region + cs.hideColumns(20, 23); + // now there are 2 hidden regions + assertEquals(2, cs.getNumberOfRegions()); + + cs.revealHiddenColumns(20, colsel); + + // hiddenColumns now has one region + assertEquals(1, cs.getNumberOfRegions()); + + // revealed columns are marked as selected (added to selection): + assertEquals("[20, 21, 22, 23]", colsel.getSelected().toString()); + + // call with a column past the end of the hidden column ranges + colsel.clear(); + cs.revealHiddenColumns(20, colsel); + // hiddenColumns still has 1 region + assertEquals(1, cs.getNumberOfRegions()); assertTrue(colsel.getSelected().isEmpty()); } @Test(groups = { "Functional" }) public void testRevealAllHiddenColumns() { - HiddenColumns cs = new HiddenColumns(); + HiddenColumns hidden = new HiddenColumns(); ColumnSelection colsel = new ColumnSelection(); - cs.hideColumns(5, 8); - cs.hideColumns(2, 3); + + // test with null hidden columns + hidden.revealAllHiddenColumns(colsel); + assertTrue(colsel.getSelected().isEmpty()); + + hidden.hideColumns(5, 8); + hidden.hideColumns(2, 3); colsel.addElement(11); colsel.addElement(1); - cs.revealAllHiddenColumns(colsel); + hidden.revealAllHiddenColumns(colsel); /* * revealing hidden columns adds them (in order) to the (unordered) * selection list */ - assertTrue(cs.getHiddenColumnsCopy().isEmpty()); - assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", colsel.getSelected() - .toString()); + + // hiddenColumns now empty + assertEquals(0, hidden.getSize()); + + assertEquals("[11, 1, 2, 3, 5, 6, 7, 8]", + colsel.getSelected().toString()); } @Test(groups = { "Functional" }) public void testIsVisible() { HiddenColumns cs = new HiddenColumns(); + assertTrue(cs.isVisible(5)); + cs.hideColumns(2, 4); cs.hideColumns(6, 7); assertTrue(cs.isVisible(0)); @@ -477,6 +469,7 @@ public class HiddenColumnsTest assertTrue(cs.isVisible(5)); assertFalse(cs.isVisible(6)); assertFalse(cs.isVisible(7)); + assertTrue(cs.isVisible(8)); } /** @@ -493,15 +486,17 @@ public class HiddenColumnsTest HiddenColumns cs = new HiddenColumns(); cs.hideColumns(49, 59); cs.hideColumns(69, 79); - List hidden = cs.getHiddenColumnsCopy(); - assertEquals(2, hidden.size()); - assertEquals("[49, 59]", Arrays.toString(hidden.get(0))); - assertEquals("[69, 79]", Arrays.toString(hidden.get(1))); + Iterator regions = cs.iterator(); + assertEquals(2, cs.getNumberOfRegions()); + assertEquals("[49, 59]", Arrays.toString(regions.next())); + assertEquals("[69, 79]", Arrays.toString(regions.next())); + assertEquals(22, cs.getSize()); cs.hideColumns(48, 80); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[48, 80]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[48, 80]", Arrays.toString(regions.next())); + assertEquals(33, cs.getSize()); /* * another...joining hidden ranges @@ -512,9 +507,10 @@ public class HiddenColumnsTest cs.hideColumns(50, 60); // hiding 21-49 should merge to one range cs.hideColumns(21, 49); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[10, 60]", Arrays.toString(hidden.get(0))); + regions = cs.iterator(); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals("[10, 60]", Arrays.toString(regions.next())); + assertEquals(51, cs.getSize()); /* * another...left overlap, subsumption, right overlap, @@ -528,14 +524,15 @@ public class HiddenColumnsTest cs.hideColumns(60, 70); cs.hideColumns(15, 45); - hidden = cs.getHiddenColumnsCopy(); - assertEquals(2, hidden.size()); - assertEquals("[10, 50]", Arrays.toString(hidden.get(0))); - assertEquals("[60, 70]", Arrays.toString(hidden.get(1))); + regions = cs.iterator(); + assertEquals(2, cs.getNumberOfRegions()); + assertEquals("[10, 50]", Arrays.toString(regions.next())); + assertEquals("[60, 70]", Arrays.toString(regions.next())); + assertEquals(52, cs.getSize()); } @Test(groups = { "Functional" }) - public void testHideBitset() + public void testHideColumns_BitSet() { HiddenColumns cs; @@ -544,80 +541,45 @@ public class HiddenColumnsTest // one hidden range one.set(1); cs = new HiddenColumns(); - cs.hideMarkedBits(one); - assertEquals(1, cs.getHiddenColumnsCopy().size()); + cs.hideColumns(one); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals(1, cs.getSize()); one.set(2); cs = new HiddenColumns(); - cs.hideMarkedBits(one); - assertEquals(1, cs.getHiddenColumnsCopy().size()); + cs.hideColumns(one); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals(2, cs.getSize()); one.set(3); cs = new HiddenColumns(); - cs.hideMarkedBits(one); - assertEquals(1, cs.getHiddenColumnsCopy().size()); + cs.hideColumns(one); + assertEquals(1, cs.getNumberOfRegions()); + assertEquals(3, cs.getSize()); // split one.clear(2); cs = new HiddenColumns(); - cs.hideMarkedBits(one); - assertEquals(2, cs.getHiddenColumnsCopy().size()); + cs.hideColumns(one); + assertEquals(2, cs.getNumberOfRegions()); + assertEquals(2, cs.getSize()); - assertEquals(0, cs.adjustForHiddenColumns(0)); - assertEquals(2, cs.adjustForHiddenColumns(1)); - assertEquals(4, cs.adjustForHiddenColumns(2)); + assertEquals(0, cs.visibleToAbsoluteColumn(0)); + assertEquals(2, cs.visibleToAbsoluteColumn(1)); + assertEquals(4, cs.visibleToAbsoluteColumn(2)); // one again one.clear(1); cs = new HiddenColumns(); - cs.hideMarkedBits(one); + cs.hideColumns(one); + assertEquals(1, cs.getSize()); - assertEquals(1, cs.getHiddenColumnsCopy().size()); + assertEquals(1, cs.getNumberOfRegions()); - assertEquals(0, cs.adjustForHiddenColumns(0)); - assertEquals(1, cs.adjustForHiddenColumns(1)); - assertEquals(2, cs.adjustForHiddenColumns(2)); - assertEquals(4, cs.adjustForHiddenColumns(3)); - } - - @Test(groups = { "Functional" }) - public void testGetBitset() - { - BitSet toMark, fromMark; - long seed = -3241532; - Random number = new Random(seed); - for (int n = 0; n < 1000; n++) - { - // create a random bitfield - toMark = BitSet.valueOf(new long[] { number.nextLong(), - number.nextLong(), number.nextLong() }); - toMark.set(n * number.nextInt(10), n * (25 + number.nextInt(25))); - HiddenColumns hc = new HiddenColumns(); - hc.hideMarkedBits(toMark); - - // see if we can recover bitfield - hc.markHiddenRegions(fromMark = new BitSet()); - assertEquals(toMark, fromMark); - } - } - - @Test(groups = { "Functional" }) - public void testFindHiddenRegionPositions() - { - HiddenColumns hc = new HiddenColumns(); - - List positions = hc.findHiddenRegionPositions(); - assertTrue(positions.isEmpty()); - - hc.hideColumns(3, 7); - hc.hideColumns(10, 10); - hc.hideColumns(14, 15); - - positions = hc.findHiddenRegionPositions(); - assertEquals(3, positions.size()); - assertEquals(3, positions.get(0).intValue()); - assertEquals(5, positions.get(1).intValue()); - assertEquals(8, positions.get(2).intValue()); + assertEquals(0, cs.visibleToAbsoluteColumn(0)); + assertEquals(1, cs.visibleToAbsoluteColumn(1)); + assertEquals(2, cs.visibleToAbsoluteColumn(2)); + assertEquals(4, cs.visibleToAbsoluteColumn(3)); } @Test(groups = { "Functional" }) @@ -637,7 +599,7 @@ public class HiddenColumnsTest } @Test(groups = "Functional") - public void getVisibleStartAndEndIndexTest() + public void testGetVisibleStartAndEndIndex() { Sequence seq = new Sequence("testSeq", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); AlignmentI align = new Alignment(new SequenceI[] { seq }); @@ -663,6 +625,13 @@ public class HiddenColumnsTest System.out.println(startEnd[0] + " : " + startEnd[1]); assertEquals(1, startEnd[0]); assertEquals(23, startEnd[1]); + + // force lowest range to start of alignment + hc = new HiddenColumns(); + hc.hideColumns(3, 4); + startEnd = hc.getVisibleStartAndEndIndex(align.getWidth()); + assertEquals(0, startEnd[0]); + assertEquals(25, startEnd[1]); } @Test(groups = "Functional") @@ -677,58 +646,683 @@ public class HiddenColumnsTest hc.hideColumns(10, 10); hc.hideColumns(14, 15); - result = hc.getRegionWithEdgeAtRes(3); + result = hc.getRegionWithEdgeAtRes(2); assertEquals(3, result[0]); assertEquals(7, result[1]); + result = hc.getRegionWithEdgeAtRes(4); + assertEquals(10, result[0]); + assertEquals(10, result[1]); + result = hc.getRegionWithEdgeAtRes(5); assertEquals(10, result[0]); assertEquals(10, result[1]); result = hc.getRegionWithEdgeAtRes(6); assertNull(result); + + result = hc.getRegionWithEdgeAtRes(0); + assertNull(result); + + result = hc.getRegionWithEdgeAtRes(7); + assertEquals(14, result[0]); + assertEquals(15, result[1]); + + result = hc.getRegionWithEdgeAtRes(8); + assertEquals(14, result[0]); + assertEquals(15, result[1]); + + result = hc.getRegionWithEdgeAtRes(16); + assertNull(result); } @Test(groups = "Functional") - public void testPropagateInsertions() + public void testHasHiddenColumns() { - // create an alignment with no gaps - this will be the profile seq and other - // JPRED seqs - AlignmentGenerator gen = new AlignmentGenerator(false); - AlignmentI al = gen.generate(20, 10, 1234, 0, 0); - - // get the profileseq - SequenceI profileseq = al.getSequenceAt(0); - SequenceI gappedseq = new Sequence(profileseq); - gappedseq.insertCharAt(5, al.getGapCharacter()); - gappedseq.insertCharAt(6, al.getGapCharacter()); - gappedseq.insertCharAt(7, al.getGapCharacter()); - gappedseq.insertCharAt(8, al.getGapCharacter()); - - // create an alignment view with the gapped sequence - SequenceI[] seqs = new SequenceI[1]; - seqs[0] = gappedseq; - AlignmentI newal = new Alignment(seqs); - HiddenColumns hidden = new HiddenColumns(); - hidden.hideColumns(15, 17); - - AlignmentView view = new AlignmentView(newal, hidden, null, true, false, - false); - - // confirm that original contigs are as expected - int[] oldcontigs = hidden.getVisibleContigs(0, 20); - int[] testcontigs = { 0, 14, 18, 19 }; - assertTrue(Arrays.equals(oldcontigs, testcontigs)); - - // propagate insertions - HiddenColumns result = HiddenColumns.propagateInsertions(profileseq, al, - view); - - // confirm that the contigs have changed to account for the gaps - int[] newcontigs = result.getVisibleContigs(0, 20); - testcontigs[1] = 10; - testcontigs[2] = 14; - assertTrue(Arrays.equals(newcontigs, testcontigs)); - + HiddenColumns h = new HiddenColumns(); + + // new HiddenColumns2 has no hidden cols + assertFalse(h.hasHiddenColumns()); + + // some columns hidden, returns true + h.hideColumns(5, 10); + assertTrue(h.hasHiddenColumns()); + + // reveal columns, no hidden cols again + ColumnSelection sel = new ColumnSelection(); + h.revealAllHiddenColumns(sel); + assertFalse(h.hasHiddenColumns()); + } + + @Test(groups = "Functional") + public void testHasManyHiddenColumns() + { + HiddenColumns h = new HiddenColumns(); + + // h has no hidden cols + assertFalse(h.hasMultiHiddenColumnRegions()); + + // one set of columns hidden, returns false + h.hideColumns(5, 10); + assertFalse(h.hasMultiHiddenColumnRegions()); + + // two sets hidden, returns true + h.hideColumns(15, 17); + assertTrue(h.hasMultiHiddenColumnRegions()); + + // back to one block, asserts false + h.hideColumns(11, 14); + assertFalse(h.hasMultiHiddenColumnRegions()); + } + + @Test(groups = "Functional") + public void testAdjustForHiddenColumns() + { + HiddenColumns h = new HiddenColumns(); + // returns input value when there are no hidden columns + assertEquals(10, h.visibleToAbsoluteColumn(10)); + + h.hideColumns(20, 30); + assertEquals(10, h.visibleToAbsoluteColumn(10)); + assertEquals(20 + 11, h.visibleToAbsoluteColumn(20)); + assertEquals(35 + 11, h.visibleToAbsoluteColumn(35)); + + h.hideColumns(5, 7); + assertEquals(10 + 3, h.visibleToAbsoluteColumn(10)); + assertEquals(20 + 14, h.visibleToAbsoluteColumn(20)); + assertEquals(35 + 14, h.visibleToAbsoluteColumn(35)); + + ColumnSelection sel = new ColumnSelection(); + h.revealAllHiddenColumns(sel); + h.hideColumns(0, 1); + assertEquals(4, h.visibleToAbsoluteColumn(2)); + } + + @Test(groups = "Functional") + public void testGetNextHiddenBoundary_Left() + { + HiddenColumns h = new HiddenColumns(); + + // returns same value if no hidden cols + assertEquals(3, h.getNextHiddenBoundary(true, 3)); + + h.hideColumns(5, 10); + assertEquals(10, h.getNextHiddenBoundary(true, 15)); + assertEquals(3, h.getNextHiddenBoundary(true, 3)); + assertEquals(7, h.getNextHiddenBoundary(true, 7)); + + h.hideColumns(15, 20); + assertEquals(10, h.getNextHiddenBoundary(true, 15)); + assertEquals(20, h.getNextHiddenBoundary(true, 21)); + } + + @Test(groups = "Functional") + public void testGetNextHiddenBoundary_Right() + { + HiddenColumns h = new HiddenColumns(); + + // returns same value if no hidden cols + assertEquals(3, h.getNextHiddenBoundary(false, 3)); + + h.hideColumns(5, 10); + assertEquals(5, h.getNextHiddenBoundary(false, 3)); + assertEquals(15, h.getNextHiddenBoundary(false, 15)); + assertEquals(7, h.getNextHiddenBoundary(false, 7)); + + h.hideColumns(15, 20); + assertEquals(15, h.getNextHiddenBoundary(false, 7)); + assertEquals(15, h.getNextHiddenBoundary(false, 14)); + + // returns same value if there is no next hidden column + assertEquals(22, h.getNextHiddenBoundary(false, 22)); + } + + @Test(groups = "Functional") + public void testIterator() + { + HiddenColumns h = new HiddenColumns(); + Iterator result = h.iterator(); + assertFalse(result.hasNext()); + + h.hideColumns(5, 10); + result = h.iterator(); + int[] next = result.next(); + assertEquals(5, next[0]); + assertEquals(10, next[1]); + assertFalse(result.hasNext()); + + h.hideColumns(22, 23); + result = h.iterator(); + next = result.next(); + assertEquals(5, next[0]); + assertEquals(10, next[1]); + next = result.next(); + assertEquals(22, next[0]); + assertEquals(23, next[1]); + assertFalse(result.hasNext()); + + // test for only one hidden region at start of alignment + ColumnSelection sel = new ColumnSelection(); + h.revealAllHiddenColumns(sel); + h.hideColumns(0, 1); + result = h.iterator(); + next = result.next(); + assertEquals(0, next[0]); + assertEquals(1, next[1]); + assertFalse(result.hasNext()); + } + + /* @Test(groups = "Functional") + public void testGetVisibleSequenceStrings() + { + HiddenColumns h = new HiddenColumns(); + SequenceI seq1 = new Sequence("TEST1", "GALMFWKQESPVICYHRNDT"); + SequenceI seq2 = new Sequence("TEST2", "VICYHRNDTGA"); + SequenceI[] seqs = new SequenceI[2]; + seqs[0] = seq1; + seqs[1] = seq2; + String[] result = h.getVisibleSequenceStrings(5, 10, seqs); + assertEquals(2, result.length); + assertEquals("WKQES", result[0]); + assertEquals("RNDTG", result[1]); + + h.hideColumns(6, 8); + result = h.getVisibleSequenceStrings(5, 10, seqs); + assertEquals(2, result.length); + assertEquals("WS", result[0]); + assertEquals("RG", result[1]); + + SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---"); + ColumnSelection sel = new ColumnSelection(); + h.revealAllHiddenColumns(sel); + h.hideColumns(1, 3); + h.hideColumns(6, 11); + assertEquals("-D", + h.getVisibleSequenceStrings(0, 5, new SequenceI[] + { seq })[0]); + }*/ + + @Test(groups = "Functional") + public void testHideInsertionsFor() + { + HiddenColumns h = new HiddenColumns(); + HiddenColumns h2 = new HiddenColumns(); + SequenceI seq1 = new Sequence("TEST1", "GAL---MFW-KQESPVICY--HRNDT"); + SequenceI seq2 = new Sequence("TEST1", "GALMFWKQESPVICYHRNDT"); + + h.hideList(seq2.getInsertions()); + assertTrue(h.equals(h2)); + assertEquals(0, h.getSize()); + + h.hideList(seq1.getInsertions()); + h2.hideColumns(3, 5); + h2.hideColumns(9, 9); + h2.hideColumns(19, 20); + assertTrue(h.equals(h2)); + assertEquals(6, h.getSize()); + } + + @Test(groups = "Functional") + public void testHideColumns_BitSet_range() + { + HiddenColumns h = new HiddenColumns(); + HiddenColumns h2 = new HiddenColumns(); + + BitSet tohide = new BitSet(25); + h.hideColumns(tohide); + assertTrue(h.equals(h2)); + + // when setting bitset, first param is inclusive, second exclusive + tohide.set(3, 6); + tohide.set(9); + tohide.set(15, 21); + h.clearAndHideColumns(tohide, 5, 23); + + h2.hideColumns(5, 5); + h2.hideColumns(9, 9); + h2.hideColumns(15, 20); + assertTrue(h.equals(h2)); + assertEquals(h.getSize(), h2.getSize()); + + tohide.clear(); + tohide.set(41); + h.clearAndHideColumns(tohide, 23, 30); + assertTrue(h.equals(h2)); + assertEquals(h.getSize(), h2.getSize()); + + tohide.set(41); + h.clearAndHideColumns(tohide, 30, 45); + h2.hideColumns(41, 41); + assertTrue(h.equals(h2)); + assertEquals(h.getSize(), h2.getSize()); + + tohide.clear(); + tohide.set(25, 28); + h.clearAndHideColumns(tohide, 17, 50); + h2 = new HiddenColumns(); + h2.hideColumns(5, 5); + h2.hideColumns(9, 9); + h2.hideColumns(15, 16); + h2.hideColumns(25, 27); + assertTrue(h.equals(h2)); + assertEquals(h.getSize(), h2.getSize()); + + HiddenColumns hc = new HiddenColumns(); + hc.hideColumns(3, 5); + hc.hideColumns(15, 20); + hc.hideColumns(45, 60); + + tohide = new BitSet(); + + // all unhidden if tohide is empty and range covers hidden + hc.clearAndHideColumns(tohide, 1, 70); + assertTrue(!hc.hasHiddenColumns()); + assertEquals(0, hc.getSize()); + + hc.hideColumns(3, 5); + hc.hideColumns(15, 20); + hc.hideColumns(45, 60); + assertEquals(25, hc.getSize()); + + // but not if range does not cover hidden + hc.clearAndHideColumns(tohide, 23, 40); + assertTrue(hc.hasHiddenColumns()); + assertEquals(25, hc.getSize()); + + // and partial unhide if range partially covers + hc.clearAndHideColumns(tohide, 1, 17); + Iterator it = hc.iterator(); + assertTrue(it.hasNext()); + int[] region = it.next(); + + assertEquals(18, region[0]); + assertEquals(20, region[1]); + + assertTrue(it.hasNext()); + region = it.next(); + + assertEquals(45, region[0]); + assertEquals(60, region[1]); + + assertFalse(it.hasNext()); + assertEquals(19, hc.getSize()); + } + + @Test(groups = "Functional") + public void testOffsetByVisibleColumns() + { + HiddenColumns h = new HiddenColumns(); + int result = h.offsetByVisibleColumns(-1, 10); + assertEquals(9, result); + + h.hideColumns(7, 9); + result = h.offsetByVisibleColumns(-4, 10); + assertEquals(3, result); + + h.hideColumns(14, 15); + result = h.offsetByVisibleColumns(-4, 10); + assertEquals(3, result); + + result = h.offsetByVisibleColumns(-10, 17); + assertEquals(2, result); + + result = h.offsetByVisibleColumns(-1, 7); + assertEquals(5, result); + + result = h.offsetByVisibleColumns(-1, 8); + assertEquals(5, result); + + result = h.offsetByVisibleColumns(-3, 15); + assertEquals(10, result); + + ColumnSelection sel = new ColumnSelection(); + h.revealAllHiddenColumns(sel); + h.hideColumns(0, 30); + result = h.offsetByVisibleColumns(-31, 0); + assertEquals(-31, result); + + HiddenColumns cs = new HiddenColumns(); + + // test that without hidden columns, offsetByVisibleColumns returns + // position n to left of provided position + long pos = cs.offsetByVisibleColumns(-3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.offsetByVisibleColumns(0, 10); + assertEquals(10, pos); + + // overflow to left returns negative number + pos = cs.offsetByVisibleColumns(-3, 0); + assertEquals(-3, pos); + + // test that with hidden columns to left of result column + // behaviour is the same as above + cs.hideColumns(1, 3); + + // position n to left of provided position + pos = cs.offsetByVisibleColumns(-3, 10); + assertEquals(7, pos); + + // 0 returns same position + pos = cs.offsetByVisibleColumns(0, 10); + assertEquals(10, pos); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.offsetByVisibleColumns(-8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.offsetByVisibleColumns(-8, 23); + assertEquals(9, pos); + + // repeat last 2 tests with no hidden columns to left of required position + ColumnSelection colsel = new ColumnSelection(); + cs.revealAllHiddenColumns(colsel); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.offsetByVisibleColumns(-8, 17); + assertEquals(5, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.offsetByVisibleColumns(-8, 23); + assertEquals(9, pos); + + // test with right (positive) offsets + + // test that without hidden columns, offsetByVisibleColumns returns + // position n to right of provided position + pos = cs.offsetByVisibleColumns(3, 7); + assertEquals(10, pos); + + // test that with hidden columns to left of result column + // behaviour is the same as above + cs.hideColumns(1, 3); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.offsetByVisibleColumns(8, 5); + assertEquals(17, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.offsetByVisibleColumns(8, 9); + assertEquals(23, pos); + + // repeat last 2 tests with no hidden columns to left of required position + colsel = new ColumnSelection(); + cs.revealAllHiddenColumns(colsel); + + // test with one set of hidden columns between start and required position + cs.hideColumns(12, 15); + pos = cs.offsetByVisibleColumns(8, 5); + assertEquals(17, pos); + + // test with two sets of hidden columns between start and required position + cs.hideColumns(20, 21); + pos = cs.offsetByVisibleColumns(8, 9); + assertEquals(23, pos); + } + + @Test(groups = "Functional") + public void testBoundedIterator() + { + HiddenColumns h = new HiddenColumns(); + Iterator it = h.getBoundedIterator(0, 10); + + // no hidden columns = nothing to iterate over + assertFalse(it.hasNext()); + + // [start,end] contains all hidden columns + // all regions are returned + h.hideColumns(3, 10); + h.hideColumns(14, 16); + it = h.getBoundedIterator(0, 20); + assertTrue(it.hasNext()); + int[] next = it.next(); + assertEquals(3, next[0]); + assertEquals(10, next[1]); + next = it.next(); + assertEquals(14, next[0]); + assertEquals(16, next[1]); + assertFalse(it.hasNext()); + + // [start,end] overlaps a region + // 1 region returned + it = h.getBoundedIterator(5, 7); + assertTrue(it.hasNext()); + next = it.next(); + assertEquals(3, next[0]); + assertEquals(10, next[1]); + assertFalse(it.hasNext()); + + // [start,end] fully contains 1 region and start of last + // - 2 regions returned + it = h.getBoundedIterator(3, 15); + assertTrue(it.hasNext()); + next = it.next(); + assertEquals(3, next[0]); + assertEquals(10, next[1]); + next = it.next(); + assertEquals(14, next[0]); + assertEquals(16, next[1]); + assertFalse(it.hasNext()); + + // [start,end] contains end of first region and whole of last region + // - 2 regions returned + it = h.getBoundedIterator(4, 20); + assertTrue(it.hasNext()); + next = it.next(); + assertEquals(3, next[0]); + assertEquals(10, next[1]); + next = it.next(); + assertEquals(14, next[0]); + assertEquals(16, next[1]); + assertFalse(it.hasNext()); + } + + @Test(groups = "Functional") + public void testBoundedStartIterator() + { + HiddenColumns h = new HiddenColumns(); + Iterator it = h.getStartRegionIterator(0, 10); + + // no hidden columns = nothing to iterate over + assertFalse(it.hasNext()); + + // [start,end] contains all hidden columns + // all regions are returned + h.hideColumns(3, 10); + h.hideColumns(14, 16); + it = h.getStartRegionIterator(0, 20); + assertTrue(it.hasNext()); + int next = it.next(); + assertEquals(3, next); + next = it.next(); + assertEquals(6, next); + assertFalse(it.hasNext()); + + // [start,end] does not contain a start of a region + // no regions to iterate over + it = h.getStartRegionIterator(4, 5); + assertFalse(it.hasNext()); + + // [start,end] fully contains 1 region and start of last + // - 2 regions returned + it = h.getStartRegionIterator(3, 7); + assertTrue(it.hasNext()); + next = it.next(); + assertEquals(3, next); + next = it.next(); + assertEquals(6, next); + assertFalse(it.hasNext()); + + // [start,end] contains whole of last region + // - 1 region returned + it = h.getStartRegionIterator(4, 20); + assertTrue(it.hasNext()); + next = it.next(); + assertEquals(6, next); + assertFalse(it.hasNext()); + } + + @Test(groups = "Functional") + public void testVisibleBlocksVisBoundsIterator() + { + HiddenColumns h = new HiddenColumns(); + Iterator regions = h.getVisContigsIterator(0, 31, true); + + // only 1 visible region spanning 0-30 if nothing is hidden + assertTrue(regions.hasNext()); + int[] region = regions.next(); + assertEquals(0, region[0]); + assertEquals(30, region[1]); + assertFalse(regions.hasNext()); + + // hide 1 region in middle + // 2 regions one on either side + // second region boundary accounts for hidden columns + h.hideColumns(10, 15); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(0, region[0]); + assertEquals(9, region[1]); + region = regions.next(); + assertEquals(16, region[0]); + assertEquals(36, region[1]); + assertFalse(regions.hasNext()); + + // single hidden region at left + h = new HiddenColumns(); + h.hideColumns(0, 5); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(6, region[0]); + assertEquals(36, region[1]); + assertFalse(regions.hasNext()); + + // single hidden region at right + h = new HiddenColumns(); + h.hideColumns(27, 30); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(0, region[0]); + assertEquals(26, region[1]); + region = regions.next(); + assertEquals(31, region[0]); + assertEquals(34, region[1]); + assertFalse(regions.hasNext()); + + // hidden region at left + hidden region in middle + h = new HiddenColumns(); + h.hideColumns(0, 5); + h.hideColumns(23, 25); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(6, region[0]); + assertEquals(22, region[1]); + region = regions.next(); + assertEquals(26, region[0]); + assertEquals(39, region[1]); + assertFalse(regions.hasNext()); + + // hidden region at right + hidden region in middle + h = new HiddenColumns(); + h.hideColumns(27, 30); + h.hideColumns(11, 14); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(0, region[0]); + assertEquals(10, region[1]); + region = regions.next(); + assertEquals(15, region[0]); + assertEquals(26, region[1]); + region = regions.next(); + assertEquals(31, region[0]); + assertEquals(38, region[1]); + assertFalse(regions.hasNext()); + + // hidden region at left and right + h = new HiddenColumns(); + h.hideColumns(27, 35); + h.hideColumns(0, 4); + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(5, region[0]); + assertEquals(26, region[1]); + region = regions.next(); + assertEquals(36, region[0]); + assertEquals(44, region[1]); + assertFalse(regions.hasNext()); + + // multiple hidden regions + h = new HiddenColumns(); + h.hideColumns(1, 1); + h.hideColumns(3, 5); + h.hideColumns(9, 11); + h.hideColumns(22, 26); + + regions = h.getVisContigsIterator(0, 31, true); + + assertTrue(regions.hasNext()); + region = regions.next(); + assertEquals(0, region[0]); + assertEquals(0, region[1]); + region = regions.next(); + assertEquals(2, region[0]); + assertEquals(2, region[1]); + region = regions.next(); + assertEquals(6, region[0]); + assertEquals(8, region[1]); + region = regions.next(); + assertEquals(12, region[0]); + assertEquals(21, region[1]); + region = regions.next(); + assertEquals(27, region[0]); + assertEquals(42, region[1]); + assertFalse(regions.hasNext()); + } + + /* + * the VisibleColsIterator is tested elsewhere, this just tests that + * it can be retrieved from HiddenColumns + */ + @Test(groups = "Functional") + public void testGetVisibleColsIterator() + { + HiddenColumns h = new HiddenColumns(); + Iterator it = h.getVisibleColsIterator(0, 10); + + assertTrue(it instanceof RangeElementsIterator); + } + + @Test(groups = "Functional") + public void testHashCode() + { + HiddenColumns h = new HiddenColumns(); + h.hideColumns(0, 25); + + int result = h.hashCode(); + assertTrue(result > 0); + + h.hideColumns(30, 50); + assertTrue(h.hashCode() > 0); + assertTrue(result != h.hashCode()); } } diff --git a/test/jalview/datamodel/HiddenMarkovModelTest.java b/test/jalview/datamodel/HiddenMarkovModelTest.java new file mode 100644 index 0000000..7978da2 --- /dev/null +++ b/test/jalview/datamodel/HiddenMarkovModelTest.java @@ -0,0 +1,146 @@ +package jalview.datamodel; + +import static org.testng.Assert.assertEquals; + +import jalview.io.DataSourceType; +import jalview.io.FileParse; +import jalview.io.HMMFile; +import jalview.schemes.ResidueProperties; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Map; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class HiddenMarkovModelTest { + + HiddenMarkovModel hmm; + + @BeforeClass(alwaysRun = true) + public void setUp() throws MalformedURLException, IOException + { + /* + * load hmm model of a Kinase domain to a HiddenMarkovModel + */ + HMMFile file = new HMMFile(new FileParse( + "test/jalview/io/test_PKinase_hmm.txt", DataSourceType.FILE)); + hmm = file.getHMM(); + } + + @Test(groups = "Functional") + public void testGetMatchEmissionProbabilities() + throws MalformedURLException, IOException + { + /* + * raw value in file is 3.67403 + * saved as probability e^-X = 0.05259 + */ + double mep = hmm.getMatchEmissionProbability(0, 'R'); + assertEquals(mep, 0.02537400637, 0.0001d); + assertEquals(mep, Math.pow(Math.E, -3.67403), 0.0001d); + + mep = hmm.getMatchEmissionProbability(19, 'W'); + assertEquals(mep, 0.00588228492, 0.0001d); + assertEquals(mep, Math.pow(Math.E, -5.13581), 0.0001d); + + // column 160 is a gapped region of the model + mep = hmm.getMatchEmissionProbability(160, 'G'); + assertEquals(mep, 0D, 0.0001d); + + mep = hmm.getMatchEmissionProbability(475, 'A'); + assertEquals(mep, 0.04995163708, 0.0001d); + assertEquals(mep, Math.pow(Math.E, -2.99670), 0.0001d); + } + + @Test(groups = "Functional") + public void testGetInsertEmissionProbabilities() + { + double iep = hmm.getInsertEmissionProbability(2, 'A'); + assertEquals(iep, Math.pow(Math.E, -2.68618), 0.0001d); + // symbol is not case-sensitive + assertEquals(iep, hmm.getInsertEmissionProbability(2, 'a')); + + iep = hmm.getInsertEmissionProbability(5, 'T'); + assertEquals(iep, Math.pow(Math.E, -2.77519), 0.0001d); + + // column 161 is gapped in the hmm + iep = hmm.getInsertEmissionProbability(161, 'K'); + assertEquals(iep, 0D, 0.0001d); + + iep = hmm.getInsertEmissionProbability(472, 'L'); + assertEquals(iep, Math.pow(Math.E, -2.69355), 0.0001d); + } + + @Test(groups = "Functional") + public void testGetStateTransitionProbabilities() + { + // * in model file treated as negative infinity + double stp = hmm.getStateTransitionProbability(475, + HiddenMarkovModel.MATCHTODELETE); + assertEquals(stp, Double.NEGATIVE_INFINITY); + + // file value is 5.01631, saved as e^-5.01631 + stp = hmm.getStateTransitionProbability(8, + HiddenMarkovModel.MATCHTOINSERT); + assertEquals(stp, Math.pow(Math.E, -5.01631), 0.0001D); + + stp = hmm.getStateTransitionProbability(36, + HiddenMarkovModel.MATCHTODELETE); + assertEquals(stp, Math.pow(Math.E, -5.73865), 0.0001D); + + stp = hmm.getStateTransitionProbability(22, + HiddenMarkovModel.INSERTTOMATCH); + assertEquals(stp, Math.pow(Math.E, -0.61958), 0.0001D); + + stp = hmm.getStateTransitionProbability(80, + HiddenMarkovModel.INSERTTOINSERT); + assertEquals(stp, Math.pow(Math.E, -0.77255), 0.0001D); + + stp = hmm.getStateTransitionProbability(475, + HiddenMarkovModel.DELETETOMATCH); + assertEquals(stp, 1D, 0.0001D); + + stp = hmm.getStateTransitionProbability(218, + HiddenMarkovModel.DELETETODELETE); + assertEquals(stp, Math.pow(Math.E, -0.95510), 0.0001D); + } + + @Test(groups = "Functional") + public void testGetConsensusSequence() + { + SequenceI seq = hmm.getConsensusSequence(); + String subStr = seq.getSequenceAsString().substring(0, 10); + assertEquals(subStr, "yelleklGsG"); + subStr = seq.getSequenceAsString().substring(150, 161); + assertEquals(subStr, "-dllk------"); + } + + /** + * A rather pointless test that reproduces the code implemented and asserts + * the result is the same... + */ + @Test(groups = "Functional") + public void testGetInformationContent() + { + /* + * information measure is sum over all symbols of + * emissionProb * log(emissionProb / background) / log(2) + */ + Map uniprotFreqs = ResidueProperties.backgroundFrequencies + .get("amino"); + int col = 4; + float expected = 0f; + for (char aa : hmm.getSymbols().toCharArray()) + { + double mep = hmm.getMatchEmissionProbability(col, aa); + float background = uniprotFreqs.get(aa); + expected += mep * Math.log(mep / background); + } + expected /= Math.log(2D); + + float actual = hmm.getInformationContent(col); + assertEquals(actual, expected, 0.0001d); + } +} diff --git a/test/jalview/datamodel/HiddenSequencesTest.java b/test/jalview/datamodel/HiddenSequencesTest.java index 11b993d..efd71e6 100644 --- a/test/jalview/datamodel/HiddenSequencesTest.java +++ b/test/jalview/datamodel/HiddenSequencesTest.java @@ -31,6 +31,7 @@ import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals; import jalview.gui.AlignViewport; import jalview.gui.JvOptionPane; +import jalview.viewmodel.AlignmentViewport; import java.util.List; @@ -487,7 +488,7 @@ public class HiddenSequencesTest * represent seqs 2-4 with seq3 * this hides seq2 and seq4 but not seq3 */ - AlignViewport av = new AlignViewport(al); + AlignmentViewport av = new AlignViewport(al); SequenceGroup sg = new SequenceGroup(); sg.addSequence(seqs[1], false); sg.addSequence(seqs[2], false); diff --git a/test/jalview/datamodel/VisibleColsIteratorTest.java b/test/jalview/datamodel/RangeElementsIteratorTest.java similarity index 84% rename from test/jalview/datamodel/VisibleColsIteratorTest.java rename to test/jalview/datamodel/RangeElementsIteratorTest.java index b2d747b..9d14822 100644 --- a/test/jalview/datamodel/VisibleColsIteratorTest.java +++ b/test/jalview/datamodel/RangeElementsIteratorTest.java @@ -22,12 +22,13 @@ package jalview.datamodel; import static org.testng.Assert.assertTrue; +import java.util.Iterator; import java.util.NoSuchElementException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -public class VisibleColsIteratorTest +public class RangeElementsIteratorTest { HiddenColumns hiddenCols; @@ -50,11 +51,12 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextWithHidden() { - VisibleColsIterator it = new VisibleColsIterator(0, 6, hiddenCols); + Iterator it = hiddenCols.getVisibleColsIterator(0, 6); int count = 0; while (it.hasNext()) { - it.next(); + int result = it.next(); + System.out.println(result); count++; } assertTrue(count == 4, "hasNext() is false after 4 iterations"); @@ -67,8 +69,8 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextNoHidden() { - VisibleColsIterator it2 = new VisibleColsIterator(0, 3, - new HiddenColumns()); + HiddenColumns test = new HiddenColumns(); + Iterator it2 = test.getVisibleColsIterator(0, 3); int count = 0; while (it2.hasNext()) { @@ -85,8 +87,7 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextStartHidden() { - VisibleColsIterator it3 = new VisibleColsIterator(0, 6, - hiddenColsAtStart); + Iterator it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6); int count = 0; while (it3.hasNext()) { @@ -103,7 +104,7 @@ public class VisibleColsIteratorTest @Test(groups = { "Functional" }) public void testHasNextAndNextEndHidden() { - VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + Iterator it4 = hiddenCols.getVisibleColsIterator(0, 4); int count = 0; while (it4.hasNext()) { @@ -123,7 +124,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextWithHidden() throws NoSuchElementException { - VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + Iterator it = hiddenCols.getVisibleColsIterator(0, 3); while (it.hasNext()) { it.next(); @@ -140,8 +141,8 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextNoHidden() throws NoSuchElementException { - VisibleColsIterator it2 = new VisibleColsIterator(0, 3, - new HiddenColumns()); + HiddenColumns test = new HiddenColumns(); + Iterator it2 = test.getVisibleColsIterator(0, 3); while (it2.hasNext()) { it2.next(); @@ -158,8 +159,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextStartHidden() throws NoSuchElementException { - VisibleColsIterator it3 = new VisibleColsIterator(0, 6, - hiddenColsAtStart); + Iterator it3 = hiddenColsAtStart.getVisibleColsIterator(0, 6); while (it3.hasNext()) { it3.next(); @@ -176,7 +176,7 @@ public class VisibleColsIteratorTest expectedExceptions = { NoSuchElementException.class }) public void testLastNextEndHidden() throws NoSuchElementException { - VisibleColsIterator it4 = new VisibleColsIterator(0, 4, hiddenCols); + Iterator it4 = hiddenCols.getVisibleColsIterator(0, 4); while (it4.hasNext()) { it4.next(); @@ -192,7 +192,7 @@ public class VisibleColsIteratorTest expectedExceptions = { UnsupportedOperationException.class }) public void testRemove() throws UnsupportedOperationException { - VisibleColsIterator it = new VisibleColsIterator(0, 3, hiddenCols); + Iterator it = hiddenCols.getVisibleColsIterator(0, 3); it.remove(); } } diff --git a/test/jalview/datamodel/ResidueCountTest.java b/test/jalview/datamodel/ResidueCountTest.java index 4eb6dbf..9a8f93d 100644 --- a/test/jalview/datamodel/ResidueCountTest.java +++ b/test/jalview/datamodel/ResidueCountTest.java @@ -27,6 +27,8 @@ import static org.testng.Assert.assertTrue; import jalview.datamodel.ResidueCount.SymbolCounts; import jalview.gui.JvOptionPane; +import java.util.Arrays; + import org.junit.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -69,6 +71,7 @@ public class ResidueCountTest assertEquals(rc.getCount('N'), 1); assertEquals(rc.getCount('?'), 0); assertEquals(rc.getCount('-'), 0); + assertEquals(rc.getTotalResidueCount(), 11); assertFalse(rc.isCountingInts()); assertFalse(rc.isUsingOtherData()); @@ -90,6 +93,7 @@ public class ResidueCountTest assertEquals(rc.getCount(' '), 4); assertEquals(rc.getCount('-'), 4); assertEquals(rc.getCount('.'), 4); + assertEquals(rc.getTotalResidueCount(), 0); assertFalse(rc.isUsingOtherData()); assertFalse(rc.isCountingInts()); } @@ -158,6 +162,7 @@ public class ResidueCountTest assertEquals(rc.getCount('m'), 13); assertEquals(rc.getCount('G'), 0); assertEquals(rc.getCount('-'), 0); + assertEquals(rc.getTotalResidueCount(), 27); assertFalse(rc.isCountingInts()); assertFalse(rc.isUsingOtherData()); @@ -439,4 +444,23 @@ public class ResidueCountTest assertEquals(rc.getCount('?'), 6); assertEquals(rc.getCount('!'), 7); } + + @Test(groups = "Functional") + public void testConstructor_forSequences() + { + SequenceI seq1 = new Sequence("seq1", "abcde--. FCD"); + SequenceI seq2 = new Sequence("seq2", "ab.kKqBd-."); + ResidueCount rc = new ResidueCount(Arrays.asList(seq1, seq2)); + + assertEquals(rc.getGapCount(), 7); + assertEquals(rc.getTotalResidueCount(), 15); // excludes gaps + assertEquals(rc.getCount('a'), 2); + assertEquals(rc.getCount('A'), 2); + assertEquals(rc.getCount('B'), 3); + assertEquals(rc.getCount('c'), 2); + assertEquals(rc.getCount('D'), 3); + assertEquals(rc.getCount('f'), 1); + assertEquals(rc.getCount('K'), 2); + assertEquals(rc.getCount('Q'), 1); + } } diff --git a/test/jalview/datamodel/SequenceGroupTest.java b/test/jalview/datamodel/SequenceGroupTest.java index b0af5c8..df88268 100644 --- a/test/jalview/datamodel/SequenceGroupTest.java +++ b/test/jalview/datamodel/SequenceGroupTest.java @@ -16,10 +16,10 @@ import jalview.schemes.PIDColourScheme; import java.awt.Color; import java.util.Collections; -import junit.extensions.PA; - import org.testng.annotations.Test; +import junit.extensions.PA; + public class SequenceGroupTest { @Test(groups={"Functional"}) @@ -242,7 +242,7 @@ public class SequenceGroupTest sg.setDisplayBoxes(false); sg.setDisplayText(false); sg.setColourText(true); - sg.isDefined = true; + PA.setValue(sg, "isDefined", true); sg.setShowNonconserved(true); sg.setOutlineColour(Color.red); sg.setIdColour(Color.blue); @@ -275,7 +275,7 @@ public class SequenceGroupTest assertEquals(sg2.thresholdTextColour, sg.thresholdTextColour); assertEquals(sg2.textColour, sg.textColour); assertEquals(sg2.textColour2, sg.textColour2); - assertEquals(sg2.getIgnoreGapsConsensus(), sg.getIgnoreGapsConsensus()); + assertEquals(sg2.isIgnoreGapsConsensus(), sg.isIgnoreGapsConsensus()); assertEquals(sg2.isShowSequenceLogo(), sg.isShowSequenceLogo()); assertEquals(sg2.isNormaliseSequenceLogo(), sg.isNormaliseSequenceLogo()); diff --git a/test/jalview/datamodel/SequenceTest.java b/test/jalview/datamodel/SequenceTest.java index a084a8e..5a14514 100644 --- a/test/jalview/datamodel/SequenceTest.java +++ b/test/jalview/datamodel/SequenceTest.java @@ -28,6 +28,7 @@ import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; +import jalview.analysis.AlignmentGenerator; import jalview.commands.EditCommand; import jalview.commands.EditCommand.Action; import jalview.datamodel.PDBEntry.Type; @@ -38,16 +39,17 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Iterator; import java.util.List; import java.util.Vector; -import junit.extensions.PA; - import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import junit.extensions.PA; + public class SequenceTest { @@ -799,7 +801,7 @@ public class SequenceTest Assert.assertEquals(pdbe1a, sq.getDatasetSequence().getPDBEntry("1PDB"), "PDB Entry '1PDB' not found on dataset sequence via getPDBEntry."); - ArrayList annotsList = new ArrayList(); + ArrayList annotsList = new ArrayList<>(); System.out.println(">>>>>> " + sq.getSequenceAsString().length()); annotsList.add(new Annotation("A", "A", 'X', 0.1f)); annotsList.add(new Annotation("A", "A", 'X', 0.1f)); @@ -1674,6 +1676,20 @@ public class SequenceTest } @Test(groups = { "Functional" }) + public void testGapBitset() + { + SequenceI sq = new Sequence("test/8-13", "-ABC---DE-F--"); + BitSet bs = sq.gapBitset(); + BitSet expected = new BitSet(); + expected.set(0); + expected.set(4, 7); + expected.set(9); + expected.set(11, 13); + + assertTrue(bs.equals(expected)); + + } + public void testFindFeatures_largeEndPos() { /* @@ -1881,4 +1897,162 @@ public class SequenceTest assertEquals(8, sq.getDatasetSequence().getStart()); assertEquals(9, sq.getDatasetSequence().getEnd()); } + + /** + * Test the code used to locate the reference sequence ruler origin + */ + @Test(groups = { "Functional" }) + public void testLocateVisibleStartofSequence() + { + // create random alignment + AlignmentGenerator gen = new AlignmentGenerator(false); + AlignmentI al = gen.generate(50, 20, 123, 5, 5); + + HiddenColumns cs = al.getHiddenColumns(); + ColumnSelection colsel = new ColumnSelection(); + + SequenceI seq = new Sequence("RefSeq", "-A-SD-ASD--E---"); + assertEquals(2, seq.findIndex(seq.getStart())); + + // no hidden columns + assertEquals(seq.findIndex(seq.getStart()) - 1, + seq.firstResidueOutsideIterator(cs.iterator())); + + // hidden column on gap after end of sequence - should not affect bounds + colsel.hideSelectedColumns(13, al.getHiddenColumns()); + assertEquals(seq.findIndex(seq.getStart()) - 1, + seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + // hidden column on gap before beginning of sequence - should vis bounds by + // one + colsel.hideSelectedColumns(0, al.getHiddenColumns()); + assertEquals(seq.findIndex(seq.getStart()) - 2, + cs.absoluteToVisibleColumn( + seq.firstResidueOutsideIterator(cs.iterator()))); + + cs.revealAllHiddenColumns(colsel); + // hide columns around most of sequence - leave one residue remaining + cs.hideColumns(1, 3); + cs.hideColumns(6, 11); + + Iterator it = cs.getVisContigsIterator(0, 6, false); + + assertEquals("-D", seq.getSequenceStringFromIterator(it)); + // cs.getVisibleSequenceStrings(0, 5, new SequenceI[] + // { seq })[0]); + + assertEquals(4, seq.firstResidueOutsideIterator(cs.iterator())); + cs.revealAllHiddenColumns(colsel); + + // hide whole sequence - should just get location of hidden region + // containing sequence + cs.hideColumns(1, 11); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 15); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + SequenceI seq2 = new Sequence("RefSeq2", "-------A-SD-ASD--E---"); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(7, 17); + assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(3, 17); + assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(3, 19); + assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 0); + assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 1); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 2); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(1, 1); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(1, 2); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(1, 3); + assertEquals(4, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 2); + cs.hideColumns(5, 6); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 2); + cs.hideColumns(5, 6); + cs.hideColumns(9, 10); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 2); + cs.hideColumns(7, 11); + assertEquals(3, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(2, 4); + cs.hideColumns(7, 11); + assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(2, 4); + cs.hideColumns(7, 12); + assertEquals(1, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(1, 11); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 12); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 4); + cs.hideColumns(6, 12); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 1); + cs.hideColumns(3, 12); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(3, 14); + cs.hideColumns(17, 19); + assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(3, 7); + cs.hideColumns(9, 14); + cs.hideColumns(17, 19); + assertEquals(0, seq2.firstResidueOutsideIterator(cs.iterator())); + + cs.revealAllHiddenColumns(colsel); + cs.hideColumns(0, 1); + cs.hideColumns(3, 4); + cs.hideColumns(6, 8); + cs.hideColumns(10, 12); + assertEquals(0, seq.firstResidueOutsideIterator(cs.iterator())); + + } } diff --git a/test/jalview/datamodel/StartRegionIteratorTest.java b/test/jalview/datamodel/StartRegionIteratorTest.java new file mode 100644 index 0000000..23d0b00 --- /dev/null +++ b/test/jalview/datamodel/StartRegionIteratorTest.java @@ -0,0 +1,214 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.testng.annotations.Test; + +public class StartRegionIteratorTest +{ + /** + * Test the start region iterator + */ + @Test(groups = { "Functional" }) + public void testBasicBoundsIterator() + { + List hiddenColumns = null; + + // null hidden columns + Iterator it = new StartRegionIterator(3, 10, + hiddenColumns); + assertFalse(it.hasNext()); + + hiddenColumns = new ArrayList<>(); + + // no hidden columns + it = new StartRegionIterator(3, 10, hiddenColumns); + assertFalse(it.hasNext()); + + // add some hidden columns + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + it = new StartRegionIterator(3, 10, hiddenColumns); + assertTrue(it.hasNext()); + Integer result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(3, 15, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(3, 18, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(3, 19, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertFalse(it.hasNext()); + + hiddenColumns.add(new int[] { 47, 50 }); + + it = new StartRegionIterator(15, 60, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(25, (int) result); + assertFalse(it.hasNext()); + } + + /** + * Test the start region iterator with null cursor + */ + @Test(groups = { "Functional" }) + public void testBoundsIteratorUsingNullCursor() + { + List hiddenColumns = null; + HiddenCursorPosition pos = null; + + // null hidden columns + Iterator it = new StartRegionIterator(pos, 3, 10, + hiddenColumns); + assertFalse(it.hasNext()); + + hiddenColumns = new ArrayList<>(); + + // no hidden columns + it = new StartRegionIterator(pos, 3, 10, hiddenColumns); + assertFalse(it.hasNext()); + + // add some hidden columns + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + it = new StartRegionIterator(pos, 3, 10, hiddenColumns); + assertTrue(it.hasNext()); + Integer result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 15, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 18, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 19, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertFalse(it.hasNext()); + + hiddenColumns.add(new int[] { 47, 50 }); + + it = new StartRegionIterator(pos, 15, 60, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(25, (int) result); + assertFalse(it.hasNext()); + } + + /** + * Test the start region iterator with nonnull cursor + */ + @Test(groups = { "Functional" }) + public void testBoundsIteratorUsingCursor() + { + List hiddenColumns = new ArrayList<>(); + + // add some hidden columns + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + HiddenCursorPosition pos = new HiddenCursorPosition(0, 0); + + Iterator it = new StartRegionIterator(pos, 3, 10, + hiddenColumns); + assertTrue(it.hasNext()); + Integer result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 15, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 18, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertFalse(it.hasNext()); + + it = new StartRegionIterator(pos, 3, 19, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(5, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertFalse(it.hasNext()); + + pos = new HiddenCursorPosition(1, 6); + hiddenColumns.add(new int[] { 47, 50 }); + + it = new StartRegionIterator(pos, 15, 60, hiddenColumns); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(19, (int) result); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(25, (int) result); + assertFalse(it.hasNext()); + } +} diff --git a/test/jalview/datamodel/VisibleContigsIteratorTest.java b/test/jalview/datamodel/VisibleContigsIteratorTest.java new file mode 100644 index 0000000..8f31dae --- /dev/null +++ b/test/jalview/datamodel/VisibleContigsIteratorTest.java @@ -0,0 +1,223 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.datamodel; + +import static org.testng.Assert.assertEquals; +import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.testng.annotations.Test; + +public class VisibleContigsIteratorTest +{ + /** + * Test the iterator with single visible regions + */ + @Test(groups = { "Functional" }) + public void testSimpleVisibleRegions() + { + List hiddenColumns = null; + + // null hidden columns + VisibleContigsIterator it = new VisibleContigsIterator(3, 10, + hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + int[] result = it.next(); + assertEquals(3, result[0]); + assertEquals(9, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + hiddenColumns = new ArrayList<>(); + + // no hidden columns + it = new VisibleContigsIterator(3, 10, + hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(3, result[0]); + assertEquals(9, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + // hidden columns, but not where we are looking + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + it = new VisibleContigsIterator(2, 3, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(2, result[0]); + assertEquals(2, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + it = new VisibleContigsIterator(5, 7, hiddenColumns); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + it = new VisibleContigsIterator(11, 15, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(11, result[0]); + assertEquals(14, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + it = new VisibleContigsIterator(50, 60, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(50, result[0]); + assertEquals(59, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + } + + /** + * Test the iterator with multiple visible regions + */ + @Test(groups = { "Functional" }) + public void testMultipleVisibleRegions() + { + List hiddenColumns = new ArrayList<>(); + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + // all hidden columns covered + VisibleContigsIterator it = new VisibleContigsIterator(3, 50, + hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + int[] result = it.next(); + assertEquals(3, result[0]); + assertEquals(4, result[1]); + + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(11, result[0]); + assertEquals(24, result[1]); + + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(41, result[0]); + assertEquals(49, result[1]); + + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + } + + /** + * Test the iterator with regions which start/end at hidden region edges + */ + @Test(groups = { "Functional" }) + public void testVisibleRegionsAtHiddenEdges() + { + List hiddenColumns = new ArrayList<>(); + hiddenColumns.add(new int[] { 5, 10 }); + hiddenColumns.add(new int[] { 25, 40 }); + + VisibleContigsIterator it = new VisibleContigsIterator(0, 10, + hiddenColumns); + assertTrue(it.hasNext()); + assertTrue(it.endsAtHidden()); + int[] result = it.next(); + assertEquals(0, result[0]); + assertEquals(4, result[1]); + assertFalse(it.hasNext()); + assertTrue(it.endsAtHidden()); + + it = new VisibleContigsIterator(2, 11, hiddenColumns); + assertTrue(it.hasNext()); + assertTrue(it.endsAtHidden()); + result = it.next(); + assertEquals(2, result[0]); + assertEquals(4, result[1]); + assertFalse(it.hasNext()); + assertTrue(it.endsAtHidden()); + + it = new VisibleContigsIterator(2, 12, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(2, result[0]); + assertEquals(4, result[1]); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(11, result[0]); + assertEquals(11, result[1]); + assertFalse(it.hasNext()); + assertFalse(it.endsAtHidden()); + + it = new VisibleContigsIterator(13, 25, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(13, result[0]); + assertEquals(24, result[1]); + assertFalse(it.hasNext()); + + it = new VisibleContigsIterator(13, 26, hiddenColumns); + assertTrue(it.hasNext()); + assertTrue(it.endsAtHidden()); + result = it.next(); + assertEquals(13, result[0]); + assertEquals(24, result[1]); + assertFalse(it.hasNext()); + + it = new VisibleContigsIterator(13, 27, hiddenColumns); + assertTrue(it.hasNext()); + assertTrue(it.endsAtHidden()); + result = it.next(); + assertEquals(13, result[0]); + assertEquals(24, result[1]); + assertFalse(it.hasNext()); + + it = new VisibleContigsIterator(13, 41, hiddenColumns); + assertTrue(it.hasNext()); + assertTrue(it.endsAtHidden()); + result = it.next(); + assertEquals(13, result[0]); + assertEquals(24, result[1]); + assertFalse(it.hasNext()); + + it = new VisibleContigsIterator(13, 42, hiddenColumns); + assertTrue(it.hasNext()); + assertFalse(it.endsAtHidden()); + result = it.next(); + assertEquals(13, result[0]); + assertEquals(24, result[1]); + assertTrue(it.hasNext()); + result = it.next(); + assertEquals(41, result[0]); + assertEquals(41, result[1]); + } +} diff --git a/test/jalview/ext/ensembl/EnsemblGeneTest.java b/test/jalview/ext/ensembl/EnsemblGeneTest.java index 1b1a2b4..217742d 100644 --- a/test/jalview/ext/ensembl/EnsemblGeneTest.java +++ b/test/jalview/ext/ensembl/EnsemblGeneTest.java @@ -25,6 +25,7 @@ import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import jalview.api.FeatureSettingsModelI; +import jalview.bin.Cache; import jalview.datamodel.SequenceDummy; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; @@ -53,6 +54,7 @@ public class EnsemblGeneTest @BeforeClass(alwaysRun = true) public void setUp() { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); SequenceOntologyFactory.setInstance(new SequenceOntologyLite()); } diff --git a/test/jalview/ext/jmol/JmolCommandsTest.java b/test/jalview/ext/jmol/JmolCommandsTest.java index 3309adf..e42b54f 100644 --- a/test/jalview/ext/jmol/JmolCommandsTest.java +++ b/test/jalview/ext/jmol/JmolCommandsTest.java @@ -115,7 +115,7 @@ public class JmolCommandsTest String chainACommand = commands[0].commands[0]; // M colour is #82827d == (130, 130, 125) (see strand.html help page) assertTrue(chainACommand - .contains(";select 21:A/1.1;color[130,130,125]")); + .contains("select 21:A/1.1;color[130,130,125]")); // first one // H colour is #60609f == (96, 96, 159) assertTrue(chainACommand.contains(";select 22:A/1.1;color[96,96,159]")); // hidden columns are Gray (128, 128, 128) @@ -128,7 +128,7 @@ public class JmolCommandsTest String chainBCommand = commands[1].commands[0]; // M colour is #82827d == (130, 130, 125) assertTrue(chainBCommand - .contains(";select 21:B/2.1;color[130,130,125]")); + .contains("select 21:B/2.1;color[130,130,125]")); // V colour is #ffff00 == (255, 255, 0) assertTrue(chainBCommand .contains(";select 22:B/2.1;color[255,255,0]")); diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java index 1ee25c7..0f15ce4 100644 --- a/test/jalview/gui/AlignFrameTest.java +++ b/test/jalview/gui/AlignFrameTest.java @@ -26,11 +26,13 @@ import static org.testng.Assert.assertNotSame; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; +import jalview.api.AlignViewportI; import jalview.api.FeatureColourI; import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; @@ -46,9 +48,10 @@ import jalview.schemes.JalviewColourScheme; import jalview.schemes.StrandColourScheme; import jalview.schemes.TurnColourScheme; import jalview.util.MessageManager; +import jalview.viewmodel.AlignmentViewport; import java.awt.Color; -import java.util.List; +import java.util.Iterator; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; @@ -92,21 +95,25 @@ public class AlignFrameTest */ assertFalse(alignFrame.hideFeatureColumns("exon", true)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns() - .getHiddenColumnsCopy().isEmpty()); + + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 0); + assertFalse(alignFrame.hideFeatureColumns("exon", false)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - assertTrue(alignFrame.getViewport().getAlignment().getHiddenColumns() - .getHiddenColumnsCopy().isEmpty()); + + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 0); /* * hiding a feature in all columns does nothing */ assertFalse(alignFrame.hideFeatureColumns("Metal", true)); assertTrue(alignFrame.getViewport().getColumnSelection().isEmpty()); - List hidden = alignFrame.getViewport().getAlignment() - .getHiddenColumns().getHiddenColumnsCopy(); - assertTrue(hidden.isEmpty()); + + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 0); + /* * threshold Metal to hide features where score < 5 @@ -118,11 +125,12 @@ public class AlignFrameTest fc.setThreshold(5f); alignFrame.getFeatureRenderer().setColour("Metal", fc); assertTrue(alignFrame.hideFeatureColumns("Metal", true)); - hidden = alignFrame.getViewport().getAlignment().getHiddenColumns() - .getHiddenColumnsCopy(); - assertEquals(hidden.size(), 1); - assertEquals(hidden.get(0)[0], 5); - assertEquals(hidden.get(0)[1], 9); + HiddenColumns hidden = alignFrame.getViewport().getAlignment().getHiddenColumns(); + assertEquals(hidden.getNumberOfRegions(), 1); + Iterator regions = hidden.iterator(); + int[] next = regions.next(); + assertEquals(next[0], 5); + assertEquals(next[1], 9); /* * hide a feature present in some columns @@ -131,13 +139,16 @@ public class AlignFrameTest */ alignFrame.getViewport().showAllHiddenColumns(); assertTrue(alignFrame.hideFeatureColumns("Turn", true)); - hidden = alignFrame.getViewport().getAlignment().getHiddenColumns() - .getHiddenColumnsCopy(); - assertEquals(hidden.size(), 2); - assertEquals(hidden.get(0)[0], 1); - assertEquals(hidden.get(0)[1], 3); - assertEquals(hidden.get(1)[0], 6); - assertEquals(hidden.get(1)[1], 8); + regions = alignFrame.getViewport().getAlignment() + .getHiddenColumns().iterator(); + assertEquals(alignFrame.getViewport().getAlignment().getHiddenColumns() + .getNumberOfRegions(), 2); + next = regions.next(); + assertEquals(next[0], 1); + assertEquals(next[1], 3); + next = regions.next(); + assertEquals(next[0], 6); + assertEquals(next[1], 8); } @BeforeClass(alwaysRun = true) @@ -199,7 +210,7 @@ public class AlignFrameTest @Test(groups = "Functional") public void testChangeColour_background_groupsAndThresholds() { - AlignViewport av = af.getViewport(); + AlignViewportI av = af.getViewport(); AlignmentI al = av.getAlignment(); /* @@ -330,7 +341,7 @@ public class AlignFrameTest @Test(groups = "Functional") public void testColourThresholdActions() { - AlignViewport av = af.getViewport(); + AlignViewportI av = af.getViewport(); AlignmentI al = av.getAlignment(); /* @@ -499,7 +510,7 @@ public class AlignFrameTest @Test(groups = "Functional") public void testNewView_colourThresholds() { - AlignViewport av = af.getViewport(); + AlignViewportI av = af.getViewport(); AlignmentI al = av.getAlignment(); /* @@ -563,7 +574,7 @@ public class AlignFrameTest */ af.newView_actionPerformed(null); assertEquals(af.alignPanel.getViewName(), "View 1"); - AlignViewport av2 = af.getViewport(); + AlignmentViewport av2 = af.getViewport(); assertNotSame(av, av2); assertSame(av2, af.alignPanel.av); rs = av2.getResidueShading(); diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java index 5ed0cac..6ab2622 100644 --- a/test/jalview/gui/AlignViewportTest.java +++ b/test/jalview/gui/AlignViewportTest.java @@ -26,6 +26,7 @@ import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; +import jalview.api.AlignViewportI; import jalview.bin.Cache; import jalview.bin.Jalview; import jalview.datamodel.AlignedCodonFrame; @@ -33,8 +34,6 @@ import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; -import jalview.datamodel.PDBEntry; -import jalview.datamodel.PDBEntry.Type; import jalview.datamodel.SearchResults; import jalview.datamodel.SearchResultsI; import jalview.datamodel.Sequence; @@ -46,6 +45,7 @@ import jalview.schemes.ColourSchemeI; import jalview.schemes.PIDColourScheme; import jalview.structure.StructureSelectionManager; import jalview.util.MapList; +import jalview.viewmodel.AlignmentViewport; import jalview.viewmodel.ViewportRanges; import java.util.ArrayList; @@ -68,7 +68,7 @@ public class AlignViewportTest AlignmentI al; - AlignViewport testee; + AlignmentViewport testee; @BeforeClass(alwaysRun = true) public static void setUpBeforeClass() throws Exception @@ -355,7 +355,7 @@ public class AlignViewportTest { AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); - AlignViewport av = af.getViewport(); + AlignViewportI av = af.getViewport(); SequenceGroup sg1 = new SequenceGroup(); SequenceGroup sg2 = new SequenceGroup(); SequenceGroup sg3 = new SequenceGroup(); @@ -384,8 +384,8 @@ public class AlignViewportTest jalview.bin.Cache.setProperty("SHOW_OCCUPANCY", Boolean.FALSE.toString()); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); - AlignViewport av = af.getViewport(); - Assert.assertNull(av.getAlignmentGapAnnotation(), "Preference did not disable occupancy row."); + AlignViewportI av = af.getViewport(); + Assert.assertNull(av.getOccupancyAnnotation(), "Preference did not disable occupancy row."); int c = 0; for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null, null, "Occupancy")) @@ -399,10 +399,10 @@ public class AlignViewportTest af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); av = af.getViewport(); - Assert.assertNotNull(av.getAlignmentGapAnnotation(), "Preference did not enable occupancy row."); + Assert.assertNotNull(av.getOccupancyAnnotation(), "Preference did not enable occupancy row."); c = 0; for (AlignmentAnnotation aa : av.getAlignment().findAnnotations(null, - null, av.getAlignmentGapAnnotation().label)) + null, av.getOccupancyAnnotation().label)) { c++; } @@ -423,7 +423,7 @@ public class AlignViewportTest String fasta = ">s1\nA-C\n>s2\nA-C\n>s3\nA-D\n>s4\n--D\n"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(fasta, DataSourceType.PASTE); - AlignViewport testme = af.getViewport(); + AlignmentViewport testme = af.getViewport(); SequenceI cons = testme.getConsensusSeq(); assertEquals("A-C", cons.getSequenceAsString()); } diff --git a/test/jalview/gui/AnnotationColumnChooserTest.java b/test/jalview/gui/AnnotationColumnChooserTest.java index 06478d5..912cd27 100644 --- a/test/jalview/gui/AnnotationColumnChooserTest.java +++ b/test/jalview/gui/AnnotationColumnChooserTest.java @@ -35,7 +35,7 @@ import jalview.io.FileFormat; import jalview.io.FormatAdapter; import java.io.IOException; -import java.util.List; +import java.util.Iterator; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -141,18 +141,21 @@ public class AnnotationColumnChooserTest HiddenColumns currentHidden = af.getViewport().getAlignment() .getHiddenColumns(); - List regions = currentHidden.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 0); - assertEquals(regions.get(0)[1], 3); - assertEquals(regions.get(1)[0], 22); - assertEquals(regions.get(1)[1], 25); + Iterator regions = currentHidden.iterator(); + int[] next = regions.next(); + assertEquals(0, next[0]); + assertEquals(3, next[1]); + next = regions.next(); + assertEquals(22, next[0]); + assertEquals(25, next[1]); // now reset hidden columns acc.reset(); currentHidden = af.getViewport().getAlignment().getHiddenColumns(); - regions = currentHidden.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 10); - assertEquals(regions.get(0)[1], 20); + regions = currentHidden.iterator(); + next = regions.next(); + assertEquals(10, next[0]); + assertEquals(20, next[1]); // check works with empty hidden columns as old columns oldhidden = new HiddenColumns(); @@ -169,8 +172,9 @@ public class AnnotationColumnChooserTest acc.reset(); currentHidden = af.getViewport().getAlignment().getHiddenColumns(); - regions = currentHidden.getHiddenColumnsCopy(); - assertEquals(regions.get(0)[0], 10); - assertEquals(regions.get(0)[1], 20); + regions = currentHidden.iterator(); + next = regions.next(); + assertEquals(10, next[0]); + assertEquals(20, next[1]); } } diff --git a/test/jalview/gui/PairwiseAlignmentPanelTest.java b/test/jalview/gui/PairwiseAlignmentPanelTest.java index 3322ee8..1ea0ba1 100644 --- a/test/jalview/gui/PairwiseAlignmentPanelTest.java +++ b/test/jalview/gui/PairwiseAlignmentPanelTest.java @@ -2,17 +2,19 @@ package jalview.gui; import static org.testng.Assert.assertEquals; +import jalview.api.AlignViewportI; import jalview.datamodel.AlignmentI; import jalview.datamodel.SequenceGroup; import jalview.io.DataSourceType; import jalview.io.FileLoader; +import jalview.viewmodel.AlignmentViewport; import javax.swing.JTextArea; -import junit.extensions.PA; - import org.testng.annotations.Test; +import junit.extensions.PA; + public class PairwiseAlignmentPanelTest { @Test(groups = "Functional") @@ -20,7 +22,7 @@ public class PairwiseAlignmentPanelTest { AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); - AlignViewport viewport = af.getViewport(); + AlignViewportI viewport = af.getViewport(); AlignmentI al = viewport.getAlignment(); /* @@ -58,7 +60,7 @@ public class PairwiseAlignmentPanelTest String seqs = ">Q93XJ9_SOLTU/23-29\nL-KAISNV\n>FER1_PEA/26-32\nV-TTTKAF\n"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqs, DataSourceType.PASTE); - AlignViewport viewport = af.getViewport(); + AlignViewportI viewport = af.getViewport(); PairwiseAlignPanel testee = new PairwiseAlignPanel(viewport); diff --git a/test/jalview/gui/PopupMenuTest.java b/test/jalview/gui/PopupMenuTest.java index 40e624d..6f60588 100644 --- a/test/jalview/gui/PopupMenuTest.java +++ b/test/jalview/gui/PopupMenuTest.java @@ -30,9 +30,13 @@ import jalview.bin.Cache; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.ColumnSelection; import jalview.datamodel.DBRefEntry; import jalview.datamodel.DBRefSource; +import jalview.datamodel.HiddenColumns; +import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; import jalview.io.DataSourceType; import jalview.io.FileFormat; @@ -46,6 +50,7 @@ import java.awt.Component; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.Iterator; import java.util.List; import javax.swing.JMenu; @@ -124,7 +129,7 @@ public class PopupMenuTest public void testConfigureReferenceAnnotationsMenu_noSequenceSelected() { JMenuItem menu = new JMenuItem(); - List seqs = new ArrayList(); + List seqs = new ArrayList<>(); testee.configureReferenceAnnotationsMenu(menu, seqs); assertFalse(menu.isEnabled()); // now try null list @@ -493,8 +498,8 @@ public class PopupMenuTest List seqs = parentPanel.getAlignment().getSequences(); // create list of links and list of DBRefs - List links = new ArrayList(); - List refs = new ArrayList(); + List links = new ArrayList<>(); + List refs = new ArrayList<>(); // links as might be added into Preferences | Connections dialog links.add("EMBL-EBI Search | http://www.ebi.ac.uk/ebisearch/search.ebi?db=allebi&query=$" @@ -579,7 +584,7 @@ public class PopupMenuTest } // if there are no valid links the Links submenu is disabled - List nomatchlinks = new ArrayList(); + List nomatchlinks = new ArrayList<>(); nomatchlinks.add("NOMATCH | http://www.uniprot.org/uniprot/$" + DB_ACCESSION + "$"); @@ -589,4 +594,117 @@ public class PopupMenuTest assertFalse(linkMenu.isEnabled()); } + + /** + * Test for adding feature links + */ + @Test(groups = { "Functional" }) + public void testHideInsertions() + { + // get sequences from the alignment + List seqs = parentPanel.getAlignment().getSequences(); + + // add our own seqs to avoid problems with changes to existing sequences + // (gap at end of sequences varies depending on how tests are run!) + Sequence seqGap1 = new Sequence("GappySeq", + "AAAA----AA-AAAAAAA---AAA-----------AAAAAAAAAA--"); + seqGap1.createDatasetSequence(); + seqs.add(seqGap1); + Sequence seqGap2 = new Sequence("LessGappySeq", + "AAAAAA-AAAAA---AAA--AAAAA--AAAAAAA-AAAAAA"); + seqGap2.createDatasetSequence(); + seqs.add(seqGap2); + Sequence seqGap3 = new Sequence("AnotherGapSeq", + "AAAAAA-AAAAAA--AAAAAA-AAAAAAAAAAA---AAAAAAAA"); + seqGap3.createDatasetSequence(); + seqs.add(seqGap3); + Sequence seqGap4 = new Sequence("NoGaps", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + seqGap4.createDatasetSequence(); + seqs.add(seqGap4); + + ColumnSelection sel = new ColumnSelection(); + parentPanel.av.getAlignment().getHiddenColumns() + .revealAllHiddenColumns(sel); + + // get the Popup Menu for 7th sequence - no insertions + testee = new PopupMenu(parentPanel, seqs.get(7), null); + testee.hideInsertions_actionPerformed(null); + + HiddenColumns hidden = parentPanel.av.getAlignment().getHiddenColumns(); + Iterator it = hidden.iterator(); + assertFalse(it.hasNext()); + + // get the Popup Menu for GappySeq - this time we have insertions + testee = new PopupMenu(parentPanel, seqs.get(4), null); + testee.hideInsertions_actionPerformed(null); + hidden = parentPanel.av.getAlignment().getHiddenColumns(); + it = hidden.iterator(); + + assertTrue(it.hasNext()); + int[] region = it.next(); + assertEquals(region[0], 4); + assertEquals(region[1], 7); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 10); + assertEquals(region[1], 10); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 18); + assertEquals(region[1], 20); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 24); + assertEquals(region[1], 34); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 45); + assertEquals(region[1], 46); + + assertFalse(it.hasNext()); + + sel = new ColumnSelection(); + hidden.revealAllHiddenColumns(sel); + + // make a sequence group and hide insertions within the group + SequenceGroup sg = new SequenceGroup(); + sg.setStartRes(8); + sg.setEndRes(42); + sg.addSequence(seqGap2, false); + sg.addSequence(seqGap3, false); + parentPanel.av.setSelectionGroup(sg); + + // hide columns outside and within selection + // only hidden columns outside the collection will be retained (unless also + // gaps in the selection) + hidden.hideColumns(1, 10); + hidden.hideColumns(31, 40); + + // get the Popup Menu for LessGappySeq in the sequence group + testee = new PopupMenu(parentPanel, seqs.get(5), null); + testee.hideInsertions_actionPerformed(null); + hidden = parentPanel.av.getAlignment().getHiddenColumns(); + it = hidden.iterator(); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 1); + assertEquals(region[1], 7); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 13); + assertEquals(region[1], 14); + + assertTrue(it.hasNext()); + region = it.next(); + assertEquals(region[0], 34); + assertEquals(region[1], 34); + } + } diff --git a/test/jalview/gui/SequenceRendererTest.java b/test/jalview/gui/SequenceRendererTest.java index 359377a..d3d6476 100644 --- a/test/jalview/gui/SequenceRendererTest.java +++ b/test/jalview/gui/SequenceRendererTest.java @@ -22,6 +22,7 @@ package jalview.gui; import static org.testng.Assert.assertEquals; +import jalview.api.AlignViewportI; import jalview.bin.Jalview; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; @@ -41,7 +42,7 @@ import org.testng.annotations.Test; public class SequenceRendererTest { AlignmentI al; - AlignViewport av; + AlignViewportI av; SequenceI seq1; diff --git a/test/jalview/hmmer/HMMERTest.java b/test/jalview/hmmer/HMMERTest.java new file mode 100644 index 0000000..8f96d04 --- /dev/null +++ b/test/jalview/hmmer/HMMERTest.java @@ -0,0 +1,132 @@ +package jalview.hmmer; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import jalview.bin.Jalview; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; +import jalview.io.HMMFile; +import jalview.util.MessageManager; +import jalview.ws.params.ArgumentI; +import jalview.ws.params.simple.Option; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.ArrayList; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class HMMERTest { + + AlignFrame frame; + + @BeforeClass(alwaysRun = true) + public void setUpBeforeClass() throws Exception + { + /* + * NB: check HMMER_PATH in testProps.jvprops is valid for + * the machine on which this runs + */ + Jalview.main( + new String[] + { "-noquestionnaire", "-nonews", "-props", + "test/jalview/hmmer/testProps.jvprops", "-open", + "examples/uniref50.fa" }); + frame = Desktop.getAlignFrames()[0]; + } + + @AfterClass(alwaysRun = true) + public static void tearDownAfterClass() throws Exception + { + Desktop.instance.closeAll_actionPerformed(null); + } + + /** + * Test with a dependency on locally installed hmmbuild binaries + * + * @throws MalformedURLException + * @throws IOException + */ + @Test(groups = "External") + public void testHMMBuildThenHMMAlign() + throws MalformedURLException, IOException + { + /* + * run hmmbuild - note the side-effect of selecting the HMM + * sequence that gets added to the alignment + */ + testHMMBuild(); + HiddenMarkovModel hmm = frame.getSelectedHMM(); + assertNotNull(hmm); + + /* + * now run hmmalign - with respect to the select HMM profile + */ + testHMMAlign(); + } + + public void testHMMBuild() + { + /* + * set up argument to run hmmbuild for the alignment + */ + ArrayList params = new ArrayList<>(); + String argName = MessageManager.getString("label.hmmbuild_for"); + String argValue = MessageManager.getString("label.alignment"); + params.add( + new Option(argName, null, false, null, argValue, null, null)); + + HMMBuild builder = new HMMBuild(frame, params); + builder.run(); + + SequenceI seq = frame.getViewport().getAlignment().getSequenceAt(0); + HiddenMarkovModel hmm = seq.getHMM(); + assertNotNull(hmm); + + assertEquals(hmm.getLength(), 148); + assertEquals(hmm.getAlphabetType(), "amino"); + assertEquals(hmm.getName(), "Alignment_HMM"); + assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), + "0.648193"); + } + + public void testHMMAlign() + { + HMMAlign thread = new HMMAlign(frame, + new ArrayList()); + thread.run(); + + AlignFrame[] alignFrames = Desktop.getAlignFrames(); + if (alignFrames == null) + { + fail("No align frame loaded"); + } + + /* + * now have the original align frame, and another for realigned sequences + */ + assertEquals(alignFrames.length, 2); + AlignmentI original = alignFrames[0].getViewport().getAlignment(); + assertNotNull(original); + AlignmentI realigned = alignFrames[1].getViewport().getAlignment(); + assertNotNull(realigned); + assertNotNull(original.getHmmConsensus()); + assertNotNull(realigned.getHmmConsensus()); + + SequenceI ferCapan = original.findName("FER_CAPAN"); + assertTrue(ferCapan.getSequenceAsString().startsWith("MA------SVSAT")); + + SequenceI ferCapanRealigned = realigned.findName("FER_CAPAN"); + assertTrue(ferCapanRealigned.getSequenceAsString() + .startsWith("-------m-A----SVSAT")); + } +} + diff --git a/test/jalview/hmmer/testProps.jvprops b/test/jalview/hmmer/testProps.jvprops new file mode 100644 index 0000000..05cd493 --- /dev/null +++ b/test/jalview/hmmer/testProps.jvprops @@ -0,0 +1,88 @@ +#---JalviewX Properties File--- +#Fri Apr 25 09:54:25 BST 2014 +SCREEN_Y=768 +SCREEN_X=936 +SHOW_WSDISCOVERY_ERRORS=true +LATEST_VERSION=2.8.0b1 +SHOW_CONSERVATION=true +JALVIEW_RSS_WINDOW_SCREEN_WIDTH=550 +JAVA_CONSOLE_SCREEN_WIDTH=450 +LAST_DIRECTORY=/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples +ID_ITALICS=true +SORT_ALIGNMENT=No sort +SHOW_IDENTITY=true +WSMENU_BYHOST=false +SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$ +SHOW_FULLSCREEN=false +RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar +FONT_NAME=SansSerif +BLC_JVSUFFIX=true +VERSION_CHECK=false +YEAR=2011 +SHOW_DBREFS_TOOLTIP=true +MSF_JVSUFFIX=true +SCREENGEOMETRY_HEIGHT=1600 +JAVA_CONSOLE_SCREEN_Y=475 +JAVA_CONSOLE_SCREEN_X=830 +PFAM_JVSUFFIX=true +PIR_JVSUFFIX=true +STARTUP_FILE=http\://www.jalview.org/examples/exampleFile_2_3.jar +JAVA_CONSOLE_SCREEN_HEIGHT=162 +PIR_MODELLER=false +GAP_SYMBOL=- +SHOW_QUALITY=true +SHOW_OCCUPANCY=true +SHOW_GROUP_CONSERVATION=false +SHOW_JWS2_SERVICES=true +SHOW_NPFEATS_TOOLTIP=true +FONT_STYLE=plain +ANTI_ALIAS=false +SORT_BY_TREE=false +RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$ +AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton +JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328 +SHOW_GROUP_CONSENSUS=false +SHOW_CONSENSUS_HISTOGRAM=true +SHOW_OVERVIEW=false +AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle +FIGURE_AUTOIDWIDTH=false +SCREEN_WIDTH=900 +ANNOTATIONCOLOUR_MIN=ffc800 +SHOW_STARTUP_FILE=false +RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out +DEFAULT_FILE_FORMAT=FASTA +SHOW_JAVA_CONSOLE=false +VERSION=2.8b1 +FIGURE_USERIDWIDTH= +WSMENU_BYTYPE=false +DEFAULT_COLOUR=None +NOQUESTIONNAIRES=true +JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM +BUILD_DATE=01 November 2013 +PILEUP_JVSUFFIX=true +SHOW_CONSENSUS_LOGO=false +SCREENGEOMETRY_WIDTH=2560 +SHOW_ANNOTATIONS=true +JALVIEW_RSS_WINDOW_SCREEN_Y=0 +USAGESTATS=false +JALVIEW_RSS_WINDOW_SCREEN_X=0 +SHOW_UNCONSERVED=false +SHOW_JVSUFFIX=true +DAS_LOCAL_SOURCE= +SCREEN_HEIGHT=650 +ANNOTATIONCOLOUR_MAX=ff0000 +AUTO_CALC_CONSENSUS=true +FASTA_JVSUFFIX=true +DAS_ACTIVE_SOURCE=uniprot\t +JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws +PAD_GAPS=false +CLUSTAL_JVSUFFIX=true +SHOW_ENFIN_SERVICES=true +FONT_SIZE=10 +RIGHT_ALIGN_IDS=false +USE_PROXY=false +WRAP_ALIGNMENT=false +#DAS_REGISTRY_URL=http\://www.dasregistry.org/das/ # retired 01/05/2015 +DAS_REGISTRY_URL=http\://www.ebi.ac.uk/das-srv/registry/das/ +logs.Jalview.level=DEBUG +HMMER_PATH=/Users/gmcarstairs/software/hmmer-3.1b2-macosx-intel/binaries diff --git a/test/jalview/io/AnnotatedPDBFileInputTest.java b/test/jalview/io/AnnotatedPDBFileInputTest.java index e14a478..c0038a1 100644 --- a/test/jalview/io/AnnotatedPDBFileInputTest.java +++ b/test/jalview/io/AnnotatedPDBFileInputTest.java @@ -39,6 +39,7 @@ import jalview.structure.StructureImportSettings.StructureParser; import java.io.File; import java.util.List; +import org.junit.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; @@ -101,18 +102,19 @@ public class AnnotatedPDBFileInputTest } } - @Test(groups = { "Functional" }) + @Test(groups = { "Functional" }, enabled = false) public void checkPDBannotationSource() { - + Assert.fail( + "This test is incorrect - does not verify that JmolParser's annotation rows can be recognised as generated by the Jmol parser."); for (SequenceI asq : al.getSequences()) { for (AlignmentAnnotation aa : asq.getAnnotation()) { System.out.println("CalcId: " + aa.getCalcId()); - if (StructureImportSettings.getDefaultPDBFileParser().equals( - StructureParser.JALVIEW_PARSER)) + if (StructureImportSettings.getDefaultPDBFileParser() + .equals(StructureParser.JALVIEW_PARSER)) { assertTrue(MCview.PDBfile.isCalcIdForFile(aa, pdbId)); } diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java index b3db4de..2b8a62f 100644 --- a/test/jalview/io/CrossRef2xmlTests.java +++ b/test/jalview/io/CrossRef2xmlTests.java @@ -45,6 +45,7 @@ import junit.extensions.PA; import org.testng.Assert; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @Test(singleThreaded = true) @@ -59,6 +60,14 @@ public class CrossRef2xmlTests extends Jalview2xmlBase JvOptionPane.setMockResponse(JvOptionPane.CANCEL_OPTION); } + @DataProvider(name = "initialAccessions") + static Object[][] getAccessions() + { + return new String[][] { { "UNIPROT", "P00338" }, + { "UNIPROT", "Q8Z9G6" }, + { "ENSEMBLGENOMES", "CAD01290" } }; + } + /** * test store and recovery of all reachable cross refs from all reachable * crossrefs for one or more fetched db refs. Currently, this test has a known @@ -66,8 +75,13 @@ public class CrossRef2xmlTests extends Jalview2xmlBase * * @throws Exception */ - @Test(groups = { "Operational" }, enabled = true) - public void testRetrieveAndShowCrossref() throws Exception + @Test( + groups = + { "Operational" }, + dataProvider = "initialAccessions", + enabled = true) + public void testRetrieveAndShowCrossref(String forSource, + String forAccession) throws Exception { List failedDBRetr = new ArrayList<>(); @@ -97,8 +111,8 @@ public class CrossRef2xmlTests extends Jalview2xmlBase List keyseq = new ArrayList<>(); Map savedProjects = new HashMap<>(); - for (String[] did : new String[][] { { "UNIPROT", "P00338" } }) - { +// for (String[] did : new String[][] { { "UNIPROT", "P00338" } }) +// { // pass counters - 0 - first pass, 1 means retrieve project rather than // perform action int pass1 = 0, pass2 = 0, pass3 = 0; @@ -108,7 +122,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase // { pass 2 = 0 { pass 3 = 0 } } do { - String first = did[0] + " " + did[1]; + String first = forSource + " " + forAccession;//did[0] + " " + did[1]; AlignFrame af = null; boolean dna; AlignmentI retral; @@ -120,7 +134,8 @@ public class CrossRef2xmlTests extends Jalview2xmlBase // retrieve dbref List afs = jalview.gui.SequenceFetcher.fetchAndShow( - did[0], did[1]); + forSource, forAccession); + // did[0], did[1]); if (afs.size() == 0) { failedDBRetr.add("Didn't retrieve " + first); @@ -416,7 +431,7 @@ public class CrossRef2xmlTests extends Jalview2xmlBase pass1++; } } while (pass1 < 3); - } + if (failedXrefMenuItems.size() > 0) { for (String s : failedXrefMenuItems) diff --git a/test/jalview/io/FileFormatsTest.java b/test/jalview/io/FileFormatsTest.java index 7810504..724bae0 100644 --- a/test/jalview/io/FileFormatsTest.java +++ b/test/jalview/io/FileFormatsTest.java @@ -55,7 +55,7 @@ public class FileFormatsTest @Test(groups = "Functional") public void testGetReadableFormats() { - String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]"; + String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3]"; FileFormats formats = FileFormats.getInstance(); assertEquals(formats.getReadableFormats().toString(), expected); } @@ -63,25 +63,25 @@ public class FileFormatsTest @Test(groups = "Functional") public void testGetWritableFormats() { - String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]"; + String expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]"; FileFormats formats = FileFormats.getInstance(); assertEquals(formats.getWritableFormats(true).toString(), expected); - expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Jalview]"; + expected = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Jalview, HMMER3]"; assertEquals(formats.getWritableFormats(false).toString(), expected); } @Test(groups = "Functional") public void testDeregisterFileFormat() { - String writable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]"; - String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]"; + String writable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]"; + String readable = "[Fasta, PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3]"; FileFormats formats = FileFormats.getInstance(); assertEquals(formats.getWritableFormats(true).toString(), writable); assertEquals(formats.getReadableFormats().toString(), readable); formats.deregisterFileFormat(FileFormat.Fasta.getName()); - writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP]"; - readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview]"; + writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3]"; + readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3]"; assertEquals(formats.getWritableFormats(true).toString(), writable); assertEquals(formats.getReadableFormats().toString(), readable); @@ -89,8 +89,8 @@ public class FileFormatsTest * re-register the format: it gets added to the end of the list */ formats.registerFileFormat(FileFormat.Fasta); - writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, Fasta]"; - readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, Fasta]"; + writable = "[PFAM, Stockholm, PIR, BLC, AMSA, JSON, PileUp, MSF, Clustal, PHYLIP, HMMER3, Fasta]"; + readable = "[PFAM, Stockholm, PIR, BLC, AMSA, HTML, RNAML, JSON, PileUp, MSF, Clustal, PHYLIP, GFF or Jalview features, PDB, mmCIF, Jalview, HMMER3, Fasta]"; assertEquals(formats.getWritableFormats(true).toString(), writable); assertEquals(formats.getReadableFormats().toString(), readable); } diff --git a/test/jalview/io/FormatAdapterTest.java b/test/jalview/io/FormatAdapterTest.java index b500266..3812a09 100644 --- a/test/jalview/io/FormatAdapterTest.java +++ b/test/jalview/io/FormatAdapterTest.java @@ -56,8 +56,17 @@ public class FormatAdapterTest { try { - AlignmentI al = new FormatAdapter().readFile("examples/uniref50.fa", + AlignmentI al; + if (format == FileFormat.HMMER3) + { + al = new FormatAdapter().readFile("examples/uniref50.hmm", + DataSourceType.FILE, FileFormat.HMMER3); + } + else + { + al = new FormatAdapter().readFile("examples/uniref50.fa", DataSourceType.FILE, FileFormat.Fasta); + } /* * 'gap' is the gap character used in the alignment data file here, @@ -73,8 +82,9 @@ public class FormatAdapterTest AlignmentI reloaded = new FormatAdapter().readFile(formatted, DataSourceType.PASTE, format); List reread = reloaded.getSequences(); - assertEquals("Wrong number of reloaded sequences", seqs.length, - reread.size()); + assertEquals("Wrong number of reloaded sequences", seqs.length, + reread.size()); + int i = 0; for (SequenceI seq : reread) @@ -131,7 +141,7 @@ public class FormatAdapterTest @DataProvider(name = "formats") static Object[][] getFormats() { - List both = new ArrayList(); + List both = new ArrayList<>(); for (FileFormatI format : FileFormats.getInstance().getFormats()) { if (format.isReadable() && format.isWritable() diff --git a/test/jalview/io/HMMFileTest.java b/test/jalview/io/HMMFileTest.java new file mode 100644 index 0000000..cf74f55 --- /dev/null +++ b/test/jalview/io/HMMFileTest.java @@ -0,0 +1,531 @@ +package jalview.io; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import jalview.datamodel.HMMNode; +import jalview.datamodel.HiddenMarkovModel; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import junit.extensions.PA; + +public class HMMFileTest { + + HMMFile fn3; + + HMMFile pKinase; + + HMMFile made1; + + @BeforeClass(alwaysRun = true) + public void setUp() throws IOException + { + fn3 = new HMMFile("test/jalview/io/test_fn3_hmm.txt", + DataSourceType.FILE); + + pKinase = new HMMFile("test/jalview/io/test_PKinase_hmm.txt", + DataSourceType.FILE); + + made1 = new HMMFile("test/jalview/io/test_MADE1_hmm.txt", + DataSourceType.FILE); + } + + @Test(groups = "Functional") + public void testParse() throws IOException + { + HiddenMarkovModel hmm = pKinase.getHMM(); + assertEquals(hmm.getName(), "Pkinase"); + assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER), "PF00069.17"); + assertEquals(hmm.getProperty(HMMFile.DESCRIPTION), + "Protein kinase domain"); + assertEquals(hmm.getLength(), 260); + assertNull(hmm.getProperty(HMMFile.MAX_LENGTH)); + assertEquals(hmm.getAlphabetType(), "amino"); + assertFalse(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION)); + assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE)); + assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE)); + assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE)); + assertTrue(hmm.getBooleanProperty(HMMFile.MAP)); + assertEquals(hmm.getProperty(HMMFile.DATE), "Thu Jun 16 11:44:06 2011"); + assertNull(hmm.getProperty(HMMFile.COMMAND_LOG)); + assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "54"); + assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), + "3.358521"); + assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3106786190"); + assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD), + "70.30 70.30"); + assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "70.30 70.30"); + assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "70.20 70.20"); + + assertEquals(hmm.getSymbols(), "ACDEFGHIKLMNPQRSTVWY"); + + assertEquals(hmm.getMatchEmissionProbability(0, 'Y'), 0.16102, 0.001d); + assertEquals(hmm.getMatchEmissionProbability(11, 'P'), 0.0130, 0.001d); + assertEquals(hmm.getMatchEmissionProbability(24, 'I'), 0.02583, 0.001d); + assertEquals(hmm.getMatchEmissionProbability(83, 'C'), 0.008549, + 0.001d); + assertEquals(hmm.getMatchEmissionProbability(332, 'E'), 0.07998, + 0.001d); + assertEquals(hmm.getMatchEmissionProbability(381, 'D'), 0.014465, + 0.001d); + assertEquals(hmm.getMatchEmissionProbability(475, 'Y'), 0.02213, + 0.001d); + + assertEquals(hmm.getInsertEmissionProbability(1, 'C'), 0.012, 0.001d); + assertEquals(hmm.getInsertEmissionProbability(14, 'H'), 0.02411, + 0.001d); + assertEquals(hmm.getInsertEmissionProbability(23, 'L'), 0.06764, + 0.001d); + assertEquals(hmm.getInsertEmissionProbability(90, 'D'), 0.0623, 0.001d); + assertEquals(hmm.getInsertEmissionProbability(374, 'T'), 0.0623, + 0.001d); + assertEquals(hmm.getInsertEmissionProbability(470, 'P'), 0.0647, + 0.001d); + + assertEquals(hmm.getStateTransitionProbability(2, 6), 0.3848, 0.001d); + assertEquals(hmm.getStateTransitionProbability(38, 3), 0.5382, 0.001d); + assertEquals(hmm.getStateTransitionProbability(305, 3), 0.2916, 0.001d); + assertEquals(hmm.getStateTransitionProbability(380, 0), 0.99, 0.001d); + assertEquals(hmm.getStateTransitionProbability(453, 1), 0.0066, 0.001d); + + assertEquals(hmm.getNodeMapPosition(3), 3); + assertEquals(hmm.getReferenceAnnotation(7), '-'); + assertEquals(hmm.getConsensusResidue(23), 't'); + assertEquals(hmm.getMaskedValue(30), '-'); + assertEquals(hmm.getConsensusStructure(56), 'S'); + + assertEquals(hmm.getNodeMapPosition(78), 136); + assertEquals(hmm.getReferenceAnnotation(93), '-'); + assertEquals(hmm.getConsensusResidue(145), 'a'); + assertEquals(hmm.getMaskedValue(183), '-'); + assertEquals(hmm.getConsensusStructure(240), 'H'); + } + + /** + * Test that Jalview can parse an HMM file even with a bunch of 'mandatory' + * fields missing (including no MAP annotation or // terminator line) + * + * @throws IOException + */ + @Test(groups = "Functional") + public void testParse_minimalFile() throws IOException + { + /* + * ALPH is absent, alphabet inferred from HMM header line + * Optional COMPO line is absent + * first line after HMM is a guide line for readability + * next line is BEGIN node insert emissions + * next line is BEGIN node transitions + * next line is first sequence node match emissions 1.1 1.2 1.3 + * next line is first sequence node insert emissions 1.4 1.5 1.6 + * last line is first sequence node transitions + */ + //@formatter:off + String hmmData = + "HMMER3\n" + + "HMM P M J\n" + + // both spec and parser require a line after the HMM line + " m->m m->i m->d i->m i->i d->m d->d\n" + + " 0.1 0.2 0.3\n" + + " 0.4 0.5 0.6 0.7 0.8 0.9 0.95\n" + + " 1 1.1 1.2 1.3 - - - - -\n" + + " 1.4 1.5 1.6\n" + + " 1.7 1.8 1.9 2.0 2.1 2.2 2.3\n" + + " 2 1.01 1.02 1.03 - - - - -\n" + + " 1.04 1.05 1.06\n" + + " 1.7 1.8 1.9 2.0 2.1 2.2 2.3\n"; + //@formatter:on + HMMFile parser = new HMMFile(hmmData, DataSourceType.PASTE); + HiddenMarkovModel hmm = parser.getHMM(); + assertNotNull(hmm); + assertEquals(hmm.getSymbols(), "PMJ"); + // no LENG property: this should return node count excluding BEGIN node + assertEquals(hmm.getLength(), 2); + + // node 1 (implicitly mapped to column 0) + double prob = hmm.getMatchEmissionProbability(0, 'p'); + assertEquals(prob, Math.pow(Math.E, -1.1)); + prob = hmm.getInsertEmissionProbability(0, 'J'); + assertEquals(prob, Math.pow(Math.E, -1.6)); + + // node 2 (implicitly mapped to column 1) + prob = hmm.getMatchEmissionProbability(1, 'M'); + assertEquals(prob, Math.pow(Math.E, -1.02)); + prob = hmm.getInsertEmissionProbability(1, 'm'); + assertEquals(prob, Math.pow(Math.E, -1.05)); + } + + @Test(groups = "Functional") + public void testParseHeaderLines_amino() throws IOException + { + FileReader fr = new FileReader( + new File("test/jalview/io/test_fn3_hmm.txt")); + BufferedReader br = new BufferedReader(fr); + HiddenMarkovModel hmm = new HiddenMarkovModel(); + HMMFile testee = new HMMFile(); + PA.setValue(testee, "hmm", hmm); + testee.parseHeaderLines(br); + br.close(); + fr.close(); + + assertEquals(hmm.getName(), "fn3"); + assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER), "PF00041.13"); + assertEquals(hmm.getProperty(HMMFile.DESCRIPTION), + "Fibronectin type III domain"); + assertEquals(hmm.getProperty(HMMFile.LENGTH), "86"); + assertNull(hmm.getProperty(HMMFile.MAX_LENGTH)); + assertEquals(hmm.getAlphabetType(), "amino"); + assertFalse(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION)); + assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE)); + assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE)); + assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE)); + + assertTrue(hmm.getBooleanProperty(HMMFile.MAP)); + assertEquals(hmm.getProperty(HMMFile.DATE), "Fri Jun 20 08:22:31 2014"); + assertNull(hmm.getProperty(HMMFile.COMMAND_LOG)); + assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "106"); + assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), + "11.415833"); + assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3564431818"); + assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD), "8.00 7.20"); + assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "8.00 7.20"); + assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "7.90 7.90"); + assertEquals(hmm.getViterbi(), "-9.7737 0.71847"); + assertEquals(hmm.getMSV(), "-9.4043 0.71847"); + assertEquals(hmm.getForward(), "-3.8341 0.71847"); + } + + @Test(groups = "Functional") + public void testParseHeaderLines_dna() throws IOException + { + FileReader fr = new FileReader( + new File("test/jalview/io/test_MADE1_hmm.txt")); + BufferedReader br = new BufferedReader(fr); + HiddenMarkovModel hmm = new HiddenMarkovModel(); + HMMFile testee = new HMMFile(); + PA.setValue(testee, "hmm", hmm); + testee.parseHeaderLines(br); + br.close(); + fr.close(); + + assertEquals(hmm.getName(), "MADE1"); + assertEquals(hmm.getProperty(HMMFile.ACCESSION_NUMBER), + "DF0000629.2"); + assertEquals(hmm.getProperty(HMMFile.DESCRIPTION), + "MADE1 (MAriner Derived Element 1), a TcMar-Mariner DNA transposon"); + assertEquals(hmm.getProperty(HMMFile.LENGTH), "80"); + assertEquals(hmm.getProperty(HMMFile.MAX_LENGTH), "426"); + assertEquals(hmm.getAlphabetType(), "DNA"); + assertTrue(hmm.getBooleanProperty(HMMFile.REFERENCE_ANNOTATION)); + assertFalse(hmm.getBooleanProperty(HMMFile.MASKED_VALUE)); + assertTrue(hmm.getBooleanProperty(HMMFile.CONSENSUS_RESIDUE)); + assertFalse(hmm.getBooleanProperty(HMMFile.CONSENSUS_STRUCTURE)); + assertTrue(hmm.getBooleanProperty(HMMFile.MAP)); + assertEquals(hmm.getProperty(HMMFile.DATE), "Tue Feb 19 20:33:41 2013"); + assertNull(hmm.getProperty(HMMFile.COMMAND_LOG)); + assertEquals(hmm.getProperty(HMMFile.NUMBER_OF_SEQUENCES), "1997"); + assertEquals(hmm.getProperty(HMMFile.EFF_NUMBER_OF_SEQUENCES), "3.911818"); + assertEquals(hmm.getProperty(HMMFile.CHECK_SUM), "3015610723"); + assertEquals(hmm.getProperty(HMMFile.GATHERING_THRESHOLD), + "2.324 4.234"); + assertEquals(hmm.getProperty(HMMFile.TRUSTED_CUTOFF), "2.343 1.212"); + assertEquals(hmm.getProperty(HMMFile.NOISE_CUTOFF), "2.354 5.456"); + assertEquals(hmm.getViterbi(), "-9.3632 0.71858"); + assertEquals(hmm.getMSV(), "-8.5786 0.71858"); + assertEquals(hmm.getForward(), "-3.4823 0.71858"); + } + + @Test(groups = "Functional") + public void testFillList() throws IOException + { + Scanner scanner1 = new Scanner("1.3 2.4 5.3 3.9 9.8 4.7 4.3 2.3 6.9"); + ArrayList filledArray = new ArrayList<>(); + + filledArray.add(0.27253); + filledArray.add(0.0907); + filledArray.add(0.00499); + filledArray.add(0.02024); + filledArray.add(0.00005); + filledArray.add(0.00909); + filledArray.add(0.01357); + filledArray.add(0.10026); + filledArray.add(0.001); + + double[] testList = HMMFile.parseDoubles(scanner1, 9); + + for (int i = 0; i < 9; i++) + { + assertEquals(testList[i], filledArray.get(i), 0.001d); + } + + filledArray.clear(); + scanner1.close(); + + Scanner scanner2 = new Scanner( + "1.346 5.554 35.345 5.64 1.4"); + filledArray.add(0.2603); + filledArray.add(0.00387); + filledArray.add(0d); + filledArray.add(0.00355); + filledArray.add(0.2466); + + testList = HMMFile.parseDoubles(scanner2, 5); + + for (int i = 0; i < 5; i++) + { + assertEquals(testList[i], filledArray.get(i), 0.001d); + } + } + + @Test(groups = "Functional") + public void testParseModel() throws IOException + { + FileReader fr = new FileReader( + new File("test/jalview/io/test_MADE1_hmm.txt")); + BufferedReader br = new BufferedReader(fr); + HiddenMarkovModel testHMM = new HiddenMarkovModel(); + String line = null; + do + { + line = br.readLine(); // skip header lines up to HMM plus one + } while (!line.startsWith("HMM ")); + br.readLine(); + + made1.parseModel(br); + testHMM = made1.getHMM(); + + br.close(); + fr.close(); + + assertEquals(testHMM.getMatchEmissionProbability(1, 'C'), 0.09267, + 0.001d); + assertEquals(testHMM.getMatchEmissionProbability(25, 'G'), 0.07327, + 0.001d); + assertEquals(testHMM.getMatchEmissionProbability(1092, 'C'), 0.04184, + 0.001d); + assertEquals(testHMM.getMatchEmissionProbability(1107, 'G'), 0.07, + 0.001d); + + assertEquals(testHMM.getInsertEmissionProbability(0, 'G'), 0.25, + 0.001d); + assertEquals(testHMM.getInsertEmissionProbability(247, 'T'), 0.2776, + 0.001d); + assertEquals(testHMM.getInsertEmissionProbability(1096, 'T'), 0.25, + 0.001d); + assertEquals(testHMM.getInsertEmissionProbability(1111, 'T'), 0.25, + 0.001d); + + assertEquals(testHMM.getStateTransitionProbability(1, 0), 0.9634, + 0.001d); + assertEquals(testHMM.getStateTransitionProbability(5, 1), 0.0203, + 0.001d); + assertEquals(testHMM.getStateTransitionProbability(14, 3), 0.2515, + 0.001d); + assertEquals(testHMM.getStateTransitionProbability(65, 4), 0.78808, + 0.001d); + assertEquals(testHMM.getStateTransitionProbability(1080, 2), 0.01845, + 0.001d); + assertEquals(testHMM.getStateTransitionProbability(1111, 6), + Double.NEGATIVE_INFINITY); + } + + @Test(groups = "Functional") + public void testParseAnnotations() + { + HMMFile testFile = new HMMFile(); + HiddenMarkovModel hmm = new HiddenMarkovModel(); + PA.setValue(testFile, "hmm", hmm); + + List nodes = new ArrayList<>(); + nodes.add(new HMMNode()); // BEGIN node + + hmm.setProperty(HMMFile.CONSENSUS_RESIDUE, "yes"); + hmm.setProperty(HMMFile.MAP, "yes"); + hmm.setProperty(HMMFile.REFERENCE_ANNOTATION, "yes"); + hmm.setProperty(HMMFile.CONSENSUS_STRUCTURE, "yes"); + hmm.setProperty(HMMFile.MASKED_VALUE, "yes"); + Scanner scanner = new Scanner("1345 t t t t"); + HMMNode node = new HMMNode(); + nodes.add(node); + testFile.parseAnnotations(scanner, node); + + hmm.setProperty(HMMFile.CONSENSUS_RESIDUE, "yes"); + hmm.setProperty(HMMFile.MAP, "no"); + hmm.setProperty(HMMFile.REFERENCE_ANNOTATION, "yes"); + hmm.setProperty(HMMFile.CONSENSUS_STRUCTURE, "no"); + hmm.setProperty(HMMFile.MASKED_VALUE, "no"); + Scanner scanner2 = new Scanner("- y x - -"); + node = new HMMNode(); + nodes.add(node); + testFile.parseAnnotations(scanner2, node); + + hmm.setNodes(nodes); + + assertEquals(hmm.getNodeMapPosition(1), 1345); + assertEquals(hmm.getConsensusResidue(1), 't'); + assertEquals(hmm.getReferenceAnnotation(1), 't'); + assertEquals(hmm.getMaskedValue(1), 't'); + assertEquals(hmm.getConsensusStructure(1), 't'); + + scanner.close(); + } + + /** + * tests to see if file produced by the output matches the file from the input + * + * @throws IOException + */ + @Test(groups = "Functional") + public void testPrint_roundTrip() throws IOException + { + String output = pKinase.print(); + HMMFile pKinaseClone = new HMMFile( + new FileParse(output, DataSourceType.PASTE)); + HiddenMarkovModel pKinaseHMM = pKinase.getHMM(); + HiddenMarkovModel pKinaseCloneHMM = pKinaseClone.getHMM(); + + checkModelsMatch(pKinaseHMM, pKinaseCloneHMM); + } + + /** + * A helper method to check two HMM models have the same values + * + * @param model1 + * @param model2 + */ + protected void checkModelsMatch(HiddenMarkovModel model1, + HiddenMarkovModel model2) + { + assertEquals(model1.getLength(), model2.getLength()); + + for (int i = 0; i < model1.getLength(); i++) + { + String msg = "For Node" + i; + assertEquals(model1.getNode(i).getMatchEmissions(), + model2.getNode(i).getMatchEmissions(), msg); + assertEquals(model1.getNode(i).getInsertEmissions(), + model2.getNode(i).getInsertEmissions(), msg); + assertEquals(model1.getNode(i).getStateTransitions(), + model2.getNode(i).getStateTransitions(), msg); + + if (i > 0) + { + assertEquals(model1.getNodeMapPosition(i), + model2.getNodeMapPosition(i), msg); + assertEquals(model1.getReferenceAnnotation(i), + model2.getReferenceAnnotation(i), msg); + assertEquals(model1.getConsensusResidue(i), + model2.getConsensusResidue(i), msg); + } + } + } + + @Test(groups = "Functional") + public void testAppendProperties() throws FileNotFoundException + { + StringBuilder sb = new StringBuilder(); + fn3.appendProperties(sb); + + Scanner testScanner = new Scanner(sb.toString()); + + String[] expected = new String[] { "HMMER3/f [3.1b1 | May 2013]", + "NAME fn3", "ACC PF00041.13", + "DESC Fibronectin type III domain", "LENG 86", "ALPH amino", + "RF no", "MM no", "CONS yes", "CS yes", "MAP yes", + "DATE Fri Jun 20 08:22:31 2014", "NSEQ 106", "EFFN 11.415833", + "CKSUM 3564431818", "GA 8.00 7.20", "TC 8.00 7.20", + "NC 7.90 7.90", "STATS LOCAL MSV -9.4043 0.71847", + "STATS LOCAL VITERBI -9.7737 0.71847", + "STATS LOCAL FORWARD -3.8341 0.71847" }; + + for (String value : expected) + { + assertEquals(testScanner.nextLine(), value); + } + + testScanner.close(); + } + + @Test(groups = "Functional") + public void testAppendModelAsString() throws FileNotFoundException + { + StringBuilder sb = new StringBuilder(); + fn3.appendModelAsString(sb); + String string = sb.toString(); + + assertEquals(findValue(2, 2, 2, string), "4.42225"); + assertEquals(findValue(12, 14, 1, string), "2.79307"); + assertEquals(findValue(6, 24, 3, string), "0.48576"); + assertEquals(findValue(19, 33, 2, string), "4.58477"); + assertEquals(findValue(20, 64, 2, string), "3.61505"); + assertEquals(findValue(3, 72, 3, string), "6.81068"); + assertEquals(findValue(10, 80, 2, string), "2.69355"); + assertEquals(findValue(16, 65, 1, string), "2.81003"); + assertEquals(findValue(14, 3, 1, string), "2.69012"); + assertEquals(findValue(11, 32, 1, string), "4.34805"); + } + + /** + * A helper method to find a token in the model string + * + * @param symbolIndex + * index of symbol being searched. First symbol has index 1. + * @param nodeIndex + * index of node being searched. Begin node has index 0. First node + * has index 1. + * @param line + * index of line being searched in node. First line has index 1. + * @param model + * string model being searched + * @return value at specified position + */ + private String findValue(int symbolIndex, int nodeIndex, int line, + String model) + { + String value = ""; + Scanner scanner = new Scanner(model); + scanner.nextLine(); + scanner.nextLine(); + + for (int lineIndex = 0; lineIndex < line - 1; lineIndex++) + { + scanner.nextLine(); + } + for (int node = 0; node < nodeIndex; node++) + { + scanner.nextLine(); + scanner.nextLine(); + scanner.nextLine(); + } + + for (int symbol = 0; symbol < symbolIndex; symbol++) + { + value = scanner.next(); + if ("COMPO".equals(value)) + { + scanner.next(); + } + else if (value.length() < 7) + { + scanner.next(); + } + } + scanner.close(); + return value; + } +} + diff --git a/test/jalview/io/JSONFileTest.java b/test/jalview/io/JSONFileTest.java index 158c901..4cd5b54 100644 --- a/test/jalview/io/JSONFileTest.java +++ b/test/jalview/io/JSONFileTest.java @@ -42,6 +42,7 @@ import jalview.schemes.ResidueColourScheme; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -205,7 +206,7 @@ public class JSONFileTest TEST_SEQ_HEIGHT = expectedSeqs.size(); TEST_GRP_HEIGHT = expectedGrps.size(); TEST_ANOT_HEIGHT = expectedAnnots.size(); - TEST_CS_HEIGHT = expectedColSel.getHiddenColumnsCopy().size(); + TEST_CS_HEIGHT = expectedColSel.getNumberOfRegions(); exportSettings = new AlignExportSettingI() { @@ -325,11 +326,12 @@ public class JSONFileTest { HiddenColumns cs = testJsonFile.getHiddenColumns(); Assert.assertNotNull(cs); - Assert.assertNotNull(cs.getHiddenColumnsCopy()); - List hiddenCols = cs.getHiddenColumnsCopy(); - Assert.assertEquals(hiddenCols.size(), TEST_CS_HEIGHT); - Assert.assertEquals(hiddenCols.get(0), expectedColSel - .getHiddenColumnsCopy().get(0), + + Iterator it = cs.iterator(); + Iterator colselit = expectedColSel.iterator(); + Assert.assertTrue(it.hasNext()); + Assert.assertEquals(cs.getNumberOfRegions(), TEST_CS_HEIGHT); + Assert.assertEquals(it.next(), colselit.next(), "Mismatched hidden columns!"); } @@ -492,8 +494,8 @@ public class JSONFileTest + actualGrp.getColourText()); System.out.println(expectedGrp.getDisplayBoxes() + " | " + actualGrp.getDisplayBoxes()); - System.out.println(expectedGrp.getIgnoreGapsConsensus() + " | " - + actualGrp.getIgnoreGapsConsensus()); + System.out.println(expectedGrp.isIgnoreGapsConsensus() + " | " + + actualGrp.isIgnoreGapsConsensus()); System.out.println(expectedGrp.getSequences().size() + " | " + actualGrp.getSequences().size()); System.out.println(expectedGrp.getStartRes() + " | " @@ -510,8 +512,8 @@ public class JSONFileTest if (expectedGrp.getName().equals(actualGrp.getName()) && expectedGrp.getColourText() == actualGrp.getColourText() && expectedGrp.getDisplayBoxes() == actualGrp.getDisplayBoxes() - && expectedGrp.getIgnoreGapsConsensus() == actualGrp - .getIgnoreGapsConsensus() + && expectedGrp.isIgnoreGapsConsensus() == actualGrp + .isIgnoreGapsConsensus() && colourSchemeMatches && expectedGrp.getSequences().size() == actualGrp .getSequences().size() diff --git a/test/jalview/io/Jalview2xmlBase.java b/test/jalview/io/Jalview2xmlBase.java index 15e18e3..fbdd782 100644 --- a/test/jalview/io/Jalview2xmlBase.java +++ b/test/jalview/io/Jalview2xmlBase.java @@ -76,7 +76,8 @@ public class Jalview2xmlBase @BeforeTest(alwaysRun = true) public static void clearDesktop() { - if (Desktop.instance != null && Desktop.getAlignFrames() != null) + if (Desktop.instance != null && Desktop.getFrames() != null + && Desktop.getFrames().length > 0) { Desktop.instance.closeAll_actionPerformed(null); } diff --git a/test/jalview/io/Jalview2xmlTests.java b/test/jalview/io/Jalview2xmlTests.java index e9e0782..41a6b89 100644 --- a/test/jalview/io/Jalview2xmlTests.java +++ b/test/jalview/io/Jalview2xmlTests.java @@ -44,7 +44,6 @@ import jalview.datamodel.features.FeatureMatcher; import jalview.datamodel.features.FeatureMatcherSet; import jalview.datamodel.features.FeatureMatcherSetI; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.gui.AlignmentPanel; import jalview.gui.Desktop; import jalview.gui.FeatureRenderer; @@ -771,7 +770,7 @@ public class Jalview2xmlTests extends Jalview2xmlBase AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", DataSourceType.FILE); - AlignViewport av = af.getViewport(); + AlignViewportI av = af.getViewport(); AlignmentI al = av.getAlignment(); /* diff --git a/test/jalview/io/StockholmFileTest.java b/test/jalview/io/StockholmFileTest.java index 4273e6c..1c9c79d 100644 --- a/test/jalview/io/StockholmFileTest.java +++ b/test/jalview/io/StockholmFileTest.java @@ -22,17 +22,22 @@ package jalview.io; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; +import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.Annotation; +import jalview.datamodel.DBRefEntry; +import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; import java.io.File; +import java.io.IOException; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; @@ -230,8 +235,8 @@ public class StockholmFileTest // we might want to revise this in future int aa_new_size = (aa_new == null ? 0 : aa_new.length); int aa_original_size = (aa_original == null ? 0 : aa_original.length); - Map orig_groups = new HashMap(); - Map new_groups = new HashMap(); + Map orig_groups = new HashMap<>(); + Map new_groups = new HashMap<>(); if (aa_new != null && aa_original != null) { @@ -654,4 +659,273 @@ public class StockholmFileTest testAlignmentEquivalence(al, newAl, true, true, true); } + + @Test(groups = { "Functional" }) + public void testTypeToDescription() + { + assertEquals("Secondary Structure", + StockholmFile.typeToDescription("SS")); + assertEquals("Surface Accessibility", + StockholmFile.typeToDescription("SA")); + assertEquals("transmembrane", StockholmFile.typeToDescription("TM")); + assertEquals("Posterior Probability", + StockholmFile.typeToDescription("PP")); + assertEquals("ligand binding", StockholmFile.typeToDescription("LI")); + assertEquals("active site", StockholmFile.typeToDescription("AS")); + assertEquals("intron", StockholmFile.typeToDescription("IN")); + assertEquals("interacting residue", + StockholmFile.typeToDescription("IR")); + assertEquals("accession", StockholmFile.typeToDescription("AC")); + assertEquals("organism", StockholmFile.typeToDescription("OS")); + assertEquals("class", StockholmFile.typeToDescription("CL")); + assertEquals("description", StockholmFile.typeToDescription("DE")); + assertEquals("reference", StockholmFile.typeToDescription("DR")); + assertEquals("look", StockholmFile.typeToDescription("LO")); + assertEquals("Reference Positions", + StockholmFile.typeToDescription("RF")); + + // case-sensitive: + assertEquals("Rf", StockholmFile.typeToDescription("Rf")); + assertEquals("junk", StockholmFile.typeToDescription("junk")); + assertEquals("", StockholmFile.typeToDescription("")); + assertNull(StockholmFile.typeToDescription(null)); + } + + @Test(groups = { "Functional" }) + public void testDescriptionToType() + { + assertEquals("SS", + StockholmFile.descriptionToType("Secondary Structure")); + assertEquals("SA", + StockholmFile.descriptionToType("Surface Accessibility")); + assertEquals("TM", StockholmFile.descriptionToType("transmembrane")); + + // test is not case-sensitive: + assertEquals("SS", + StockholmFile.descriptionToType("secondary structure")); + + // test is white-space sensitive: + assertNull(StockholmFile.descriptionToType("secondary structure ")); + + assertNull(StockholmFile.descriptionToType("any old junk")); + assertNull(StockholmFile.descriptionToType("")); + assertNull(StockholmFile.descriptionToType(null)); + } + + @Test(groups = { "Functional" }) + public void testPrint() + { + SequenceI seq1 = new Sequence("seq1", "LKMF-RS-Q"); + SequenceI seq2 = new Sequence("seq2/10-15", "RRS-LIP-"); + SequenceI[] seqs = new SequenceI[] { seq1, seq2 }; + AlignmentI al = new Alignment(seqs); + + StockholmFile testee = new StockholmFile(al); + + /* + * basic output (sequences only): + * sequence ids are padded with 9 spaces more than the widest id + */ + String output = testee.print(seqs, true); + String expected = "# STOCKHOLM 1.0\n" + "seq1/1-7 LKMF-RS-Q\n" + + "seq2/10-15 RRS-LIP-\n//\n"; + assertEquals(expected, output); + + /* + * add some dbrefs + */ + seq1.addDBRef(new DBRefEntry("PFAM", "1", "PF00111")); + seq1.addDBRef(new DBRefEntry("UNIPROT", "1", "P83527")); + seq2.addDBRef(new DBRefEntry("RFAM", "1", "AY119185.1")); + seq2.addDBRef(new DBRefEntry("EMBL", "1", "AF125575")); + output = testee.print(seqs, true); + // PFAM and RFAM dbrefs should be output as AC, others as DR + expected = "# STOCKHOLM 1.0\n" + "#=GS seq1/1-7 AC PF00111\n" + + "#=GS seq1/1-7 DR UNIPROT ; P83527\n" + + "#=GS seq2/10-15 AC AY119185.1\n" + + "#=GS seq2/10-15 DR EMBL ; AF125575\n" + + "seq1/1-7 LKMF-RS-Q\n" + + "seq2/10-15 RRS-LIP-\n//\n"; + assertEquals(expected, output); + + /* + * add some sequence and alignment annotation + */ + Annotation[] anns = new Annotation[5]; + for (int i = 0; i < anns.length; i++) + { + anns[i] = new Annotation(String.valueOf((char) ('B' + i)), + "Desc " + i, + (char) ('C' + i), i + 3); + } + + // expect "secondary structure" to be output as #=GR seqid SS + // using the secondary structure character (CDEFG) not display char (BCDEF) + AlignmentAnnotation aa1 = new AlignmentAnnotation("secondary structure", + "ssdesc", anns); + aa1.sequenceRef = seq1; + seq1.addAlignmentAnnotation(aa1); + al.addAnnotation(aa1); + + // "sec structure" should not be output as no corresponding feature id + AlignmentAnnotation aa2 = new AlignmentAnnotation("sec structure", + "ssdesc", anns); + aa2.sequenceRef = seq2; + seq2.addAlignmentAnnotation(aa2); + al.addAnnotation(aa2); + + // alignment annotation for Reference Positions: output as #=GC RF + AlignmentAnnotation aa3 = new AlignmentAnnotation("reference positions", + "refpos", anns); + al.addAnnotation(aa3); + + // 'seq' annotation: output as seq_cons + AlignmentAnnotation aa4 = new AlignmentAnnotation("seq", "seqdesc", + anns); + al.addAnnotation(aa4); + + // 'intron' annotation: output as IN_cons + AlignmentAnnotation aa5 = new AlignmentAnnotation("intron", + "introndesc", anns); + al.addAnnotation(aa5); + + // 'binding site' annotation: output as binding_site + AlignmentAnnotation aa6 = new AlignmentAnnotation("binding site", + "bindingdesc", anns); + al.addAnnotation(aa6); + + // 'autocalc' annotation should not be output + AlignmentAnnotation aa7 = new AlignmentAnnotation("Consensus", + "consensusdesc", anns); + aa7.autoCalculated = true; + al.addAnnotation(aa7); + + // hidden annotation should not be output + AlignmentAnnotation aa8 = new AlignmentAnnotation("domains", + "domaindesc", anns); + aa8.visible = false; + al.addAnnotation(aa8); + + output = testee.print(seqs, true); + //@formatter:off + expected = + "# STOCKHOLM 1.0\n" + + "#=GS seq1/1-7 AC PF00111\n" + + "#=GS seq1/1-7 DR UNIPROT ; P83527\n" + + "#=GS seq2/10-15 AC AY119185.1\n" + + "#=GS seq2/10-15 DR EMBL ; AF125575\n" + + "#=GR seq1/1-7 SS CDEFG\n" + + "seq1/1-7 LKMF-RS-Q\n" + + "seq2/10-15 RRS-LIP-\n" + + "#=GC RF BCDEF\n" + "#=GC seq_cons BCDEF\n" + + "#=GC IN_cons BCDEF\n" + "#=GC binding_site BCDEF\n" + + "//\n"; + //@formatter:on + assertEquals(expected, output); + } + + @Test(groups = "Functional") + public void testGetAnnotationCharacter() + { + SequenceI seq = new Sequence("seq", "abc--def-"); + + Annotation[] ann = new Annotation[8]; + ann[1] = new Annotation("Z", "desc", 'E', 1f); + ann[2] = new Annotation("Q", "desc", ' ', 1f); + ann[4] = new Annotation("", "desc", 'E', 1f); + ann[6] = new Annotation("ZH", "desc", 'E', 1f); + + /* + * null annotation in column (not Secondary Structure annotation) + * should answer sequence character, or '-' if null sequence + */ + assertEquals('-', + StockholmFile.getAnnotationCharacter("RF", 0, ann[0], null)); + assertEquals('d', + StockholmFile.getAnnotationCharacter("RF", 5, ann[5], seq)); + assertEquals('-', + StockholmFile.getAnnotationCharacter("RF", 8, null, seq)); + + /* + * null annotation in column (SS annotation) should answer underscore + */ + assertEquals('_', + StockholmFile.getAnnotationCharacter("SS", 0, ann[0], seq)); + + /* + * SS secondary structure symbol + */ + assertEquals('E', + StockholmFile.getAnnotationCharacter("SS", 1, ann[1], seq)); + + /* + * no SS symbol, use label instead + */ + assertEquals('Q', + StockholmFile.getAnnotationCharacter("SS", 2, ann[2], seq)); + + /* + * SS with 2 character label - second character overrides SS symbol + */ + assertEquals('H', + StockholmFile.getAnnotationCharacter("SS", 6, ann[6], seq)); + + /* + * empty display character, not SS - answers '.' + */ + assertEquals('.', + StockholmFile.getAnnotationCharacter("RF", 4, ann[4], seq)); + } + + /** + * Test to verify that gaps are input/output as underscore in STO annotation + * + * @throws IOException + */ + @Test(groups = "Functional") + public void testRoundtripWithGaps() throws IOException + { + /* + * small extract from RF00031_folded.stk + */ + // @formatter:off + String stoData = + "# STOCKHOLM 1.0\n" + + "#=GR B.taurus.4 SS .._((.))_\n" + + "B.taurus.4 AC.UGCGU.\n" + + "#=GR B.taurus.5 SS ..((_._))\n" + + "B.taurus.5 ACUU.G.CG\n" + + "//\n"; + // @formatter:on + StockholmFile parser = new StockholmFile(stoData, DataSourceType.PASTE); + SequenceI[] seqs = parser.getSeqsAsArray(); + assertEquals(2, seqs.length); + + /* + * B.taurus.4 has a trailing gap + * rendered as underscore in Stockholm annotation + */ + assertEquals("AC.UGCGU.", seqs[0].getSequenceAsString()); + AlignmentAnnotation[] anns = seqs[0].getAnnotation(); + assertEquals(1, anns.length); + AlignmentAnnotation taurus4SS = anns[0]; + assertEquals(9, taurus4SS.annotations.length); + assertEquals(" .", taurus4SS.annotations[0].displayCharacter); + assertNull(taurus4SS.annotations[2]); // gapped position + assertNull(taurus4SS.annotations[8]); // gapped position + assertEquals('(', taurus4SS.annotations[3].secondaryStructure); + assertEquals("(", taurus4SS.annotations[3].displayCharacter); + assertEquals(')', taurus4SS.annotations[7].secondaryStructure); + + /* + * output as Stockholm and verify it matches the original input + * (gaps output as underscore in annotation lines) + * note: roundtrip test works with the input lines ordered as above; + * can also parse in other orders, but then input doesn't match output + */ + AlignmentFileWriterI afile = FileFormat.Stockholm + .getWriter(new Alignment(seqs)); + String output = afile.print(seqs, false); + assertEquals(stoData, output); + } } diff --git a/test/jalview/io/test_MADE1_hmm.txt b/test/jalview/io/test_MADE1_hmm.txt new file mode 100644 index 0000000..32231db --- /dev/null +++ b/test/jalview/io/test_MADE1_hmm.txt @@ -0,0 +1,268 @@ +HMMER3/f [3.1 | February 2013] +NAME MADE1 +ACC DF0000629.2 +DESC MADE1 (MAriner Derived Element 1), a TcMar-Mariner DNA transposon +LENG 80 +MAXL 426 +ALPH DNA +RF yes +MM no +CONS yes +CS no +MAP yes +DATE Tue Feb 19 20:33:41 2013 +NSEQ 1997 +EFFN 3.911818 +CKSUM 3015610723 +GA 2.324 4.234 +TC 2.343 1.212 +NC 2.354 5.456 +STATS LOCAL MSV -8.5786 0.71858 +STATS LOCAL VITERBI -9.3632 0.71858 +STATS LOCAL FORWARD -3.4823 0.71858 +HMM A C G T + m->m m->i m->d i->m i->i d->m d->d + COMPO 1.24257 1.59430 1.62906 1.16413 + 1.38629 1.38629 1.38629 1.38629 + 0.03960 3.94183 3.94183 1.46634 0.26236 0.00000 * + 1 2.69765 2.44396 2.81521 0.24089 1 t x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03960 3.94183 3.94183 1.46634 0.26236 1.09861 0.40547 + 2 2.72939 2.37873 2.85832 0.24244 2 t x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03725 4.00179 4.00179 1.46634 0.26236 1.09861 0.40547 + 3 0.16099 3.16370 2.87328 2.99734 3 a x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03604 4.03416 4.03416 1.46634 0.26236 1.09861 0.40547 + 4 1.98862 2.42132 0.42649 2.10770 4 g x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03539 4.05203 4.05203 1.46634 0.26236 1.09861 0.40547 + 5 1.96369 2.69532 0.36534 2.32099 5 g x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03764 4.06427 3.92372 1.46634 0.26236 1.09861 0.40547 + 6 2.56994 2.11239 2.71946 0.30571 6 t x - - + 1.37159 1.41129 1.39124 1.37159 + 0.03806 3.89715 4.07214 1.50442 0.25122 1.00714 0.45454 + 7 2.58388 2.10353 2.64646 0.31253 12 t x - - + 1.38764 1.38524 1.38764 1.38465 + 0.03494 4.03864 4.09125 1.40070 0.28293 1.09237 0.40860 + 8 2.18552 2.70201 0.28821 2.64645 14 g x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03628 4.09157 3.96779 1.46634 0.26236 1.09861 0.40547 + 9 2.16916 2.82142 0.28427 2.60854 15 g x - - + 1.38091 1.39033 1.38365 1.39033 + 0.03566 4.00237 4.08886 1.38021 0.28972 1.01958 0.44745 + 10 2.45517 2.15232 2.42886 0.34277 18 t x - - + 1.39065 1.39065 1.39065 1.37335 + 0.03536 4.01212 4.09576 1.39554 0.28462 1.09775 0.40589 + 11 2.10260 2.95484 0.28160 2.64222 21 g x - - + 1.36740 1.40555 1.40555 1.36740 + 0.03843 3.92069 4.02468 1.44733 0.26814 1.09856 0.40549 + 12 2.54740 0.30185 2.61355 2.21647 26 c x - - + 1.38748 1.38276 1.38748 1.38748 + 0.03457 4.05446 4.09623 1.40847 0.28040 1.05496 0.42803 + 13 0.28443 2.72003 2.32214 2.48149 28 a x - - + 1.38740 1.38740 1.38298 1.38740 + 0.03441 4.05976 4.10001 1.41198 0.27926 1.09780 0.40587 + 14 0.29412 2.55413 2.49679 2.35701 30 a x - - + 1.38194 1.39067 1.38194 1.39067 + 0.03505 4.02482 4.10005 1.39522 0.28473 1.09929 0.40512 + 15 0.18837 2.99710 2.82270 2.77556 33 a x - - + 1.39015 1.39472 1.37503 1.38539 + 0.03725 3.97815 4.02618 1.37955 0.28994 1.10102 0.40426 + 16 0.50816 2.05151 2.22111 1.82407 37 a x - - + 1.36727 1.38730 1.39683 1.39405 + 0.04830 3.89881 3.61610 1.29026 0.32186 1.05306 0.42905 + 17 2.11260 2.73141 0.29747 2.64152 41 g x - - + 1.36913 1.40376 1.40376 1.36913 + 0.03705 3.93681 4.08299 1.44872 0.26771 1.07479 0.41759 + 18 2.24459 1.90539 2.34054 0.43234 46 t x - - + 1.33632 1.42493 1.39937 1.38665 + 0.04427 3.64574 4.06297 1.70501 0.20061 1.21309 0.35279 + 19 0.44322 2.17202 2.18055 2.03175 57 a x - - + 1.41047 1.41471 1.36338 1.35797 + 0.03970 3.81957 4.07540 1.65588 0.21186 1.22788 0.34660 + 20 0.33340 2.42691 2.40824 2.25160 66 a x - - + 1.29389 1.44615 1.37917 1.43324 + 0.04223 3.70146 4.09459 1.55158 0.23815 1.05880 0.42598 + 21 2.50563 1.98543 2.69601 0.33746 74 t x - - + 1.39462 1.39462 1.42862 1.32990 + 0.04184 3.80216 3.98177 1.80466 0.17976 1.00279 0.45705 + 22 2.54484 1.97505 2.66483 0.33806 84 t x - - + 1.39134 1.39489 1.38662 1.37246 + 0.03877 3.97504 3.95038 1.37620 0.29107 1.13932 0.38572 + 23 2.10159 2.83856 0.29282 2.61635 88 g x - - + 1.39682 1.39682 1.35536 1.39682 + 0.05046 3.75402 3.65808 1.08330 0.41321 1.13019 0.39004 + 24 2.25298 0.61854 2.50691 1.29221 90 c x - - + 1.35803 1.49605 1.46737 1.24379 + 0.06091 3.28322 3.83564 1.89752 0.16245 1.28788 0.32276 + 25 1.27819 2.23285 0.76242 1.91259 106 g x - - + 1.29024 1.67349 1.68279 1.04597 + 0.05752 3.44263 3.73311 2.58671 0.07825 1.26818 0.33037 + 26 1.86925 2.58352 0.39466 2.33986 131 g x - - + 1.31084 1.49412 1.46666 1.29002 + 0.04698 3.54257 4.07715 2.25245 0.11109 0.86163 0.54900 + 27 2.38297 1.93394 2.39162 0.39800 151 t x - - + 1.33582 1.47359 1.44163 1.30411 + 0.04951 3.48445 4.03783 2.15951 0.12260 1.21681 0.35122 + 28 2.41717 2.17810 2.62774 0.32113 170 t x - - + 1.36805 1.48060 1.37439 1.32840 + 0.04849 3.50958 4.05014 2.58370 0.07850 1.22399 0.34822 + 29 2.57764 2.35132 2.56552 0.28512 194 t x - - + 1.43829 1.43458 1.24787 1.43829 + 0.04667 3.56670 4.05428 2.49706 0.08591 1.23744 0.34267 + 30 2.47248 2.07688 2.62257 0.33172 215 t x - - + 1.25120 1.52623 1.70635 1.15531 + 0.08932 3.31524 3.01336 2.81842 0.06156 1.22909 0.34610 + 31 2.25937 2.13157 2.02027 0.43957 248 t x - - + 1.18172 1.43522 1.72841 1.28150 + 0.07936 2.93117 3.77395 2.46269 0.08906 0.60457 0.79034 + 32 2.04508 2.84981 0.30490 2.58263 280 g x - - + 1.17665 1.66785 1.66218 1.16056 + 0.05998 3.23615 3.96853 2.83684 0.06040 1.01952 0.44749 + 33 2.45103 0.38098 2.56776 1.87147 317 c x - - + 1.24153 1.52524 1.60663 1.22783 + 0.05538 3.39046 3.90294 2.73920 0.06680 1.18729 0.36391 + 34 2.22082 0.36258 2.75077 2.02704 347 c x - - + 1.15008 1.62014 1.86511 1.10673 + 0.06086 3.18178 4.04341 2.94504 0.05403 1.25991 0.33363 + 35 0.27033 2.66664 2.52541 2.43767 388 a x - - + 1.24951 1.47565 1.41392 1.42074 + 0.07123 3.00373 3.95552 3.13655 0.04440 1.28173 0.32512 + 36 2.83107 2.41670 2.97197 0.22235 439 t x - - + 1.37071 1.57683 1.38637 1.23972 + 0.05293 3.45216 3.91807 2.54402 0.08181 1.14651 0.38235 + 37 2.52322 2.25084 2.45909 0.31611 465 t x - - + 1.26335 1.55077 1.59008 1.19965 + 0.07504 3.13329 3.55006 3.08962 0.04659 1.13108 0.38962 + 38 0.45807 2.30687 1.98940 2.03143 512 a x - - + 1.15472 1.67511 1.53797 1.26320 + 0.09820 3.13076 2.99876 2.79197 0.06326 1.39915 0.28343 + 39 2.37471 0.42180 2.44763 1.80427 550 c x - - + 1.23785 1.49058 1.48364 1.35502 + 0.06081 3.19472 4.01643 2.41851 0.09327 0.94671 0.49105 + 40 2.32826 1.95481 2.36781 0.40458 578 t x - - + 1.36586 1.46001 1.43000 1.29720 + 0.05257 3.39673 4.03256 1.84862 0.17133 1.40979 0.27997 + 41 2.68669 2.13935 2.81520 0.28200 592 t x - - + 1.34965 1.42793 1.45781 1.31633 + 0.04735 3.57826 3.99988 2.09424 0.13144 1.22129 0.34934 + 42 2.55904 2.16444 2.70859 0.29952 609 t x - - + 1.12072 1.61936 1.63578 1.26895 + 0.07346 3.25910 3.42962 2.85641 0.05919 1.38363 0.28857 + 43 1.99923 1.61027 2.26343 0.57851 646 t x - - + 1.32290 1.58747 1.61095 1.11018 + 0.06656 3.08568 3.97944 2.44774 0.09046 0.75593 0.63407 + 44 0.23887 2.79899 2.55209 2.60783 675 a x - - + 1.18557 1.50323 1.59070 1.31590 + 0.05597 3.38637 3.88222 2.46900 0.08847 1.27945 0.32599 + 45 0.29593 2.53488 2.53903 2.32335 701 a x - - + 1.08710 1.54222 1.59276 1.40430 + 0.07539 2.94521 3.91062 1.91623 0.15918 1.22327 0.34852 + 46 2.58352 2.40524 2.76700 0.25955 725 t x - - + 1.19685 1.58503 1.74852 1.14293 + 0.06124 3.18279 4.02089 2.82961 0.06085 1.05474 0.42814 + 47 2.13251 2.88788 0.29508 2.50964 764 g x - - + 1.20891 1.55463 1.68206 1.19000 + 0.06526 3.12574 3.94910 2.41448 0.09367 1.10396 0.40280 + 48 2.23841 2.99164 0.25118 2.72900 792 g x - - + 1.26330 1.55339 1.52606 1.24355 + 0.05464 3.34968 4.01313 2.78872 0.06347 1.15133 0.38012 + 49 2.57533 0.32900 2.64632 2.01501 824 c x - - + 1.35118 1.39828 1.40141 1.39516 + 0.04340 3.79297 3.91506 1.59549 0.22666 1.20075 0.35806 + 50 0.46433 2.04127 2.23437 2.00605 833 a x - - + 1.23062 1.36903 1.62282 1.36182 + 0.05764 3.31530 3.92762 2.28791 0.10700 1.07910 0.41536 + 51 0.27513 2.77017 2.28518 2.57549 853 a x - - + 1.27958 1.58726 1.46109 1.25394 + 0.05750 3.30072 3.96214 2.60776 0.07656 1.25708 0.33475 + 52 0.20149 2.86434 2.84551 2.69770 883 a x - - + 1.23645 1.62259 1.71174 1.10368 + 0.05756 3.26729 4.02702 2.54508 0.08172 1.27391 0.32814 + 53 0.26982 2.65833 2.50477 2.46835 911 a x - - + 1.36005 1.50358 1.48100 1.22550 + 0.06921 3.37553 3.42118 2.36646 0.09851 1.27560 0.32748 + 54 0.40022 2.19284 2.22687 2.20396 934 a x - - + 1.12070 1.60472 1.53213 1.35895 + 0.05523 3.36752 3.94966 2.42917 0.09224 0.84774 0.55928 + 55 2.11356 0.46400 2.46442 1.79955 960 c x - - + 1.23932 1.35913 1.50478 1.46331 + 0.05187 3.47055 3.94022 2.35854 0.09933 1.12102 0.39445 + 56 1.85868 0.79440 2.22069 1.25971 983 c x - - + 1.21951 1.50212 1.51138 1.34185 + 0.06404 3.29054 3.69705 1.75742 0.18933 1.18410 0.36532 + 57 1.33272 2.32720 0.71452 1.90215 999 g x - - + 1.12229 1.49343 1.56653 1.42255 + 0.04920 3.46654 4.08749 2.17995 0.11996 1.31769 0.31164 + 58 2.48337 0.43652 2.46331 1.68683 1017 c x - - + 1.34704 1.55461 1.38112 1.28222 + 0.04823 3.61532 3.90311 2.20911 0.11631 1.00864 0.45368 + 59 0.41659 2.44509 1.93972 2.20507 1034 a x - - + 1.38198 1.38198 1.39194 1.38932 + 0.03641 3.98130 4.06929 1.35873 0.29704 1.31330 0.31325 + 60 0.41612 2.39160 1.97116 2.21075 1037 a x - - + 1.03649 1.46430 1.57421 1.57557 + 0.04769 3.52580 4.06641 2.32461 0.10294 0.84329 0.56263 + 61 2.66264 2.12302 2.82746 0.28581 1056 t x - - + 1.36925 1.39635 1.38930 1.39048 + 0.04097 3.97400 3.84718 1.39433 0.28502 1.12205 0.39395 + 62 2.26510 2.13196 2.42551 0.37231 1060 t x - - + 1.37965 1.39147 1.39147 1.38264 + 0.04082 3.91610 3.90805 1.24613 0.33914 0.95192 0.48776 + 63 0.41244 2.25761 2.16787 2.12907 1062 a x - - + 1.34515 1.41203 1.41203 1.37753 + 0.04054 3.77835 4.08203 1.30483 0.31638 1.11819 0.39582 + 64 2.51464 0.37905 2.62296 1.82008 1068 c x - - + 1.39543 1.38753 1.39233 1.37008 + 0.03854 3.90584 4.03535 1.36573 0.29463 1.13682 0.38689 + 65 2.16380 2.11332 2.18714 0.42765 1073 t x - - + 1.38764 1.38471 1.38519 1.38764 + 0.03575 4.05376 4.03073 1.40080 0.28289 1.03825 0.43707 + 66 2.79349 2.39141 2.87271 0.23478 1075 t x - - + 1.37227 1.39101 1.39101 1.39101 + 0.03597 4.01447 4.05827 1.39017 0.28639 1.06429 0.42308 + 67 2.82488 2.47749 2.93179 0.21887 1078 t x - - + 1.38141 1.39112 1.38915 1.38353 + 0.03661 3.99477 4.04370 1.35958 0.29675 1.13439 0.38804 + 68 2.77679 2.30433 2.90694 0.24425 1081 t x - - + 1.37593 1.38989 1.45520 1.32825 + 0.04447 3.68736 3.99242 1.76176 0.18843 0.98580 0.46703 + 69 2.47698 3.17398 0.19595 2.95437 1093 g x - - + 1.38264 1.38264 1.39734 1.38264 + 0.05358 3.96553 3.40487 1.40348 0.28202 1.03112 0.44100 + 70 2.84327 0.27906 2.97336 2.00890 1097 c x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03412 4.08811 4.08811 1.46634 0.26236 0.69006 0.69625 + 71 0.21870 2.83638 2.69251 2.65798 1098 a x - - + 1.37446 1.37942 1.39640 1.39509 + 0.03670 3.93983 4.09935 1.41905 0.27700 1.10002 0.40476 + 72 2.35233 0.46085 2.23804 1.78715 1103 c x - - + 1.38536 1.38781 1.38781 1.38421 + 0.03493 4.03822 4.09272 1.39310 0.28542 1.09638 0.40658 + 73 2.57111 0.32543 2.74124 1.98892 1105 c x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03381 4.09688 4.09688 1.46634 0.26236 1.09626 0.40664 + 74 0.27014 2.61416 2.53262 2.47636 1106 a x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03461 4.09267 4.05587 1.46634 0.26236 1.09748 0.40603 + 75 0.52873 2.16549 1.91736 1.90409 1107 a x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03426 4.08396 4.08396 1.46634 0.26236 1.07423 0.41788 + 76 2.33134 0.38082 2.65861 1.90055 1108 c x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03466 4.07266 4.07266 1.46634 0.26236 1.09861 0.40547 + 77 2.20588 0.45134 2.35553 1.84373 1109 c x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03550 4.04912 4.04912 1.46634 0.26236 1.09861 0.40547 + 78 2.69018 2.22054 2.82311 0.26898 1110 t x - - + 1.38629 1.38629 1.38629 1.38629 + 0.03711 4.00561 4.00561 1.46634 0.26236 1.09861 0.40547 + 79 0.16248 3.15867 2.86159 2.98963 1111 a x - - + 1.38629 1.38629 1.38629 1.38629 + 0.04048 3.92018 3.92018 1.46634 0.26236 1.09861 0.40547 + 80 0.17484 3.04770 2.86638 2.88183 1112 a x - - + 1.38629 1.38629 1.38629 1.38629 + 0.02045 3.90014 * 1.46634 0.26236 0.00000 * +// diff --git a/test/jalview/io/test_PKinase_hmm.txt b/test/jalview/io/test_PKinase_hmm.txt new file mode 100644 index 0000000..e1ad9f9 --- /dev/null +++ b/test/jalview/io/test_PKinase_hmm.txt @@ -0,0 +1,806 @@ +HMMER3/e [3.0 | March 2010] +NAME Pkinase +ACC PF00069.17 +DESC Protein kinase domain +LENG 260 +ALPH amino +RF no +CONS yes +CS yes +MAP yes +DATE Thu Jun 16 11:44:06 2011 +NSEQ 54 +EFFN 3.358521 +CKSUM 3106786190 +GA 70.30 70.30 +TC 70.30 70.30 +NC 70.20 70.20 +STATS LOCAL MSV -10.7215 0.70254 +STATS LOCAL VITERBI -11.6541 0.70254 +STATS LOCAL FORWARD -5.2305 0.70254 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 2.60017 4.19886 2.94089 2.63789 3.35087 2.89119 3.48337 2.79435 2.60265 2.43454 3.62613 3.06133 3.41286 3.09693 2.94507 2.65650 2.87761 2.67871 4.54052 3.43274 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.00000 * + 1 2.91704 4.31028 4.76351 3.63148 2.10912 3.47710 4.39734 2.27639 3.96619 1.99282 3.42844 4.19567 4.43771 4.11903 3.67403 3.22736 3.14918 2.35905 3.32515 1.82622 1 y - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 2 2.77204 4.20708 3.06476 1.97968 4.66603 3.66509 3.19858 3.37903 2.25347 3.34018 4.38833 2.97180 4.05804 2.36838 2.43173 2.67542 2.50268 2.83403 5.78758 4.38976 2 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 3 2.90076 4.04294 3.31590 2.80413 3.08157 3.87481 4.12616 2.18958 2.49735 1.97194 3.73714 3.32717 3.98753 3.23115 3.12315 2.99137 2.62008 2.29426 5.21478 3.75979 3 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 4 2.89383 4.85429 3.10311 2.63174 3.71383 2.56808 3.47232 2.82076 2.61844 1.98342 3.72320 3.05498 4.17347 3.05527 3.32194 2.85608 2.93671 2.18878 5.40057 3.87183 4 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 5 2.68261 5.39185 2.80437 1.87471 4.73638 2.79887 3.69591 4.22191 2.19487 3.69685 4.08896 3.12413 3.70490 2.48424 2.08916 2.53260 3.02309 3.43812 5.82480 4.41426 5 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 6 2.77253 4.06085 3.07881 2.53373 4.10647 3.71564 3.68370 2.64290 2.00036 2.72968 4.17370 3.24239 3.08607 2.77632 2.72820 2.69921 2.54335 2.71931 5.60386 4.26496 6 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 7 3.42930 4.74416 5.34765 4.76823 3.71832 4.71430 5.09461 1.33015 3.54417 1.12594 3.33523 4.84641 5.00427 4.73010 4.64986 4.05097 3.66327 1.83083 5.51142 4.37013 7 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 8 2.57460 4.94286 4.00732 3.93216 5.40516 0.41612 5.15134 4.86315 4.18766 4.52736 5.33508 4.05990 4.45245 3.74651 4.46171 3.15888 3.14590 4.15180 6.71159 5.52767 8 G - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 9 2.30218 5.38172 3.03799 2.02026 4.18991 3.65799 3.84554 3.67215 2.28945 3.68495 4.42365 2.84227 3.73039 2.44555 2.39428 2.00278 2.95859 3.63127 5.81726 4.40923 9 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 10 4.54226 6.07621 5.39207 5.44513 6.34643 0.07137 6.34600 6.33790 5.73770 5.76452 6.83374 5.56171 5.46536 5.98137 5.73783 4.76037 5.08470 5.67502 7.03864 6.52156 10 G - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 11 2.06444 5.37337 2.91595 2.40063 4.70969 2.61181 3.84889 4.18948 2.46835 3.67503 4.41668 2.62917 4.05392 2.88235 2.66711 2.00495 2.47288 3.39649 5.81159 4.40596 11 s - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 12 2.90920 4.46494 4.12493 3.14570 1.52027 3.22992 4.24969 2.92840 3.46467 2.66529 3.12827 3.55640 4.33979 3.72214 3.72236 2.53517 2.98442 2.55125 5.06498 2.30159 12 f - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 13 2.21104 4.80722 4.64199 4.55509 5.54982 0.52550 5.49025 5.04875 4.70671 4.72740 5.47955 4.30215 4.43233 4.84666 4.86038 1.95116 3.45005 4.17507 6.87595 5.79039 13 G - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 14 2.71551 3.46186 3.01248 2.27453 4.55840 3.55853 3.50842 3.55064 2.03335 3.34882 4.31847 3.17065 4.07218 2.83960 2.83653 2.25762 2.26864 2.61469 5.72841 4.35037 14 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 15 3.17885 3.97005 5.63014 5.16553 4.35293 4.89782 5.77682 2.09398 5.06494 2.94083 4.14496 5.20428 5.30924 5.30763 5.20260 4.32158 3.61414 0.44769 6.26043 5.04118 15 V - - E + 2.68625 4.42232 2.77526 2.73102 3.46361 2.40519 3.72501 3.29361 2.67747 2.69306 4.24696 2.90353 2.73746 3.18153 2.89807 2.37893 2.77526 2.98499 4.58484 3.61510 + 0.09563 2.43065 5.73865 0.67073 0.71608 0.48576 0.95510 + 16 2.91101 3.31342 4.36759 3.41772 2.45121 4.01227 4.31421 2.75922 2.81772 2.31733 3.50420 3.69862 4.38187 3.88257 3.14725 3.02772 3.14303 2.46483 3.37889 1.69905 18 y - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 17 2.88484 5.28431 3.03179 2.31849 4.58595 3.47769 3.54625 2.98124 1.69233 2.43413 4.04064 3.16353 4.06907 2.72555 2.58277 2.55274 3.04512 3.20501 5.74377 4.36100 19 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 18 1.57125 2.56460 3.38436 3.39201 3.66458 2.34190 4.20526 2.93932 3.32823 2.44127 3.26099 3.74334 4.30466 3.60817 3.63469 3.01628 2.92537 2.55308 5.13581 3.91882 20 a - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 19 2.89298 4.40558 3.44708 2.63051 3.77015 3.77747 2.87940 2.57515 2.33949 2.85128 3.20054 3.37379 4.16367 2.65910 2.52913 2.67954 2.59930 2.46709 5.42679 3.74337 21 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 20 2.88350 5.37811 2.42858 2.28192 4.71668 3.65945 2.35349 4.19788 2.20596 2.91798 4.42054 2.38258 4.05280 2.81490 2.60119 2.77457 3.11461 3.76528 3.43428 3.80493 22 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 21 2.59359 5.30144 3.00667 2.46268 4.60954 3.67285 3.22394 2.91749 2.13087 2.60378 4.35201 3.05590 3.51881 2.48537 2.35096 2.62551 3.00998 2.84793 5.75687 4.36947 23 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 22 2.64500 5.38003 2.46961 2.36386 4.71962 2.36153 3.71093 3.77963 2.19342 3.27291 4.42213 2.49968 3.44456 2.94396 2.94770 2.23767 2.90215 3.58800 5.81601 3.79868 24 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 23 2.71410 5.35453 2.26257 2.17828 4.68327 3.06138 3.85215 3.65600 2.51871 3.65284 4.39957 2.64619 4.05631 2.95399 2.98284 2.41102 1.94961 3.19379 5.79713 3.78693 25 t - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03260 5.01631 3.67114 0.61958 0.77255 0.48576 0.95510 + 24 2.77509 4.50579 3.06414 2.40741 4.68877 2.10468 3.84020 4.16638 2.52713 3.65577 4.39945 2.31826 2.82304 2.55347 2.45557 2.51717 3.10489 3.55245 5.79545 3.68618 26 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.13496 4.99383 2.12471 0.61958 0.77255 0.54753 0.86365 + 25 2.82390 4.23357 2.59579 2.09029 4.65095 3.47120 3.53571 3.50264 1.93281 3.24335 4.10745 2.98984 3.99409 2.41262 2.43858 2.60001 2.84781 3.57090 5.75206 3.98239 27 k - - E + 2.68634 4.42166 2.77510 2.73101 3.46370 2.40521 3.72473 3.29370 2.67713 2.69347 4.24706 2.90350 2.73742 3.18145 2.89817 2.37895 2.77536 2.98516 4.58493 3.61485 + 0.21086 2.33296 2.37401 1.37928 0.29003 0.81455 0.58490 + 26 2.79249 4.86773 3.27912 2.48247 3.81836 3.65430 3.86742 2.36980 2.31612 2.40000 3.66176 2.98804 3.52938 2.45192 2.80383 2.80149 2.71760 2.93241 5.39419 3.83742 36 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01259 4.77670 5.49905 0.61958 0.77255 0.27298 1.43175 + 27 2.94684 4.40681 4.93000 4.33270 2.14562 4.19543 4.43742 2.60780 4.12995 2.51432 3.32273 4.32339 4.55150 4.25562 4.15094 3.50804 3.26683 1.12964 4.39266 2.23526 37 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 28 0.67405 4.13502 4.78133 4.26234 4.00859 4.13420 4.88775 2.58668 4.14876 2.87877 3.59530 4.37511 4.66004 4.38446 4.34251 3.50924 3.44597 2.20111 5.62436 4.43519 38 A - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 29 2.77559 4.05359 4.82280 4.21814 3.45081 3.88127 4.46447 1.69887 3.29990 2.06046 2.92956 4.25618 4.49083 4.18293 4.07725 3.28739 3.19210 1.31639 4.98894 3.80930 39 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 30 4.13385 6.06880 4.58555 3.84767 5.73274 4.53840 4.41573 5.06650 0.32256 4.37802 5.30885 4.14872 4.92009 3.55775 2.54913 4.11741 4.25754 4.75872 6.25921 5.22828 40 K - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 31 2.53136 3.93442 3.55191 2.54113 3.59001 3.81267 3.67691 2.09853 2.22431 2.85063 3.63116 3.45300 4.19661 2.87681 2.71089 2.96116 2.67441 2.46338 5.34241 3.76111 41 i - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 32 2.80227 4.30542 4.81704 3.71619 2.31247 3.45194 4.41496 1.85614 4.00698 1.68898 3.06826 4.22398 4.44809 4.15126 4.03957 3.11345 3.01936 1.82478 4.92889 3.75130 42 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 33 2.72320 4.19698 2.89173 2.30854 4.21536 3.66470 3.63903 3.54937 1.81020 3.33297 4.38970 2.50126 3.12497 2.85129 2.61476 2.47307 2.93549 3.43057 4.63863 3.86554 43 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 34 2.73748 5.16363 3.24304 2.62749 4.42406 3.39882 3.64889 3.08793 1.75481 2.64054 4.22767 2.81684 3.49630 2.92572 2.69253 2.71691 2.78362 2.91622 5.65055 3.09244 44 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 35 2.82342 4.21564 2.57688 2.18304 4.09635 3.66104 3.29269 4.17416 2.24176 3.24419 4.40775 3.13331 3.02670 2.66210 2.30119 2.38622 2.91913 2.84969 5.80393 4.13733 45 e - - H + 2.68618 4.42225 2.77520 2.73124 3.46354 2.40513 3.72495 3.29354 2.67741 2.69355 4.24690 2.90347 2.73731 3.18147 2.89801 2.37887 2.77520 2.98519 4.58477 3.61503 + 0.02362 3.90596 5.73865 0.48782 0.95182 0.48576 0.95510 + 36 2.81479 5.38805 2.34307 2.08229 3.84722 3.00939 3.24618 4.21561 2.24819 3.24444 4.42924 2.80965 3.63231 2.74299 2.65208 2.41080 2.72103 3.26063 5.82196 4.16400 47 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 37 2.42659 5.32934 2.94543 1.98753 4.27035 3.66735 3.85733 2.97282 2.27697 3.20526 3.75542 2.69174 3.50027 2.79550 2.45131 2.66535 2.70832 3.28701 5.77800 4.07668 48 e - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 38 2.82479 5.36482 2.46403 2.36491 4.23121 3.19666 3.53460 3.47934 2.01766 2.87145 4.06028 2.53791 3.88358 2.73438 2.79605 2.39315 2.94316 3.30320 5.80464 3.67777 49 k - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 39 2.81259 3.82036 2.58997 2.16257 3.93187 3.50795 3.44913 3.32347 2.23760 3.42042 3.43188 3.03914 3.18139 2.98833 2.90722 1.97318 3.04237 3.44327 4.85883 4.01646 50 s - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04017 5.01631 3.41907 0.61958 0.77255 0.48576 0.95510 + 40 2.75150 4.68420 2.78864 2.20581 3.96394 3.14028 3.85474 3.62649 2.17804 2.84544 3.93254 2.66146 3.79370 2.72658 2.87564 2.43841 2.71937 3.23202 3.36778 4.34996 51 k - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01020 4.98634 5.70869 0.61958 0.77255 0.56699 0.83755 + 41 2.52028 4.29421 2.93844 2.26593 3.28616 3.42961 3.89113 3.40312 1.92589 2.89626 3.59280 3.04537 4.08209 2.42956 3.02333 2.89065 2.87512 2.78376 5.62895 3.97726 52 k - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.06456 4.98634 2.88790 0.61958 0.77255 0.56699 0.83755 + 42 2.52102 4.66200 2.60886 2.12080 3.90563 3.43164 3.41299 3.76759 2.19798 2.95231 4.37667 2.71584 3.31098 2.66775 2.46389 2.65499 2.89357 3.57073 4.74853 4.36793 53 e - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.06881 4.93254 2.82535 0.61958 0.77255 0.69302 0.69327 + 43 2.65676 5.27743 2.81592 2.16715 4.59834 3.44096 3.79920 2.82354 2.10889 3.57233 3.78816 2.93522 4.00237 2.20078 2.58862 2.72374 2.99283 3.18643 5.72482 3.30249 54 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04191 4.87514 3.39892 0.61958 0.77255 0.80592 0.59181 + 44 2.46416 5.14935 3.14274 2.35064 4.42785 3.46788 3.62138 3.06885 2.39724 2.90472 4.00413 2.77252 4.01153 2.56699 2.69346 2.37713 2.33258 3.34725 5.62407 3.30627 55 t - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.15381 4.84499 2.00472 0.61958 0.77255 0.85820 0.55151 + 45 2.15178 5.11690 2.80767 2.47016 4.06926 3.56450 3.25874 3.42510 2.38373 2.72748 4.17388 2.58132 3.95629 2.68997 2.59104 2.52019 2.89357 3.10461 5.58730 3.84420 56 a - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.06869 4.70471 2.85898 0.61958 0.77255 1.05523 0.42788 + 46 2.33893 4.38200 3.78128 3.08857 2.87706 3.76539 4.03303 2.50172 2.82237 2.26545 3.48958 3.56901 4.14175 3.13269 2.43377 3.02211 2.55318 2.18677 4.40164 3.75633 57 v - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.07407 4.65033 2.78326 0.61958 0.77255 1.03937 0.43646 + 47 2.66580 4.77769 3.25859 2.69691 3.69577 3.61140 3.56963 3.36841 2.45062 2.28390 3.86113 2.83101 3.99793 3.01640 2.00932 2.40384 2.97180 2.98514 3.81809 4.01106 58 r - - H + 2.68588 4.42292 2.77574 2.73101 3.46421 2.40561 3.72562 3.29362 2.67747 2.69305 4.24679 2.90348 2.73776 3.18179 2.89693 2.37874 2.77432 2.98554 4.58544 3.61510 + 0.56084 0.85690 5.33966 1.67148 0.20822 0.22069 1.61932 + 48 3.87852 6.35819 2.88185 0.33512 5.75300 3.98086 4.66680 5.41085 3.73193 4.87592 5.81368 3.19190 4.67406 3.86930 4.28895 3.74624 4.21685 4.94226 6.88673 5.40485 78 E - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 49 2.34469 4.06185 4.67394 3.74635 3.19070 3.72385 4.38165 1.69529 3.89930 1.68521 3.30505 3.88179 4.42519 3.50953 3.71087 3.12279 3.14596 1.99339 4.94125 3.41486 79 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 50 2.41611 3.92039 3.06862 2.24055 4.69692 3.38839 3.50460 4.17440 2.17094 3.43336 4.01855 2.84870 4.05421 2.22409 2.42800 2.49697 2.93959 3.48161 5.80403 3.10747 80 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 51 2.65097 4.31309 4.79937 4.19096 3.25102 4.08746 4.41763 1.57396 3.99634 1.77576 3.18772 3.58572 4.45127 4.14513 4.03729 2.91921 3.15786 1.73265 4.93848 3.33785 81 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 52 2.71474 4.35776 4.49839 3.90546 3.26558 3.60358 3.11363 2.58541 3.76519 1.24138 2.56017 3.78382 4.40165 3.77674 3.90460 2.91080 2.88501 2.43218 4.97232 3.44306 82 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 53 2.21717 5.37509 3.13954 2.36108 4.71254 3.44569 3.50643 4.19289 1.90576 2.89362 4.41783 2.84264 3.50886 2.51670 2.27883 2.73413 2.79427 3.37900 5.81221 4.40629 83 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 54 2.88332 4.76187 3.15794 2.34306 4.64959 3.18467 2.98724 4.11774 2.20976 2.84622 3.53657 2.69640 4.06011 2.81953 2.22587 2.26090 2.67755 3.39248 5.77872 3.89328 84 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 55 2.92075 3.71086 4.82119 4.21031 2.91851 4.08375 4.41406 2.48059 4.00923 1.14255 2.77088 4.22517 4.44739 4.15194 3.51737 2.79440 3.04088 2.14784 4.92583 3.58797 85 l - - H + 2.68619 4.42231 2.77526 2.73130 3.46360 2.40505 3.72501 3.29360 2.67737 2.69361 4.24696 2.90322 2.73746 3.18153 2.89797 2.37878 2.77526 2.98514 4.58483 3.61509 + 0.21093 1.81438 3.60337 0.15203 1.95873 0.48576 0.95510 + 56 2.87228 4.32697 2.43695 2.52023 4.72535 3.09966 3.42727 4.21076 2.24746 3.68599 4.14994 2.21640 3.70120 2.45856 2.42604 2.20075 2.84715 3.77128 5.81417 4.40372 87 s - - S + 2.68626 4.42233 2.77498 2.73131 3.46362 2.40515 3.72479 3.29362 2.67733 2.69363 4.24698 2.90355 2.73719 3.18141 2.89809 2.37895 2.77498 2.98527 4.58485 3.61511 + 0.08622 2.53438 5.71435 0.90816 0.51628 0.44628 1.02166 + 57 2.95437 4.05540 4.02453 3.66262 4.73022 3.00582 0.63840 4.27369 3.61156 3.92435 4.76053 3.90244 4.38221 3.97389 3.93213 2.36608 3.39859 3.79517 6.08861 4.80370 91 H - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 58 2.74925 4.59154 2.64384 2.02057 4.69046 3.19970 3.85151 4.16644 2.39568 3.65893 3.99620 3.06676 1.73396 2.95270 2.98758 2.52836 2.96698 3.57815 5.80119 4.39902 92 p - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 59 2.77600 3.63123 3.60742 3.04389 2.88763 3.83093 3.22852 3.27052 2.82124 2.96220 3.83761 1.44485 4.21384 3.33393 3.26463 3.06163 2.84916 2.86372 5.30436 2.85576 93 n - - S + 2.68619 4.42226 2.77521 2.73125 3.46355 2.40506 3.72496 3.29355 2.67742 2.69356 4.24691 2.90348 2.73741 3.18148 2.89802 2.37880 2.77521 2.98520 4.58478 3.61504 + 0.02736 3.73933 5.73865 0.64347 0.74542 0.48576 0.95510 + 60 3.43736 4.73250 5.40681 4.85032 3.21534 3.89737 5.21348 0.72821 4.70181 2.29095 3.77438 4.92025 5.08011 4.86610 4.77171 4.12622 3.68020 1.72131 5.65218 4.46593 96 i - - B + 2.68620 4.42119 2.77522 2.73126 3.46356 2.40515 3.72497 3.29356 2.67743 2.69357 4.24692 2.90349 2.73742 3.18149 2.89780 2.37889 2.77522 2.98521 4.58479 3.61505 + 0.04171 3.27988 5.73865 0.65380 0.73410 0.48576 0.95510 + 61 3.22247 3.52386 5.20134 4.62057 3.74032 4.49428 4.89197 1.38422 4.44333 2.03444 3.40884 4.64781 4.83078 4.60265 4.48778 3.55308 3.01459 1.16992 5.37248 4.18666 99 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 62 2.72238 4.59459 3.13585 2.30027 4.72566 3.17722 3.67251 4.20868 2.00822 3.53187 4.42604 2.97500 3.44674 2.41134 2.06447 2.53711 2.32763 3.77297 5.81907 4.41084 100 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 63 2.75790 4.02501 4.89076 4.27684 2.25991 4.10991 4.44304 2.31340 4.06541 1.38378 2.56521 4.26823 4.47075 4.19670 4.07763 3.42134 2.72551 2.21249 4.93572 3.01728 101 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 64 2.79378 4.36122 4.48297 3.70404 2.84684 4.03133 3.55103 1.94759 2.82835 1.82248 3.32801 4.05424 4.39941 3.70850 3.13439 3.15759 3.14407 2.41334 4.25902 2.30786 102 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 65 2.47264 4.33075 2.07830 2.03157 4.71750 2.27093 3.18950 4.19892 2.58523 3.68152 4.42156 3.04070 4.05295 2.84140 2.67254 2.59104 3.11515 3.76615 5.81569 3.60292 103 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 66 2.10377 4.03530 4.82986 4.21790 2.76136 4.07923 4.41023 2.08081 4.01359 2.30827 2.78821 4.22543 4.44340 4.15406 4.03913 2.38166 2.60707 1.97272 3.19782 3.33258 104 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 67 2.82605 3.67894 3.38070 3.01266 1.82001 3.97118 3.82789 2.76491 3.48734 2.34143 3.24926 3.10725 3.78017 3.42990 3.73647 2.98277 3.13977 2.32864 3.87637 2.72935 105 f - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04987 5.01631 3.16967 0.61958 0.77255 0.48576 0.95510 + 68 2.55964 4.21441 3.10666 1.94329 4.49707 3.21758 3.46239 3.37098 2.39709 3.00488 3.51821 3.06808 4.06187 2.54621 2.66989 2.75991 2.68522 3.13970 5.68635 3.14043 106 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02094 4.97674 4.28127 0.61958 0.77255 0.42506 1.06054 + 69 2.80310 5.38415 2.22807 2.18295 4.72718 3.65266 3.36574 4.21171 2.46641 3.56699 4.42536 2.57848 3.46451 2.86899 2.36310 2.58224 2.17995 3.52075 5.81804 3.65548 107 t - - E + 2.68640 4.42162 2.77535 2.73147 3.46354 2.40551 3.72458 3.29233 2.67716 2.69348 4.24762 2.90375 2.73699 3.18187 2.89837 2.37858 2.77480 2.98522 4.58549 3.61548 + 0.36809 1.18844 5.72853 1.68950 0.20409 0.46837 0.98355 + 70 2.88244 5.39287 2.47300 2.29715 3.79460 2.82884 3.28660 4.22374 2.09832 3.69810 4.43357 2.45444 3.07035 2.85151 2.47539 2.34133 3.01376 3.78345 5.82560 4.10620 126 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 71 2.57798 5.39101 2.06614 2.42374 4.73510 2.82383 3.84381 4.22040 2.28304 3.69587 4.43195 2.62257 3.38372 2.71683 2.73886 2.29050 2.66881 3.34289 5.82427 4.18691 127 d - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 72 2.58231 5.35788 2.77781 2.22432 4.08337 3.66211 2.49021 4.16401 2.37240 3.16748 4.40241 2.52484 4.05523 2.76334 2.63486 2.49164 2.89823 3.30761 4.95167 3.05734 128 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 73 2.78575 3.74303 4.78141 4.17260 2.95491 4.07322 4.40160 1.89067 3.97854 1.60353 2.95383 3.71592 3.11906 4.12798 3.50390 3.07790 2.85145 2.24111 4.92509 2.91282 129 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 74 2.58399 2.76389 4.59675 3.99881 3.19843 4.04871 3.62339 2.65148 3.84111 2.12752 3.45456 3.62454 3.46238 4.02369 3.94739 2.79096 3.14543 2.42948 3.13888 1.74690 130 y - - E + 2.68624 4.42096 2.77500 2.73129 3.46360 2.40508 3.72501 3.29360 2.67747 2.69353 4.24696 2.90343 2.73746 3.18153 2.89807 2.37893 2.77510 2.98525 4.58483 3.61509 + 0.10354 2.49668 4.13492 0.66960 0.71726 0.48576 0.95510 + 75 3.07392 4.44555 4.97084 3.81418 2.87255 4.25097 4.57886 1.74564 4.16653 1.31678 2.12605 4.39109 4.59167 3.71495 4.19337 3.56380 3.30386 2.29390 5.05348 3.89648 133 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.52175 0.90012 + 76 2.86449 3.41378 5.01300 4.41506 3.07458 4.28568 4.64425 1.49634 4.22335 2.27773 3.54368 4.43380 4.63588 3.70581 4.25773 3.60458 3.30826 1.19505 5.13861 3.95920 134 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.46390 0.99109 + 77 2.91733 4.35063 4.55668 3.96112 2.40516 4.04680 4.36140 2.56068 3.81048 1.70108 1.79340 3.59899 4.41359 3.09405 3.93172 3.15547 2.48177 2.59902 4.96582 3.78095 135 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 78 2.76564 5.57030 2.50020 1.03018 4.90220 3.70297 3.44513 4.39514 2.75995 3.87044 4.62325 3.16505 3.19754 2.75935 3.27129 2.65802 3.28146 3.95557 6.00401 4.57374 136 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 79 2.81579 3.90369 4.68991 4.08721 2.27644 4.06399 3.63829 2.69790 3.58050 1.84024 3.31248 4.16081 4.42953 4.07816 3.60709 3.36667 3.01039 2.57256 4.40465 1.54393 137 y - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 80 2.45920 2.17262 4.69646 4.09287 3.22405 3.32199 3.21264 2.59887 3.91610 2.06244 2.25581 4.16309 3.61702 4.08102 3.98811 3.14866 3.14614 2.03766 4.93767 3.46778 138 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04171 5.01631 3.37486 0.61958 0.77255 0.48576 0.95510 + 81 2.70314 5.37371 2.37994 1.91497 4.71601 2.93053 3.83161 4.20005 2.46492 3.55263 3.57885 2.58870 2.59223 2.74552 2.71928 2.69862 3.03649 3.29150 5.80804 4.39872 139 e - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01022 4.98481 5.70716 0.61958 0.77255 0.57090 0.83245 + 82 2.41993 3.72287 3.12898 2.52046 4.44831 1.89639 3.49536 3.62837 2.38762 3.31281 3.53904 2.44913 3.42379 3.00780 3.12891 2.87912 2.75467 3.52812 5.65946 3.81984 140 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.10979 4.98481 2.33166 0.61958 0.77255 0.57090 0.83245 + 83 2.77350 5.21303 2.43943 2.62703 4.54309 1.39496 3.89257 3.99092 2.60267 3.54085 4.32260 3.04209 4.06226 3.01831 3.03242 2.64588 2.77651 3.04353 5.73236 4.35922 141 g - - - + 2.68631 4.42210 2.77537 2.73126 3.46359 2.40522 3.72475 3.29338 2.67758 2.69250 4.24657 2.90377 2.73770 3.18148 2.89796 2.37902 2.77541 2.98478 4.58507 3.61496 + 0.21230 1.67338 5.60865 1.39945 0.28334 0.33567 1.25476 + 84 2.88583 5.39491 1.79381 2.06461 4.73890 3.24821 3.51210 4.22442 2.47141 3.51906 4.43601 2.95989 3.57031 2.79057 2.82788 2.02605 2.91163 3.62254 5.82805 4.41723 147 d - - B + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 85 2.90986 4.42406 3.70533 3.66371 3.02577 3.99009 3.90749 2.78363 3.56278 1.02082 3.24022 3.34355 4.36146 3.52102 3.78389 3.13807 2.95820 2.60948 5.03043 3.48016 148 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 86 2.57337 4.10245 3.03950 2.95233 2.09915 3.53742 3.15959 3.37138 2.66519 2.44003 3.54971 3.10382 3.71714 3.06888 3.13958 2.44794 3.05039 3.11306 4.61969 3.07664 149 f - - H + 2.68621 4.42228 2.77522 2.73126 3.46357 2.40516 3.72497 3.29357 2.67744 2.69358 4.24693 2.90350 2.73735 3.18149 2.89804 2.37890 2.77502 2.98521 4.58480 3.61458 + 0.24291 3.02648 1.78874 0.58545 0.81386 0.48576 0.95510 + 87 2.29362 5.30873 1.92419 2.32474 4.26868 3.43187 3.46788 4.12970 2.37357 3.61146 4.35100 2.92576 3.98105 2.69850 2.60197 2.47206 2.54407 3.69618 5.74493 3.96335 152 d - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01185 4.83724 5.55959 0.61958 0.77255 0.87096 0.54223 + 88 2.24696 4.24235 4.56569 3.96478 2.41045 3.97137 3.29432 2.27668 3.43922 2.04964 3.19406 4.05576 4.33743 3.97000 3.38896 3.27217 3.06100 2.23241 4.18296 2.20711 153 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01185 4.83724 5.55959 0.61958 0.77255 0.87096 0.54223 + 89 3.80243 5.01974 5.81731 5.27268 3.70245 5.26548 5.70409 1.30084 5.15744 0.98923 3.04180 5.42350 5.39649 5.16571 5.17462 4.65797 4.03105 1.75151 5.84473 4.80632 154 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01185 4.83724 5.55959 0.61958 0.77255 0.62617 0.76494 + 90 2.48275 5.13868 3.18520 2.44727 3.97540 3.65122 3.65677 3.36126 2.16734 3.30486 3.19390 3.06911 4.04233 2.41632 2.75033 2.25069 2.41675 3.09873 5.62108 3.69504 155 k - - H + 2.68595 4.42186 2.77509 2.73103 3.46377 2.40517 3.72421 3.29387 2.67761 2.69368 4.24695 2.90368 2.73754 3.18175 2.89730 2.37895 2.77536 2.98514 4.58473 3.61505 + 0.63487 1.25520 1.68753 1.39580 0.28453 0.74756 0.64154 + 91 2.43987 5.24839 2.75312 2.20207 4.11839 3.54175 3.72993 4.06095 2.07671 3.34429 3.98666 2.75679 3.72576 2.60349 2.28520 2.46158 2.79062 3.43756 5.68761 3.81452 172 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01352 4.70589 5.42824 0.61958 0.77255 0.34096 1.24163 + 92 2.56414 5.37054 2.84426 2.11401 4.71382 2.70860 2.88683 4.19851 2.19051 3.14492 4.41168 2.55924 4.03189 2.79129 2.63798 2.35762 3.09530 3.76022 5.80426 3.44686 173 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01035 4.97167 5.69402 0.61958 0.77255 0.60365 0.79145 + 93 2.86527 4.78061 2.95620 2.59670 4.27271 1.99448 3.84571 3.48713 2.08881 3.39073 4.33266 2.46895 3.64059 2.84730 2.63768 2.84659 2.50396 3.24160 5.73764 4.35043 174 g - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01035 4.97167 5.69402 0.61958 0.77255 0.46145 0.99524 + 94 2.57883 3.45102 3.31966 2.70191 4.02973 3.16828 3.76144 3.12068 2.26544 3.06289 4.10647 2.81108 2.70638 2.99156 2.57108 2.49596 2.68439 2.78596 4.48656 4.03099 175 k - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01001 5.00539 5.72774 0.61958 0.77255 0.51640 0.90799 + 95 3.00846 4.37852 4.95050 4.33851 2.03946 4.18408 4.51243 2.07907 4.13124 1.32746 2.71567 3.86888 4.53472 4.25457 4.14405 3.49709 3.23945 2.15194 4.98866 3.35208 176 l - - T + 2.68632 4.42239 2.77534 2.73137 3.46298 2.40515 3.72509 3.29351 2.67755 2.69332 4.24641 2.90361 2.73734 3.18136 2.89815 2.37881 2.77519 2.98532 4.58491 3.61446 + 0.13280 2.11108 5.72774 1.00017 0.45858 0.46707 0.98573 + 96 2.55096 5.39506 2.51329 2.14467 4.73966 3.20813 3.84532 4.22553 2.37049 3.70015 4.43599 2.79265 3.16832 2.74582 2.82569 1.88822 2.42672 3.78548 5.82793 4.41687 180 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 97 2.55253 5.00371 2.91674 1.56530 3.77486 3.74196 3.71669 3.18678 2.77868 2.90828 3.00031 3.29724 3.28640 3.12328 3.07027 2.76413 2.89289 3.32236 3.74938 3.48354 181 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 98 2.59075 4.32000 2.44335 2.15201 3.95693 3.12347 3.34011 3.83572 2.30797 3.16698 3.93315 2.75363 3.60071 2.81660 2.61665 2.70578 2.85000 3.34465 3.67935 4.00275 182 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 99 2.65092 5.35978 2.44414 1.82235 4.69093 3.44711 3.03513 3.63938 2.46445 2.69072 4.40412 3.13476 3.87902 2.43027 2.99516 2.67955 2.75495 3.20344 5.80088 4.03299 183 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 100 1.86496 3.02665 4.71869 4.11439 3.41506 3.78632 4.39467 1.72869 3.93413 2.03606 3.25110 4.17623 4.43415 4.09606 3.42450 3.02051 2.94480 2.04904 4.94015 3.76003 184 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 101 2.66380 3.60669 3.09016 2.70629 3.97052 3.12773 3.91117 3.25572 1.80561 2.74214 4.19581 3.23071 4.10037 2.51557 2.19861 2.73033 3.11863 2.97558 5.62300 4.27841 185 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 102 2.65525 3.61780 2.73206 2.59880 2.91626 3.69337 3.17740 3.91061 2.06495 2.87551 3.62080 2.65252 4.08468 3.01717 2.55140 2.50072 2.84956 3.37543 5.67937 3.86408 186 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 103 2.78549 3.75825 4.89230 4.27707 2.37628 4.09576 4.42870 1.58181 4.06146 2.16353 2.83229 4.25917 4.45832 4.19107 4.06819 3.40747 3.15724 2.08428 3.94244 2.32199 187 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 104 1.91854 4.04767 4.83572 4.22341 2.21465 3.82491 4.41156 2.18264 4.01792 2.17430 2.43077 4.22827 4.44431 4.15736 4.04152 2.82624 2.88622 2.07903 4.25105 3.74133 188 a - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 105 2.59846 4.94560 3.39451 2.56515 3.67443 3.44440 3.79808 3.54150 2.22767 2.11264 4.02778 3.19297 4.14629 3.16161 2.51054 2.63727 2.68778 3.11215 4.13689 2.62651 189 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 106 2.71202 4.65478 2.93025 2.07602 4.70407 3.24619 3.70431 4.18261 2.58938 3.67040 4.10390 3.00747 4.05496 1.41184 3.00214 2.55548 2.74962 3.75459 5.80879 4.40428 190 q - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 107 3.40758 4.70636 5.39472 4.82751 3.82844 4.73217 5.15283 1.33187 4.66862 1.85779 2.55181 4.88258 5.03394 4.81634 4.72035 4.07618 2.46891 1.37416 5.58393 4.41648 191 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 108 2.29107 3.23763 4.81578 4.20571 3.00975 3.26830 4.41487 2.37700 4.00619 1.39060 3.28560 4.22330 4.44775 4.15070 4.03923 2.94875 3.15303 1.86969 4.92930 3.75166 192 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 109 2.62933 4.07203 2.95927 2.08969 4.71415 3.53463 3.84677 3.97436 2.17805 2.82549 4.41873 2.79932 4.05232 2.53645 2.16719 2.25459 2.86145 3.76301 5.81311 4.40656 193 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 110 1.17650 4.82606 4.24050 3.83461 4.98724 1.08848 4.85992 4.42183 3.81285 4.07900 4.88120 3.97861 4.34888 4.10941 3.49121 2.50205 3.18154 3.58125 6.30917 5.10145 194 g - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 111 3.90271 5.14012 5.90469 5.33230 3.41122 5.28833 5.65529 2.02087 5.19062 0.88043 2.65524 5.45552 5.42442 5.15469 5.16815 4.66249 4.12260 1.40813 5.79888 4.77647 195 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 112 2.18892 5.38966 2.64044 1.97751 4.73333 3.65659 3.60437 3.92129 2.10090 3.35469 4.43069 2.33847 4.05005 2.60616 2.77179 2.58383 3.11351 3.51057 5.82316 3.92131 196 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 113 2.81051 5.07767 4.77644 4.29954 2.03535 4.57845 2.23184 3.59557 4.18346 3.18325 4.21755 4.37554 4.93163 4.33627 4.35340 3.88728 3.48134 3.41897 4.49144 0.85916 197 y - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 114 3.22459 2.61128 5.38969 4.79509 3.58979 4.68737 5.03975 1.79213 4.61293 0.89179 2.61919 4.84389 4.96801 4.69100 4.62327 4.02095 3.66625 2.57847 5.40913 4.29402 198 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 115 4.50357 5.94639 4.67261 4.49457 2.97674 4.90740 0.35314 4.75553 4.20979 3.98991 5.25041 4.60971 5.36272 4.62490 4.36557 4.47961 4.76464 4.60938 4.62703 2.51319 199 H - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 116 2.59851 4.33805 2.68311 2.05797 4.71676 3.15802 3.59362 3.65569 2.43439 3.32473 4.42034 2.78736 4.05190 2.70193 2.69422 1.73897 3.11362 3.60918 5.81450 4.40740 200 s - - H + 2.68619 4.42226 2.77521 2.73118 3.46355 2.40514 3.72496 3.29355 2.67742 2.69356 4.24691 2.90348 2.73741 3.18131 2.89802 2.37888 2.77521 2.98510 4.58478 3.61505 + 0.04979 3.09322 5.73865 0.35009 1.21950 0.48576 0.95510 + 117 2.54785 4.42029 2.89622 2.25922 4.34868 3.66610 3.21799 3.71995 2.27125 3.07920 3.10189 2.25867 4.05899 2.34775 2.56766 2.85682 3.11428 3.36249 5.78309 3.93739 202 n - - T + 2.68634 4.42198 2.77524 2.73138 3.46344 2.40486 3.72467 3.29300 2.67713 2.69352 4.24714 2.90371 2.73709 3.18145 2.89825 2.37911 2.77527 2.98532 4.58501 3.61528 + 0.09842 2.40225 5.73865 1.69597 0.20263 0.48576 0.95510 + 118 2.53322 5.34393 2.95935 2.59629 3.94657 1.84501 3.63806 4.14023 2.18335 3.64044 4.39013 2.55576 3.77395 2.95784 2.71428 2.21077 3.11477 3.72355 4.68564 4.39095 213 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 119 3.55513 4.24694 5.60079 5.05662 2.60993 4.96071 5.43324 0.97900 4.91818 2.09234 3.80321 5.12225 5.23216 5.06726 4.97588 4.32549 3.79818 1.34455 5.81250 4.64107 214 i - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 120 2.50668 3.55624 4.84676 4.23404 3.24346 4.08398 4.41611 1.66920 4.02684 2.01982 2.79518 4.23489 4.44784 4.16480 3.83668 2.91482 2.83994 1.71230 4.92013 3.32611 215 i - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 121 4.62495 5.94818 4.90176 4.71687 2.80207 5.05504 0.41821 4.71670 4.43975 3.92227 5.21366 4.70109 5.45885 4.74110 4.56151 4.57303 4.86606 4.59605 4.46431 2.05738 216 H - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 122 3.04282 4.16968 3.83274 3.22981 4.12386 3.92565 4.16387 3.45658 2.89535 2.79946 3.52962 3.63885 4.33284 3.40809 0.88367 3.03173 2.91452 3.20781 5.47983 4.24517 217 r - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 123 4.66549 6.56867 0.13049 3.73947 6.20930 4.51726 5.46620 6.15252 4.80154 5.54790 6.65359 4.31602 5.22661 4.77980 5.35908 4.57977 5.04873 5.69924 7.06132 6.05090 218 D - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 124 4.11594 5.30633 6.13178 5.57769 3.73657 5.59693 5.98457 1.50133 5.46568 0.67788 3.07617 5.76705 5.63423 5.36401 5.43088 5.00606 4.33175 2.14525 5.97972 5.01356 219 L - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 125 4.55719 6.24846 4.80697 4.34215 5.94023 4.73956 5.02576 5.52333 0.17090 4.86848 5.87217 4.66859 5.24422 4.23030 3.41495 4.59394 4.77093 5.20290 6.57866 5.65826 220 K - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 126 2.73388 4.87911 3.10327 2.90832 4.07991 3.41413 4.01646 3.20246 2.89177 2.38683 3.78561 3.39051 1.51394 3.22647 3.32105 2.31617 2.81372 3.19214 5.43675 4.15025 221 p - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 127 2.30763 5.39894 2.49711 1.50775 4.74209 3.53358 3.60730 4.22742 2.31483 3.70337 3.89187 2.94609 4.05547 2.65035 3.08133 2.29509 3.12215 3.78862 5.83238 4.42137 222 e - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 128 4.24075 6.04161 4.10323 4.13804 5.66046 4.44992 5.52992 5.77835 4.64675 5.26705 6.30900 0.15130 5.17553 4.91694 4.94682 4.32646 4.70552 5.25421 6.75952 5.61338 223 N - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 129 3.55135 3.88080 5.58388 5.03211 3.05772 4.93598 5.38843 0.81084 4.88763 1.84199 3.74557 5.09695 5.20522 5.02095 4.93631 4.29650 3.79207 1.75582 5.75938 4.60163 224 i - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 130 4.26500 5.46000 6.21355 5.61602 2.31085 5.64571 5.88455 2.68862 5.47780 0.52109 2.36789 5.81754 5.61663 5.25881 5.37169 5.03996 4.45544 2.72136 5.81387 4.88779 225 L - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 131 3.14725 3.80930 5.11896 4.51210 2.75868 4.35237 4.69393 1.48763 4.30885 1.32733 3.15909 4.51494 4.68518 4.42027 4.31553 3.67228 3.37834 1.91515 5.14039 3.60311 226 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 132 2.83132 4.28838 2.02200 2.41335 4.70055 3.12743 3.31546 4.17875 2.06503 3.46693 4.09733 2.49326 4.05387 2.94892 3.07895 2.27711 2.89161 2.90947 5.80603 4.40188 227 d - - E + 2.68620 4.42227 2.77521 2.73125 3.46356 2.40515 3.72496 3.29356 2.67743 2.69346 4.24692 2.90348 2.73741 3.18137 2.89794 2.37889 2.77521 2.98513 4.58479 3.61505 + 0.19179 2.92011 2.11536 0.31959 1.29625 0.48576 0.95510 + 133 2.77846 5.34345 2.73873 2.12504 4.68884 3.31622 3.10327 4.17503 2.07146 3.64885 4.14408 2.35495 3.55373 2.53396 2.68259 2.30312 2.80970 3.73426 5.77591 4.07717 229 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01122 4.89146 5.61380 0.61958 0.77255 0.46383 0.99121 + 134 2.76231 5.37627 2.40965 2.30431 4.72103 3.48860 3.46007 4.20680 2.15285 3.68141 4.41704 2.22463 3.54282 2.67483 2.66394 2.48608 2.48229 3.08661 5.80911 4.39830 230 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01030 4.97674 5.69908 0.61958 0.77255 0.42506 1.06054 + 135 2.88621 4.31580 2.58861 2.52891 4.00821 1.80604 3.64216 3.70404 2.55848 3.01103 3.82083 2.93142 3.28125 2.96153 3.15140 2.63196 2.92652 3.07947 5.65563 3.39061 231 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 136 2.74326 5.32913 2.62872 2.23118 4.20190 3.27586 3.01088 3.39612 2.54602 3.28443 3.99578 2.66732 4.06020 2.45230 2.82728 2.54748 2.65672 2.69485 5.77785 3.49295 232 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 137 2.61635 3.28525 4.16732 3.71739 2.98202 4.03403 4.34546 2.03775 3.50788 1.92540 3.47356 3.38535 3.11745 3.96570 3.52677 3.32696 2.46663 1.86856 4.97202 3.78516 233 v - - E + 2.68644 4.42087 2.77438 2.73125 3.46306 2.40580 3.72561 3.29182 2.67742 2.69394 4.24637 2.90298 2.73752 3.18209 2.89809 2.37898 2.77573 2.98487 4.58490 3.61464 + 0.36530 1.19470 5.73865 2.01193 0.14356 0.48576 0.95510 + 138 2.92386 3.12674 3.30583 2.50241 4.41812 3.73989 3.57074 3.83865 1.16713 3.42239 3.64701 3.25964 4.12762 3.06518 2.74407 2.94589 3.15200 3.22587 5.64420 3.71460 253 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 139 3.61791 5.07369 5.93139 5.42030 4.01697 5.40165 5.95563 1.06228 5.32659 1.08905 3.76387 5.56598 5.56723 5.42106 5.39317 4.81179 4.11011 1.74432 6.14737 5.05160 254 i - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 140 1.74479 2.79152 4.35686 3.77898 3.55350 2.78668 4.34505 2.08763 3.66685 2.55990 3.56128 3.98833 4.38080 3.89329 3.86150 2.46831 2.34811 2.41028 5.05799 3.86488 255 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 141 4.66549 6.56867 0.13049 3.73947 6.20930 4.51726 5.46620 6.15252 4.80154 5.54790 6.65359 4.31602 5.22661 4.77980 5.35908 4.57977 5.04873 5.69924 7.06132 6.05090 256 D - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 142 4.66482 5.73614 5.86239 5.64956 0.40883 5.43325 4.33355 3.86711 5.42110 2.16428 4.36705 5.11239 5.65371 5.16689 5.27011 4.83252 4.86624 3.98432 3.74189 2.69037 257 F - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 143 3.93699 5.85566 3.02816 3.87037 6.00993 0.21285 5.44927 5.75466 4.70121 5.27717 6.21696 4.31536 4.99427 4.76567 5.12629 4.02226 4.42780 5.10478 6.99282 5.96830 258 G - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 144 2.54355 3.67295 4.73868 4.13265 2.71576 4.06852 3.76754 2.37455 3.94756 1.20416 3.31174 3.74431 4.43365 4.10500 4.00521 2.64259 3.14725 2.29206 4.93223 3.75278 259 l - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03189 5.01631 3.69859 0.61958 0.77255 0.48576 0.95510 + 145 0.77520 2.86695 4.81978 4.47036 4.95592 3.15951 5.20700 4.36343 4.38394 4.08078 4.90451 4.25075 4.38058 4.58838 4.56864 1.45304 3.34905 3.34992 6.35477 5.22001 260 a - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.07711 4.99453 2.69658 0.61958 0.77255 0.54567 0.86620 + 146 2.54977 3.79925 3.16699 2.32606 4.48674 3.31547 3.84408 3.47518 1.75582 3.12339 4.25869 2.84258 4.04145 2.96441 2.18943 2.71334 2.91887 2.95414 5.67187 4.30075 261 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.13472 4.92824 2.13029 0.61958 0.77255 0.70219 0.68419 + 147 2.64685 3.78445 3.06669 2.61534 3.32325 3.67596 3.69246 3.14713 2.01231 2.43193 3.43451 3.16113 4.06301 2.47274 3.08778 2.74475 2.84906 2.65428 5.37440 4.07606 262 k - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.29473 4.80574 1.39802 0.61958 0.77255 0.92027 0.50818 + 148 2.40579 4.15423 4.25399 3.66267 2.39272 3.57693 3.44550 2.33935 3.03827 1.86796 2.97007 3.83355 4.18573 3.73297 3.67827 3.10851 2.93289 2.21754 4.76738 2.96352 263 l - - . + 2.68635 4.42219 2.77489 2.73146 3.46367 2.40530 3.72500 3.29419 2.67720 2.69370 4.24630 2.90362 2.73727 3.18122 2.89818 2.37860 2.77478 2.98583 4.58472 3.61420 + 0.77167 0.63015 5.24955 1.50734 0.25038 0.20147 1.70117 + 149 2.68930 5.13793 2.99383 2.28756 4.12167 3.02811 3.40047 2.83046 2.53990 2.67433 3.91490 2.66806 3.85841 2.95123 3.08518 2.54554 2.43488 3.14237 4.83794 3.11842 281 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 150 2.67960 3.59834 3.08049 2.32634 4.00400 2.85568 3.65072 3.26198 2.22635 2.80014 3.89773 3.03566 3.90780 2.84131 2.77630 2.59674 2.54121 2.94346 4.66327 3.60288 282 k - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 151 2.78407 5.36932 2.80723 2.38070 3.95652 3.28210 3.31902 3.80407 2.38757 3.23090 4.41260 2.26860 2.87333 2.94776 2.55475 2.11230 2.82314 3.31603 5.80800 4.40313 283 s - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 152 2.55066 5.37311 2.42428 2.58328 4.70981 2.65546 3.66067 3.46611 2.34139 3.39818 4.41598 2.44705 3.58966 2.48003 2.87086 2.30355 2.92043 3.58081 5.81084 3.32103 284 s - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 153 2.61131 5.36709 3.05324 2.00706 4.70125 2.53001 3.45141 4.17959 2.46541 3.54879 4.41063 3.13225 3.27183 2.67970 2.77280 2.14590 2.62504 2.97295 5.80635 3.79465 285 e - - S + 2.68619 4.42226 2.77520 2.73124 3.46320 2.40514 3.72495 3.29355 2.67742 2.69356 4.24691 2.90348 2.73740 3.18147 2.89802 2.37888 2.77520 2.98519 4.58478 3.61504 + 0.03620 3.43177 5.73865 0.40966 1.09027 0.48576 0.95510 + 154 2.80870 4.76397 2.82688 2.35901 3.53520 3.31737 3.24083 3.53679 2.31494 2.98485 3.52265 2.69923 3.15465 2.90046 2.56489 2.40361 2.83318 3.04461 5.74293 3.76697 287 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 155 2.38638 3.55872 3.84850 3.27925 3.07902 3.89951 3.49984 3.07191 2.87600 2.13071 2.79826 2.94436 3.28103 3.24012 3.30127 2.77627 2.52689 2.66914 5.17020 2.84075 288 l - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 156 2.88266 4.79637 2.63708 2.49106 4.69372 3.27452 3.02757 4.17056 2.31920 3.54781 3.84892 2.54158 3.83133 2.71114 2.83815 2.34796 2.07167 3.53868 4.84477 3.26548 289 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 157 2.55115 5.22307 2.81541 2.42597 3.84088 2.72211 3.45978 3.70939 2.65113 3.50012 4.03956 3.00145 3.26637 2.92366 3.12986 2.10982 2.09681 2.95270 4.42058 4.32902 290 t - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 158 2.79383 4.53543 3.94528 3.00256 2.28876 3.25886 4.19260 2.53698 3.31063 2.13485 3.51266 3.25465 3.61933 3.02975 2.60672 3.04108 3.13630 2.22820 5.12884 3.03437 291 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 159 2.54133 2.27249 3.62507 3.14565 3.48798 3.47382 4.20805 2.87324 3.24770 2.61629 3.62417 3.76153 4.31084 3.45605 3.15192 3.19594 2.77273 1.44309 5.11140 3.89714 292 v - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 160 2.50560 4.02210 4.21483 3.69251 4.03927 0.87585 4.50859 3.18042 3.62456 3.12203 4.01557 3.91946 4.34666 3.89680 3.91281 2.66630 3.23503 2.52015 5.49804 3.97346 293 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 161 2.98792 5.00679 3.18026 3.47531 5.09253 3.65988 4.75357 4.53531 3.72802 4.18133 4.99276 3.79669 4.37930 3.97717 4.12874 1.60941 0.74054 3.97784 6.39182 5.11951 294 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 162 2.69840 5.26022 3.00961 2.31122 4.20998 3.68086 3.63617 3.20701 2.41779 2.58849 4.31499 2.98486 2.62271 2.99075 2.13729 2.36313 3.11573 3.42385 5.72545 3.54571 295 r - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 163 2.71301 5.29924 2.59488 2.14743 3.52695 3.04037 3.28275 4.06670 2.61594 3.34508 4.35002 2.84026 3.31113 2.97459 2.36266 2.86533 2.70674 3.41928 3.03699 3.23042 296 e - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 164 4.65993 5.73598 5.69662 5.49898 1.97465 5.32012 3.31709 4.36240 5.29326 3.66395 4.92323 4.93743 5.59573 5.06816 5.17473 4.69695 3.41633 4.25844 2.61302 0.51590 297 Y - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 165 2.46851 3.63596 4.34730 3.76113 3.49978 4.00900 4.30977 2.55613 3.41377 2.11254 1.89168 3.40620 4.37893 3.86942 2.23584 3.08926 3.14320 2.13937 5.00600 3.81292 298 m - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 166 0.54633 4.79516 4.59072 4.34047 5.33605 3.22550 5.27451 4.80651 4.37656 4.47607 5.24769 4.21379 3.02084 4.58677 4.60871 1.81435 3.40538 4.05386 6.66459 5.53199 299 A - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 167 3.08666 5.02380 4.02349 3.92167 5.10908 3.73669 5.07487 4.62556 4.04836 4.33998 5.22795 3.34786 0.41351 4.38870 4.30726 3.26072 3.60085 3.40472 6.47905 5.20179 300 P - - H + 2.68622 4.42144 2.77523 2.73111 3.46358 2.40517 3.72498 3.29358 2.67745 2.69359 4.24694 2.90351 2.73743 3.18126 2.89786 2.37891 2.77523 2.98522 4.58481 3.61507 + 0.03484 3.47295 5.73865 0.99675 0.46057 0.48576 0.95510 + 168 3.66837 6.19086 2.84947 0.45189 5.55161 3.90523 4.43200 5.09782 3.30487 4.55035 5.42336 3.03786 4.53514 3.60153 3.37398 3.54999 3.95969 4.65772 6.64024 5.17650 305 E - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 169 2.79774 4.32598 4.68241 3.67608 3.42171 4.06471 4.38713 2.01470 3.90321 1.87174 3.44282 4.15860 4.43014 3.77035 3.25202 3.36713 2.95239 1.31877 3.77234 3.76466 306 v - - H + 2.68603 4.42242 2.77519 2.73104 3.46342 2.40506 3.72511 3.29371 2.67728 2.69322 4.24707 2.90364 2.73756 3.18163 2.89801 2.37893 2.77519 2.98535 4.58494 3.61520 + 0.12919 2.22240 4.35495 1.23224 0.34480 0.48576 0.95510 + 170 2.91184 3.76308 4.76588 4.15799 3.39752 4.06920 3.82796 1.60071 3.96642 1.39613 3.17824 3.65225 4.43387 4.11848 4.01348 2.94594 3.14403 2.21737 4.92444 3.43929 311 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00999 5.00664 5.72898 0.61958 0.77255 0.51297 0.91308 + 171 2.62785 5.06480 3.29796 2.67561 3.73804 3.41086 3.92577 3.21358 2.32640 2.15096 3.31180 2.55443 4.11004 2.47045 2.33927 2.70318 3.11578 3.12852 5.57146 4.24107 312 l - - C + 2.68631 4.42245 2.77511 2.73076 3.46350 2.40522 3.72547 3.29356 2.67765 2.69366 4.24573 2.90389 2.73738 3.18142 2.89826 2.37846 2.77520 2.98520 4.58530 3.61473 + 0.62427 1.87899 1.16602 1.98855 0.14722 0.46912 0.98231 + 172 2.60166 5.18307 2.62016 2.19793 3.35206 2.39740 3.57105 3.96340 2.18128 3.47543 4.23188 3.01161 3.92489 2.82990 2.86326 2.33987 2.67701 3.55746 5.63416 3.78538 327 k - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01428 4.65191 5.37425 0.61958 0.77255 0.24611 1.52250 + 173 2.37600 3.94341 2.81761 2.45806 4.08381 2.38833 3.32666 4.15213 2.47322 3.64753 4.39446 2.71786 3.74359 2.39493 2.76163 2.38666 3.00597 3.01776 5.79219 3.82026 328 a - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00998 5.00778 5.73012 0.61958 0.77255 0.47101 0.97916 + 174 2.81816 4.87774 2.88922 2.34131 3.91699 3.47934 3.84840 3.76601 2.22767 3.10881 4.41163 2.46519 2.75598 2.51039 2.43545 2.43680 2.76354 3.54179 5.80719 3.84984 329 k - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 175 2.74169 5.33416 2.58184 2.32653 3.61666 2.33545 3.50275 4.12419 2.36762 3.50261 3.56274 2.91332 3.07814 2.74477 2.96926 2.79421 2.92848 3.32496 5.78164 2.72284 330 e - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 176 2.48397 4.72191 2.72922 2.94719 3.45604 3.83733 2.73484 2.72590 3.03376 2.94128 3.81928 3.51045 4.21965 3.13222 3.31573 2.84267 3.12967 2.71705 3.94971 1.76193 331 y - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 177 2.88858 5.15756 2.48812 2.69267 3.68939 2.20273 3.90720 3.84889 2.69072 3.17648 4.22648 3.21985 3.19313 3.04303 3.16266 2.07644 2.02474 3.50391 5.64990 3.69862 332 t - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 178 2.44412 5.27089 3.18567 2.52594 4.01181 3.49400 3.20300 3.68711 2.26882 2.99802 4.32458 3.16791 2.73532 2.67304 2.47574 2.35896 2.41445 3.31659 5.73361 3.79657 333 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 179 2.27957 5.36842 3.14470 2.24142 4.70283 3.35867 3.70433 4.18054 1.84880 3.00297 4.41216 3.13478 2.50109 2.87247 2.49374 2.50485 2.88881 3.75338 5.80713 4.40386 334 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 180 2.25487 3.19836 3.67383 3.53894 3.58335 3.60706 4.24810 2.30247 3.45618 2.57768 3.58074 3.40343 4.33674 3.48890 3.71724 2.25302 2.94661 1.56396 5.07167 3.86608 335 v - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 181 3.32488 6.23611 0.30142 2.99559 5.85936 3.97225 4.81661 5.46625 4.07634 5.00781 5.98660 3.57219 4.70996 4.04099 4.76451 3.76774 4.26196 4.95940 7.04785 5.56474 336 D - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 182 2.97530 4.34655 4.92112 4.31006 3.42469 4.15298 4.48903 1.67409 4.10270 2.14170 2.44181 4.30839 4.51041 4.23558 4.11915 3.46567 2.80277 1.45020 3.28394 3.56694 337 v - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 183 4.60767 5.71652 5.61554 3.89031 2.18526 5.28181 4.15190 4.32304 5.18037 3.62888 4.88484 4.90634 5.56392 5.01906 5.10312 4.65700 4.81381 4.22147 0.60655 1.74323 338 W - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 184 1.30551 4.78823 4.65738 4.37945 5.36630 2.58206 5.28849 4.84019 4.38318 4.50739 5.27020 4.22569 4.39579 4.59600 4.61395 0.79404 2.89139 4.06528 6.68751 5.56026 339 s - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 185 2.44153 3.17932 4.87400 4.25972 2.53121 4.09082 4.42403 2.33144 4.04748 1.34403 2.92510 4.24940 4.45392 4.18053 4.05982 3.14600 3.15398 2.13810 4.92017 3.14864 340 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 186 2.22507 4.96728 4.63623 4.63233 5.66307 0.33314 5.62287 5.16416 4.86793 4.86816 5.66661 4.43512 4.57282 5.01497 4.99264 3.26151 3.63533 4.32703 6.92990 5.89905 341 G - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 187 2.93009 2.13614 4.95885 4.35253 3.48038 4.19799 4.54424 1.68794 4.14925 1.93394 3.18432 4.35359 4.55452 4.28834 4.17024 3.34008 3.23972 1.60527 5.03746 3.47367 342 v - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 188 3.21831 4.55127 5.17022 4.58630 3.70338 4.47717 4.86313 1.30610 4.40976 1.92114 2.79907 4.62299 4.81179 4.56490 4.45688 3.52794 2.67243 1.42404 5.34369 4.16408 343 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 189 2.77853 3.56970 4.91220 4.29933 2.66878 4.13468 4.46922 2.12981 4.08926 1.13811 3.14072 4.29275 4.49323 4.21981 4.10205 3.44689 2.88537 2.20246 4.95897 3.46211 344 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 190 2.08301 4.31008 4.80905 4.20025 2.66597 4.08391 3.54227 2.07553 4.00182 2.35024 3.19529 4.21899 4.44796 4.14611 4.03654 3.39206 3.15615 2.32332 2.91148 1.86433 345 y - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 191 2.65126 3.79080 3.03118 1.37895 4.54227 3.68257 3.87660 3.27048 2.56225 3.53374 4.30787 2.88399 4.07460 2.72714 3.11894 2.49943 2.86114 3.20681 5.71940 3.61825 346 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 192 2.75949 4.33120 4.86063 4.24972 2.93412 4.11800 4.44873 2.58063 4.04775 1.34098 1.86205 4.26240 4.47769 4.18564 4.07448 3.30982 2.87183 2.17494 4.95131 3.25026 347 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 193 2.13730 3.34433 4.84746 4.23449 2.67079 4.08305 4.41495 2.45417 4.02682 1.45586 2.95446 4.23448 4.44687 4.16424 3.65241 3.39295 2.78239 2.10310 4.91833 3.10946 348 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 194 2.61714 3.04119 3.51958 2.50105 3.16562 3.44068 4.02999 3.26384 2.78703 2.46125 3.90521 2.94061 4.18669 3.26384 2.94427 2.45451 1.92365 2.96026 5.36672 3.77569 349 t - - H + 2.68592 4.42131 2.77530 2.73134 3.46364 2.40523 3.72505 3.29364 2.67751 2.69365 4.24624 2.90357 2.73750 3.18157 2.89769 2.37886 2.77510 2.98507 4.58487 3.61513 + 0.08274 2.77459 4.07273 1.24373 0.34011 0.48576 0.95510 + 195 2.74009 5.38236 2.60734 2.58658 4.30151 1.49346 3.57775 4.19577 2.06867 3.68256 4.42710 2.84258 4.06100 2.86136 2.79826 2.78642 3.12785 3.76776 5.82019 4.41533 355 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02515 5.00240 4.01100 0.61958 0.77255 0.52459 0.89600 + 196 2.87057 4.15783 2.81932 2.15097 3.67482 3.00161 3.44561 3.53712 2.01194 3.52030 4.39830 2.84675 4.04172 2.62971 2.18111 2.65254 2.90372 3.46034 5.79407 3.92999 356 k - - S + 2.68632 4.42239 2.77496 2.73101 3.46368 2.40527 3.72508 3.29339 2.67739 2.69369 4.24616 2.90361 2.73734 3.18160 2.89815 2.37901 2.77533 2.98486 4.58491 3.61430 + 0.06990 2.74572 5.70978 1.46974 0.26135 0.43968 1.03351 + 197 2.53761 4.57755 3.85895 3.05555 3.06219 3.90225 3.89097 2.90555 3.23603 1.98376 3.43681 3.14844 2.18635 3.28921 3.56902 2.76101 2.38583 2.48063 5.16546 3.65117 363 l - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 198 2.94035 4.49377 4.16973 3.59341 3.59928 3.99457 4.28692 2.57573 3.48228 2.11382 3.59630 3.88641 1.19333 3.75706 3.46613 3.08341 3.17527 2.51467 5.10025 3.66586 364 p - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 199 2.95410 3.97958 4.76382 4.16399 1.23466 4.10162 4.38107 2.78567 3.65586 2.19089 3.46719 4.20671 3.78920 4.13156 4.03525 3.25126 3.18603 2.50296 2.73984 2.86766 365 f - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 200 2.72297 4.82530 2.62940 2.35446 3.83755 3.31971 3.71413 4.17131 2.26174 3.54363 4.14174 3.02369 2.60946 2.49179 2.66057 2.21727 2.99115 3.74587 4.55596 3.10965 366 s - - S + 2.68620 4.42227 2.77522 2.73112 3.46340 2.40515 3.72496 3.29334 2.67743 2.69357 4.24692 2.90349 2.73742 3.18148 2.89803 2.37889 2.77522 2.98520 4.58479 3.61505 + 0.07731 2.84051 4.13492 0.30572 1.33404 0.48576 0.95510 + 201 2.63880 5.38435 2.63657 2.22720 4.72697 1.94780 3.15235 3.87964 2.57669 3.68860 4.42577 2.57921 3.16991 2.74291 2.86900 2.50219 2.85278 3.77370 5.81843 4.40865 368 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.52175 0.90012 + 202 2.40102 4.71375 2.46996 2.13243 4.71840 3.11745 3.05416 3.48265 2.25142 3.16134 4.41932 2.93828 3.25177 2.60824 2.79040 2.58260 2.90071 3.38079 5.81277 4.40438 369 e - - S + 2.68658 4.42180 2.77453 2.73123 3.46394 2.40505 3.72421 3.29333 2.67765 2.69382 4.24730 2.90354 2.73686 3.18110 2.89829 2.37906 2.77522 2.98525 4.58428 3.61543 + 0.55463 1.48984 1.60791 1.39890 0.28351 0.52175 0.90012 + 203 2.69338 5.29005 2.51143 2.25105 4.62988 2.84270 3.49832 3.48405 2.27737 3.31427 4.33211 2.56706 3.20350 2.85310 2.67590 2.21378 2.73620 3.67787 5.72586 4.31806 375 s - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01250 4.78398 5.50633 0.61958 0.77255 0.95212 0.48763 + 204 2.65942 5.19894 2.69156 2.28179 3.77027 3.19251 3.77484 3.06173 2.43464 2.99400 3.94013 2.58274 3.44930 2.63512 2.62020 2.46578 2.71730 3.35179 5.65696 3.80565 376 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01250 4.78398 5.50633 0.61958 0.77255 0.77169 0.62033 + 205 2.38920 5.21254 2.73488 2.26876 4.51445 3.29559 3.03245 3.05648 2.42252 2.83088 3.97624 2.72691 3.66747 2.74292 2.65924 2.79642 2.87825 3.04317 5.67196 3.47007 377 e - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01186 4.83615 5.55849 0.61958 0.77255 0.33713 1.25111 + 206 2.65422 4.48489 1.88534 2.29942 4.71042 3.12833 3.84224 3.67843 2.58000 3.67468 4.41498 2.22848 4.04754 2.86157 2.64414 2.33478 2.73698 3.75923 5.80928 4.40246 378 d - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.52175 0.90012 + 207 2.52228 5.35256 2.79874 2.27245 4.68298 3.15080 3.25420 3.81263 2.42135 3.03021 2.98061 3.02733 3.41549 2.09266 2.89624 2.43800 3.03420 3.22791 5.79412 4.39217 379 q - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.52175 0.90012 + 208 2.88352 5.03264 3.01718 2.64158 3.36791 3.41419 3.67586 2.82361 2.46533 2.06980 3.25199 2.87105 3.91016 2.67457 2.54739 2.67076 3.11488 3.35644 5.54543 3.24074 380 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.52175 0.90012 + 209 2.31106 5.21929 3.20358 2.11286 3.58411 3.54755 3.12693 3.74178 2.35878 3.37262 4.27754 3.18132 3.64073 2.21825 2.83044 2.63943 3.03559 2.71879 4.50670 3.34948 381 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01003 5.00344 5.72579 0.61958 0.77255 0.46390 0.99109 + 210 2.74907 4.02445 4.23598 3.43708 3.16042 3.98772 3.66116 2.29352 2.78065 1.91975 2.65717 3.64306 4.00461 3.79624 2.62994 3.12682 2.72367 2.05105 5.03295 3.83444 382 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 211 2.79706 4.32223 4.14412 4.07508 2.44930 4.05985 3.54709 1.67401 3.90204 2.17979 2.94629 3.31750 4.42562 4.07034 3.98057 2.91878 2.88141 2.01026 4.94063 2.95520 383 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 212 2.43063 3.51667 2.84063 2.33381 3.23751 3.53757 3.64461 3.61354 2.52297 3.04234 3.80037 3.02528 3.31294 2.77439 2.36706 2.71893 3.04140 2.71650 5.64517 3.47973 384 e - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 213 2.54995 5.35768 3.14585 2.23433 4.68798 3.33616 3.38625 3.80986 2.09254 2.85705 3.68757 2.56176 4.05535 2.40160 2.38927 2.57618 3.04385 3.36418 5.79929 3.79887 385 k - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 214 2.66499 5.02053 2.80345 2.59207 4.23983 3.19081 3.94632 1.95336 2.43621 2.96229 3.77095 2.92719 4.12615 3.11304 2.86357 2.94448 2.42822 2.54184 5.53679 4.21766 386 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 215 2.79062 4.84420 3.48859 2.83007 4.02200 3.06268 4.01637 2.98055 2.36084 1.68419 3.06982 3.40535 3.56488 2.89781 2.78978 2.64270 2.97298 2.81255 5.39215 4.11258 387 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 216 2.78422 4.40067 2.87114 2.38957 4.66317 2.42774 3.11725 3.68493 2.29738 3.11118 3.80555 3.07548 3.38861 2.66839 2.52841 2.36297 2.74889 3.71883 4.85618 3.72852 388 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04975 5.01631 3.17248 0.61958 0.77255 0.48576 0.95510 + 217 2.55009 3.88585 3.08502 2.47179 4.52328 2.60499 3.86026 3.74333 2.31088 3.21633 3.94275 3.03087 2.50945 2.97834 2.41589 2.69163 2.38722 3.38360 5.70135 4.11095 389 k - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01030 4.97686 5.69921 0.61958 0.77255 0.59090 0.80705 + 218 2.71816 5.35510 2.47492 2.28903 4.69101 3.44039 3.67059 2.92462 2.15295 3.03900 4.39818 2.98975 2.40750 2.74839 2.76016 2.49540 2.85213 3.74081 5.79327 4.38792 390 k - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02103 4.97686 4.27462 0.61958 0.77255 0.59090 0.80705 + 219 2.59242 4.56547 3.37418 3.24570 3.28039 3.87349 3.78552 2.80260 2.91515 1.85640 3.67045 2.94464 3.03710 3.48913 3.31352 2.93163 2.57101 2.12270 4.60315 3.29903 391 l - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01041 4.96623 5.68858 0.61958 0.77255 0.61678 0.77584 + 220 2.76552 5.35116 2.75065 2.09233 4.26840 3.39661 3.23930 3.45666 2.13782 2.93921 3.69074 2.78256 2.85112 2.85423 2.61182 2.41762 3.01864 3.73701 5.78920 4.16743 392 e - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01041 4.96623 5.68858 0.61958 0.77255 0.61678 0.77584 + 221 2.56616 4.88573 3.26662 2.33696 2.41520 3.27403 3.41068 2.92250 2.70761 2.68623 3.97070 3.19787 3.38122 3.16656 2.79903 2.47364 2.99470 2.86843 4.82552 3.32054 393 e - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01041 4.96623 5.68858 0.61958 0.77255 0.61678 0.77584 + 222 2.62567 5.35084 2.04845 2.35215 4.39252 3.47212 3.16243 3.98892 2.45186 3.65226 3.66396 2.66846 2.63580 2.82810 3.05661 2.22708 2.99549 3.54011 5.78899 3.92777 394 d - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03667 4.96623 3.53930 0.61958 0.77255 0.61678 0.77584 + 223 2.86103 4.03193 3.18635 2.38909 3.31435 3.61153 3.49109 2.70908 2.69769 2.69388 3.88535 3.22191 3.67076 3.11276 2.73635 2.49324 3.00545 2.72730 2.94731 2.96802 395 e - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01875 4.94025 4.47244 0.61958 0.77255 0.67631 0.71028 + 224 2.62521 5.12447 2.77972 2.44738 3.31605 3.53418 3.86652 3.33309 2.47319 3.03557 4.18886 3.10134 2.42408 2.60018 2.70100 2.64509 2.92363 3.22521 3.41935 3.46519 396 p - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.05901 4.93227 2.99396 0.61958 0.77255 0.69360 0.69269 + 225 2.68343 5.20702 2.88582 2.22963 3.55567 3.45903 3.65367 3.49248 2.11994 2.97314 4.26172 2.80968 3.57686 2.44336 3.06162 2.53581 2.67303 3.18308 3.73101 3.66292 397 k - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01130 4.88456 5.60691 0.61958 0.77255 0.78866 0.60597 + 226 2.68707 4.98468 2.82158 2.38405 3.75917 3.36024 3.65392 3.18317 2.38508 2.73942 3.76303 3.22111 3.36652 3.04584 2.96704 2.31757 2.64759 2.95752 3.21600 3.40268 398 s - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.11345 4.88456 2.30573 0.61958 0.77255 0.78866 0.60597 + 227 2.79298 3.84213 2.48108 2.52210 3.99851 3.60747 3.12972 3.13545 2.48018 3.05991 4.13768 2.83211 3.54520 2.93964 2.41588 2.35619 2.76810 2.97839 5.56015 3.44494 399 s - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02807 4.78362 3.94704 0.61958 0.77255 0.95264 0.48731 + 228 2.58191 4.56682 2.77742 2.37170 4.46635 3.58143 3.77449 3.50815 2.36445 2.67587 4.22448 2.86502 2.73607 2.80387 2.79297 2.07848 2.75446 3.53442 5.63386 3.74575 400 s - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.14447 4.76826 2.07130 0.61958 0.77255 0.97412 0.47405 + 229 2.74120 5.02625 2.90214 2.38037 3.96892 2.81361 3.75340 3.09744 2.29181 2.85276 3.79351 2.85134 3.31773 2.88600 2.57247 2.48932 2.74923 2.81409 5.51153 4.15648 401 k - - . + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02950 4.63827 3.94280 0.61958 0.77255 1.12880 0.39071 + 230 2.65814 5.03703 2.72915 2.44094 4.30481 3.19996 3.74471 3.73960 2.51991 2.72378 3.12113 3.05398 2.98987 2.79382 2.49179 2.12708 2.96796 3.38544 5.51898 3.52938 402 s - - . + 2.68724 4.42293 2.77612 2.73159 3.46162 2.40699 3.72369 3.29398 2.67731 2.69321 4.24701 2.90285 2.73662 3.18257 2.89624 2.37860 2.77511 2.98573 4.58252 3.61251 + 0.60323 0.80254 5.34581 2.99471 0.05135 0.22221 1.61320 + 231 2.51767 5.38833 2.69504 1.91983 4.73145 3.65677 3.84405 3.51135 2.26714 3.33248 4.42951 2.74739 2.83044 2.63263 2.69535 2.26534 2.89575 3.77792 5.82218 4.12814 442 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 232 2.61324 5.33087 2.55247 1.71577 3.78905 3.51981 3.85697 4.11872 2.53837 3.37618 3.68276 2.71899 3.50504 2.96215 2.76975 2.43182 2.62759 3.19721 4.83386 4.08215 443 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 233 1.85315 2.66076 4.74963 4.14369 2.72361 2.76389 4.40211 2.66580 3.95769 1.60680 3.08425 4.19191 4.43908 4.11400 4.01342 3.37949 2.94810 2.35782 4.93743 3.75833 444 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 234 2.54113 3.93957 3.31567 2.58263 3.59686 3.36801 3.93655 2.84244 1.77469 2.55244 4.12290 3.02474 4.11900 2.54032 2.70090 2.93506 2.79964 3.23719 5.55956 3.97978 445 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 235 2.66035 5.38903 1.80529 2.16718 4.22724 3.25823 3.17680 4.00903 2.28647 3.50730 4.43018 2.97613 4.05032 2.48614 2.98498 2.31241 3.11375 3.77870 5.82277 3.97909 446 d - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 236 3.21254 4.56529 5.14365 4.53738 1.97526 4.40976 4.73239 2.19759 4.34073 1.04052 3.41232 4.55986 4.72994 4.44093 4.35221 3.72900 3.00622 2.20314 5.16040 3.53582 447 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 237 2.97518 4.05135 5.35921 4.78478 3.77817 4.66169 5.06989 1.35059 4.61468 1.50253 2.60400 4.82061 4.97178 4.75525 4.65269 4.00168 3.59517 1.52175 5.50364 4.33590 448 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 238 2.63113 4.16111 2.70523 2.01221 4.32546 2.89528 3.69801 3.91463 1.97992 3.37990 4.41866 2.72468 4.05215 2.88390 2.65380 2.44936 2.78930 3.52828 5.81309 3.68713 449 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 239 2.79532 4.56741 2.59886 2.26653 4.72524 2.97326 3.84498 4.20852 1.87988 3.68761 4.42563 2.67816 4.05093 2.72680 2.26697 2.39445 3.11354 3.44147 4.06926 3.70096 450 k - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 240 2.76031 1.91137 4.93344 4.32897 3.47342 4.21043 4.55379 2.12811 4.13437 1.60981 2.11111 4.35327 4.56463 4.27495 4.16872 3.52442 2.73881 2.49904 5.05160 3.88034 451 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 241 3.00579 3.43594 4.91160 4.30236 2.88535 4.17356 4.48924 2.41412 3.62991 0.97514 3.41700 4.31537 4.52645 4.23058 4.12367 3.48482 3.23680 2.59853 2.70167 3.78558 452 l - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 242 2.51291 3.86266 2.42773 2.26878 4.71076 3.65927 3.14908 3.51790 2.32370 3.67561 4.41657 2.44903 4.05255 2.58104 2.64695 2.72413 2.48024 3.27065 5.81133 3.77060 453 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 243 2.89024 4.99098 3.22187 2.69841 3.16242 3.74556 3.43367 3.45008 2.12873 2.47972 3.65551 3.30484 3.00902 2.69329 2.47140 2.87653 2.77051 2.80352 4.74384 3.09104 454 k - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 244 2.75442 4.59220 1.48443 2.55169 4.69407 3.66624 3.85987 4.16899 2.26580 3.66358 4.41104 2.16093 4.06270 2.96232 2.94350 2.69711 3.00639 3.21953 5.80766 4.40610 455 d - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 245 2.53666 4.51809 3.31495 2.50094 3.81458 3.47863 3.66745 3.68842 2.74796 3.30408 3.76297 2.90283 1.45947 2.98944 2.97069 2.84711 3.12065 2.90248 5.56105 4.23506 456 p - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 246 2.18867 5.36299 2.90524 2.21328 4.32931 3.53924 3.49382 3.97251 2.24621 3.14962 3.99253 2.78034 3.78478 2.54072 2.85251 2.30318 2.70173 3.25844 5.80328 3.47734 457 a - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 247 2.48590 4.36945 2.67418 2.22639 4.72760 3.65776 3.84501 4.21118 1.68322 3.11616 4.42723 3.02530 4.05117 2.52411 2.40832 2.54354 2.78662 3.77464 5.82017 4.41136 458 k - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 248 3.97870 5.88109 4.77637 3.79584 5.10245 4.51923 4.26030 4.68907 2.25479 4.07008 4.99673 4.06985 4.83329 3.42182 0.45649 3.98836 4.07883 4.42272 3.45519 4.78623 459 R - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 249 2.59820 4.04607 4.60274 4.00452 3.26886 3.61184 4.36773 2.06089 3.84570 1.56372 3.45362 4.11687 2.06890 4.02734 3.95003 2.68390 3.14561 2.58630 4.40258 3.38622 460 l - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04987 5.01631 3.16967 0.61958 0.77255 0.48576 0.95510 + 250 2.79362 5.19179 3.01710 2.75300 4.64905 2.77281 4.01085 4.10036 2.79939 3.46822 4.43166 2.61914 4.12461 3.14023 3.27668 1.68833 1.53351 3.69065 5.84113 4.47617 461 t - - T + 2.68631 4.42192 2.77519 2.73130 3.46353 2.40482 3.72508 3.29367 2.67738 2.69360 4.24703 2.90360 2.73753 3.18148 2.89804 2.37867 2.77518 2.98532 4.58490 3.61498 + 0.12278 2.37863 3.77824 1.17468 0.36950 0.42506 1.06054 + 251 1.47902 3.78300 4.72209 4.11644 2.74562 3.65840 4.38345 2.02614 3.93274 2.07959 3.21794 4.17061 3.49702 4.09137 3.99270 2.98272 3.05871 2.38788 4.48487 3.74373 467 a - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01009 4.99737 5.71972 0.61958 0.77255 0.53813 0.87669 + 252 2.38222 4.71734 2.84513 2.05232 4.42547 3.25385 3.43556 4.19285 2.14440 3.09056 3.51596 2.80436 3.18490 2.67888 2.63294 2.69832 2.67125 3.58577 5.80764 4.40015 468 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01009 4.99737 5.71972 0.61958 0.77255 0.45436 1.00747 + 253 2.65797 4.06542 2.63237 1.57032 4.71890 3.65831 3.45654 4.20087 2.52289 3.68238 4.00276 3.00654 3.59507 2.12286 2.86428 2.58695 3.11362 3.45316 5.81563 3.91003 469 e - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 254 1.93383 3.77543 4.87213 4.26567 3.27005 3.35948 4.48352 1.60295 4.06924 1.71770 3.29328 4.28554 4.50523 4.21524 4.10410 3.45599 3.20183 2.00553 4.99383 3.81574 470 i - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 255 2.91099 3.35807 4.39311 3.80506 3.12662 3.41984 4.32058 2.74098 2.62412 1.35983 2.89439 3.70896 4.38574 3.55146 3.43970 3.02120 3.14303 2.30767 4.99433 3.18557 471 l - - H + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 256 2.62697 4.23577 2.94369 2.01671 4.73311 3.52212 3.12192 4.21804 1.98366 3.41966 4.43054 2.33684 4.05005 2.29561 2.80226 2.65814 2.90658 3.41449 5.82302 4.41298 472 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 5.01631 5.73865 0.61958 0.77255 0.48576 0.95510 + 257 2.67425 5.24257 2.69003 2.64384 4.09422 3.68496 1.59772 3.97575 2.52719 3.06621 3.97630 3.17995 4.07682 2.88982 2.86815 2.31165 2.78826 3.60139 5.71188 4.10399 473 h - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.18941 5.01631 1.79622 0.61958 0.77255 0.48576 0.95510 + 258 2.81850 5.23743 2.76502 2.35780 4.54654 3.39495 3.79640 3.57339 2.36240 3.35446 4.28834 3.08690 1.61434 2.83455 2.79066 2.56844 3.04975 3.37601 5.69198 4.30446 474 p - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01183 4.83873 5.56107 0.61958 0.77255 0.86853 0.54398 + 259 3.22678 4.58175 4.94227 4.40609 1.73776 4.31983 4.20406 3.01156 4.21650 2.23279 3.33965 4.33985 4.66520 3.80636 4.24184 3.63704 3.45535 2.61441 1.69956 1.91736 475 w - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01183 4.83873 5.56107 0.61958 0.77255 0.30436 1.33787 + 260 2.99670 4.36610 4.95290 4.33956 1.72799 3.71830 4.50360 1.92619 4.12878 1.69258 2.79907 4.33234 4.52551 4.25179 4.13733 3.48573 3.22794 1.98896 4.25850 3.81122 476 l - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00667 5.01308 * 0.61958 0.77255 0.00000 * +// diff --git a/test/jalview/io/test_fn3_hmm.txt b/test/jalview/io/test_fn3_hmm.txt new file mode 100644 index 0000000..0dcfa22 --- /dev/null +++ b/test/jalview/io/test_fn3_hmm.txt @@ -0,0 +1,285 @@ +HMMER3/f [3.1b1 | May 2013] +NAME fn3 +ACC PF00041.13 +DESC Fibronectin type III domain +LENG 86 +ALPH amino +RF no +MM no +CONS yes +CS yes +MAP yes +DATE Fri Jun 20 08:22:31 2014 +NSEQ 106 +EFFN 11.415833 +CKSUM 3564431818 +GA 8.00 7.20 +TC 8.00 7.20 +NC 7.90 7.90 +STATS LOCAL MSV -9.4043 0.71847 +STATS LOCAL VITERBI -9.7737 0.71847 +STATS LOCAL FORWARD -3.8341 0.71847 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 2.70330 4.91262 3.03272 2.64079 3.60307 2.84344 3.74204 3.07942 2.79841 2.65364 4.14864 2.95826 2.87120 3.02176 2.96125 2.44783 2.59757 2.57680 4.02726 3.21526 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.00000 * + 1 3.16986 5.21447 4.52134 3.29953 4.34285 4.18764 4.30886 3.35801 3.70246 2.11675 4.32057 4.32984 0.76706 3.91880 4.22437 3.23552 3.21670 2.88223 5.80355 3.93889 1 p - - - + 2.68629 4.42236 2.77530 2.73088 3.46365 2.40512 3.72505 3.29365 2.67737 2.69316 4.24701 2.90358 2.73734 3.18157 2.89812 2.37898 2.77517 2.98515 4.58488 3.61514 + 0.09796 2.38361 6.81068 0.10064 2.34607 0.48576 0.95510 + 2 2.70230 5.97353 2.24744 2.62947 5.31433 2.60356 4.43584 4.79731 3.17221 2.95090 5.01531 3.26630 2.09873 3.30219 3.34190 1.45782 3.14099 3.57507 6.40877 4.25623 3 s - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 3 1.38116 5.98285 3.50784 2.54546 5.32790 3.48945 4.43311 4.81385 2.38773 3.98773 5.02352 3.27895 1.92260 2.69012 2.96119 2.64228 3.29228 3.29618 6.41555 4.20553 4 a - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 4 3.32856 5.10403 4.47046 4.60386 4.23079 4.75438 5.09647 2.69918 4.46632 2.97102 4.23502 4.77984 0.63388 4.68581 3.76781 4.05413 3.46306 2.04533 5.75329 4.56372 5 P - - - + 2.68616 4.42236 2.77530 2.73134 3.46365 2.40523 3.72505 3.29295 2.67751 2.69303 4.24634 2.90357 2.73739 3.18157 2.89783 2.37897 2.77530 2.98529 4.58488 3.61514 + 0.09682 2.39494 6.81068 0.10162 2.33687 0.48576 0.95510 + 5 2.95325 4.65976 3.57762 2.20709 3.14816 2.51487 3.41109 4.78902 2.65862 3.19599 4.41042 3.45032 3.44719 2.43205 2.26492 2.25400 2.23196 3.66828 4.80003 4.52485 7 e - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01246 6.08833 4.59386 0.61958 0.77255 0.48576 0.95510 + 6 2.74215 5.97618 2.19482 2.69150 4.58171 2.33553 3.83525 3.28222 2.95080 3.32698 5.01691 1.45822 3.52462 2.79670 2.90942 3.13467 3.27956 4.36668 6.40902 3.92307 8 n - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00341 6.07928 6.80162 0.61958 0.77255 0.44282 1.02784 + 7 3.32507 4.98102 3.78072 3.31043 2.85257 4.76439 5.09585 2.50332 4.69760 1.03851 3.36125 4.91001 2.73206 4.83820 4.72389 4.07376 3.83146 1.59790 5.60385 4.42704 9 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.03752 6.08833 3.36505 0.61958 0.77255 0.48576 0.95510 + 8 3.15997 4.90658 3.35204 2.72775 4.53493 3.60960 2.65074 3.69535 2.11078 4.01384 4.99896 3.14668 4.61695 2.40643 2.34723 1.92358 2.03982 3.05153 6.39127 4.98082 10 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00349 6.05430 6.77664 0.61958 0.77255 0.35749 1.20207 + 9 1.76295 3.98252 5.55061 4.93551 2.13202 3.39992 5.09294 2.14638 4.23898 2.23988 3.42109 4.92079 4.39252 3.70640 3.99349 3.50811 3.63432 1.47830 4.51148 4.41177 11 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 10 3.01387 4.98892 2.91217 2.42744 5.22342 4.00576 3.74074 2.67275 2.47618 2.92529 3.89570 3.36720 4.15809 3.26810 2.80854 1.81572 2.02040 2.77133 4.92415 4.31555 12 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 11 2.41247 5.98374 2.24093 2.04842 3.41543 2.59695 4.10033 4.81544 3.05501 4.28918 5.02429 2.22829 2.90635 3.12939 3.01921 2.37278 3.01194 3.02522 6.41619 3.66635 13 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.06784 6.08833 2.75947 0.61958 0.77255 0.48576 0.95510 + 12 2.77725 4.36386 3.23435 2.92496 4.75140 4.31852 4.53101 1.91389 3.01135 2.51491 3.47932 2.97934 3.54432 2.88257 2.68923 3.07794 2.71169 1.80880 6.06849 4.75973 14 v - - E + 2.68623 4.42259 2.77533 2.73059 3.46323 2.40500 3.72529 3.29333 2.67757 2.69369 4.24724 2.90364 2.73744 3.18108 2.89835 2.37891 2.77531 2.98493 4.58511 3.61510 + 0.22113 1.62346 6.74643 0.44471 1.02446 0.29166 1.37446 + 13 3.17575 5.97994 3.10322 2.84738 5.32369 2.00173 4.43389 4.80873 3.01150 3.75019 4.42663 2.23751 4.64014 2.74467 2.85546 1.99984 1.67133 4.36987 5.08444 3.58488 18 t - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 14 2.14203 5.98483 2.53686 2.20884 5.33077 2.76253 3.61799 4.81737 2.91636 3.96256 5.02525 2.79307 2.44932 3.35978 3.34773 1.76758 2.51815 4.12754 4.53404 4.35768 19 s - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02274 6.08833 3.90154 0.61958 0.77255 0.48576 0.95510 + 15 3.45984 5.96297 2.32904 2.98671 5.30486 3.14893 3.59992 3.68067 2.95954 4.26690 5.00447 2.01875 4.62814 3.51950 2.89162 1.97303 1.47565 3.87160 6.39755 3.59993 20 t - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00344 6.06904 6.79138 0.61958 0.77255 0.40302 1.10352 + 16 2.82603 5.98256 2.96292 2.53617 4.39559 3.14388 4.09532 4.81336 2.59005 4.28779 5.02326 3.12547 4.63955 2.76620 3.03618 1.28432 2.14874 3.55065 4.82032 3.29405 21 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 17 2.29842 4.96481 5.56794 4.95172 2.45211 3.33868 4.31545 1.97312 4.73378 1.34355 2.88087 4.92903 5.12608 4.86259 4.73754 4.07438 3.55674 1.71344 5.58685 3.78328 22 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 18 2.99930 4.68496 3.44656 2.53427 3.92510 4.04338 3.13178 3.10095 3.07007 2.68343 3.58599 3.17010 4.15335 2.63450 2.71950 2.30083 2.03779 2.23518 4.92400 3.84991 23 t - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 19 3.61302 4.50726 5.99163 5.39935 2.74200 5.23506 5.61087 1.85210 5.20622 1.10188 3.56291 5.40353 5.56305 5.33364 5.22134 4.56441 3.85751 1.20867 6.05610 4.88933 24 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 20 2.90508 5.98486 3.37356 2.37027 5.33083 3.46854 3.40789 4.81743 2.65230 3.22177 4.17825 2.67373 4.63906 2.52648 2.39431 1.50547 2.16764 4.37598 5.01440 5.00552 25 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 21 5.54218 6.63564 6.83891 6.61797 2.57168 6.35073 5.30532 3.96643 6.37377 3.18917 5.26281 6.07009 4.35269 6.11992 6.21105 5.74680 5.75143 4.86346 0.24436 3.66807 26 W - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 22 3.10862 5.98423 2.61761 2.10221 4.46995 3.93009 3.84182 3.79843 2.19229 3.09373 4.47555 2.66452 4.06864 2.59255 2.99987 1.99073 2.05618 3.67318 6.41655 4.47364 27 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 23 2.05280 5.87614 3.77610 2.63103 5.17655 3.25143 3.55897 3.09279 2.68152 3.35866 4.92882 3.43937 1.44938 3.29932 2.98336 2.85751 2.78420 3.02863 4.43359 4.47040 28 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 24 2.65644 5.88726 3.37601 2.96202 5.19190 3.53629 4.46143 4.20046 2.87295 2.91429 4.93884 3.27084 1.07653 3.39095 3.69926 2.07705 3.29723 2.92337 6.34501 4.95985 29 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.32165 6.08833 1.29911 0.61958 0.77255 0.48576 0.95510 + 25 2.44244 5.77880 2.64467 2.21733 3.20572 3.66340 3.27861 4.60939 2.17717 2.95495 4.81953 3.17778 2.62084 2.96028 2.64039 2.55818 2.51134 3.52175 6.21164 4.20060 30 k - - S + 2.68557 4.42278 2.77404 2.73101 3.46370 2.40555 3.72548 3.29364 2.67779 2.69337 4.24743 2.90378 2.73741 3.18051 2.89835 2.37928 2.77557 2.98526 4.58530 3.61392 + 1.12909 0.74203 1.60680 0.24883 1.51281 1.67198 0.20810 + 26 2.76497 5.64634 2.06362 2.44254 4.06108 3.91520 3.28362 3.73992 2.46695 3.95074 4.68755 2.93859 2.87257 2.71813 3.08100 2.16767 2.28242 3.00778 6.08028 4.00221 33 d - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00580 5.54941 6.27176 0.61958 0.77255 1.23854 0.34222 + 27 2.94904 4.81418 2.88265 2.99332 4.83563 1.49306 3.87927 3.68299 2.59086 2.53757 4.07313 2.89409 2.92833 3.04624 2.88166 2.82744 3.22994 3.21444 4.18838 4.04981 34 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00508 5.68074 6.40309 0.61958 0.77255 0.20085 1.70396 + 28 2.96588 5.95917 2.45759 2.65943 5.30490 1.91234 3.11781 3.44164 2.78003 4.01788 4.99965 2.12379 3.26764 2.84040 2.87160 2.26272 3.15721 3.84740 4.86821 3.64128 35 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00351 6.05095 6.77330 0.61958 0.77255 0.34864 1.22298 + 29 2.45969 5.96445 2.88574 2.61716 5.30131 1.53630 4.43818 3.46883 2.98393 3.60366 4.33332 3.25719 4.28257 3.08417 2.40821 2.08539 3.20111 2.81105 6.40207 4.25093 36 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 30 2.71563 5.98438 2.50720 1.96228 5.33013 3.47246 3.38617 3.68065 2.34086 4.03521 4.36775 3.08029 1.87041 2.90329 3.33287 2.70645 2.77558 2.97286 6.41666 4.17777 37 p - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 31 3.04837 4.96747 2.67316 4.92527 2.42064 4.14655 5.09097 1.34551 4.71334 2.18068 3.34829 4.91585 3.31178 4.15082 4.72663 3.69906 3.53551 1.88881 3.93067 3.04034 38 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 32 2.89418 4.58676 2.12720 2.65970 3.99748 4.30700 4.50689 3.12934 2.75241 2.32504 4.34805 3.25317 4.69765 2.93544 2.97945 2.48570 1.85268 2.60501 5.05387 4.40931 39 t - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 33 3.05045 5.96458 3.15002 2.79713 4.16491 1.56242 3.20986 4.07540 2.34002 3.77648 3.66616 2.65073 4.64351 3.21500 2.62101 2.34442 2.98761 3.25677 5.04578 3.36446 40 g - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 34 4.72855 5.99332 6.32397 5.91516 1.75259 5.71064 3.47111 3.64093 3.68669 3.44300 5.13564 5.60513 6.03397 5.64902 5.63703 5.05114 4.95149 3.46344 3.97019 0.49348 41 Y - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 35 3.03913 5.98101 2.74983 1.95825 3.75604 3.98121 3.78677 3.48894 2.41418 2.89991 5.02189 2.66693 4.63989 2.65222 2.20113 2.26435 2.64729 3.16844 6.41420 3.93691 42 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 36 3.75576 5.90373 6.92143 6.48083 5.27028 6.48043 7.33031 1.16190 6.46559 1.72148 4.18143 6.65320 6.63807 6.70678 6.63399 5.94811 5.00240 0.82398 7.51298 6.31097 43 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.04904 6.08833 3.08806 0.61958 0.77255 0.48576 0.95510 + 37 2.63429 4.71789 2.89387 2.04081 4.17861 4.22097 3.38514 2.92734 2.36124 3.26230 4.97143 3.69265 4.61418 2.27063 2.38238 2.70982 2.11937 3.37005 6.36711 3.73375 44 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00353 6.04282 6.76517 0.61958 0.77255 0.32899 1.27173 + 38 3.00800 2.48193 5.53105 4.91728 2.98458 4.75707 4.15268 2.83469 3.12355 2.32451 4.08737 4.91198 5.12099 4.84273 3.46182 3.58557 3.26283 2.28912 2.64554 1.29971 45 y - - E + 2.68641 4.42053 2.77543 2.73091 3.46377 2.40536 3.72420 3.29377 2.67764 2.69378 4.24582 2.90336 2.73763 3.18113 2.89660 2.37910 2.77543 2.98542 4.58500 3.61526 + 0.12278 2.16768 6.81068 0.54422 0.86820 0.48576 0.95510 + 39 2.52553 4.02469 3.60093 2.65311 4.18239 3.63052 4.17989 3.44209 2.14970 3.12319 4.96260 3.43770 4.02454 2.12722 2.15391 2.32250 3.25888 3.40611 2.73453 3.57446 49 q - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02932 6.08833 3.62591 0.61958 0.77255 0.48576 0.95510 + 40 2.85303 5.96779 2.74660 1.91867 5.31393 3.60453 3.59476 4.33679 2.36399 3.57280 3.62613 2.83996 2.06170 2.51716 3.24767 2.43993 2.61505 3.39964 6.39984 4.98824 50 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00347 6.06248 6.78482 0.61958 0.77255 0.67944 0.70705 + 41 2.55267 3.11480 2.72137 2.31006 5.21613 3.67111 4.08491 3.18721 2.11932 2.73126 3.73119 3.72342 3.44703 2.78931 3.31632 2.60923 2.50487 2.33623 6.34948 4.95631 51 k - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.09789 6.06248 2.39773 0.61958 0.77255 0.38130 1.14877 + 42 3.41114 5.92195 2.00739 2.51445 4.35946 1.85149 4.04885 4.75310 3.02073 3.41727 4.96259 1.88803 4.57836 2.81891 2.77402 2.53317 2.79169 3.60394 6.35459 4.48731 52 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00370 5.99676 6.71911 0.61958 0.77255 0.25112 1.50474 + 43 2.89692 5.98568 2.39354 2.04021 5.33202 2.12548 3.27810 4.81889 2.36649 3.39071 4.58505 2.82477 4.63888 2.99231 3.02264 2.04514 2.45319 3.82791 6.41761 5.00590 53 e - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 44 3.10206 5.95088 3.50928 2.19657 4.70794 1.83640 4.44201 3.85177 2.81849 3.20653 3.64542 2.17673 2.82486 2.50236 3.67274 2.64718 2.71954 3.18909 6.39210 3.73228 54 g - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.08059 6.08833 2.58819 0.61958 0.77255 0.48576 0.95510 + 45 2.83017 5.93388 2.31048 1.94273 5.28007 2.46456 3.60606 4.35357 2.35448 2.95362 4.97424 3.06816 3.41033 2.69285 2.84649 2.21743 2.98206 3.67978 4.23187 4.95426 55 e - - C + 2.68733 4.40831 2.77609 2.73043 3.46444 2.40393 3.72592 3.29278 2.67833 2.69426 4.24827 2.90407 2.73626 3.18024 2.89744 2.37952 2.77650 2.98614 4.58019 3.61570 + 1.45631 0.90375 1.01651 1.51529 0.24813 0.96821 0.47765 + 46 2.32839 5.42660 2.93163 2.28220 4.02543 3.04571 3.03894 3.22247 2.82753 3.21315 3.89864 3.49093 2.50859 3.14260 2.89921 2.69284 3.05772 2.38519 4.38264 3.20345 66 e - - G + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00571 5.56406 6.28641 0.61958 0.77255 0.18459 1.78051 + 47 2.69465 3.91083 2.42967 2.34662 4.43247 3.13708 3.62175 3.49809 2.56727 2.84127 4.03266 3.52527 3.00745 3.22895 3.52756 2.46523 2.69768 3.11906 2.19019 4.92515 67 w - - C + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00353 6.04443 6.76678 0.61958 0.77255 0.33269 1.26228 + 48 2.67627 5.86490 3.17099 3.22595 3.40616 4.27494 3.15476 3.07365 2.21494 2.78239 4.39426 2.30764 3.56160 2.19351 2.71433 2.94392 2.62330 2.55032 5.16850 4.37026 68 q - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 49 3.05871 5.98132 3.36643 1.71285 5.32569 3.90513 2.27648 4.25125 2.92072 4.28630 4.28595 2.90579 3.33969 2.79371 2.63337 2.42582 2.46361 2.81009 3.46671 3.72048 69 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 50 2.88323 4.65127 3.40086 2.73607 2.41972 3.62669 3.91044 2.52424 2.75640 2.37424 3.94274 3.64921 4.76561 2.38668 2.64750 3.03028 3.09193 2.27100 6.08057 3.03402 70 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 51 3.36533 5.95840 2.65995 2.86095 3.44584 4.25167 3.55888 2.90987 2.78397 3.33346 3.90493 2.03375 3.68901 2.80089 2.78508 2.11531 1.97302 3.15541 6.39763 4.99330 71 t - - E + 2.68571 4.42246 2.77540 2.73144 3.46375 2.40497 3.72515 3.29375 2.67742 2.69376 4.24711 2.90367 2.73710 3.18135 2.89822 2.37876 2.77540 2.98457 4.58498 3.61524 + 0.06628 2.76409 6.81068 0.97562 0.47314 0.48576 0.95510 + 52 2.38926 5.49703 3.09615 2.80044 4.68202 3.76562 4.62096 2.19958 3.33274 2.03099 4.11871 2.97731 4.26404 3.83080 2.89542 3.19964 2.84193 1.56133 6.03936 4.75239 75 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 53 2.79501 4.92737 2.35659 2.60299 4.06511 2.98090 3.88301 4.80087 2.44593 3.57653 5.01701 3.37711 1.76863 3.53250 3.23955 1.94419 2.68524 2.95506 6.41016 5.00121 76 p - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 54 2.44542 5.98316 3.18675 2.55065 5.32835 2.12386 4.43300 4.38419 2.38413 2.93654 5.02378 2.50193 2.49139 3.27226 2.05133 2.36069 3.70337 4.12664 4.32391 4.48343 77 r - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 55 2.77179 5.98329 2.50848 2.76644 5.32854 3.30269 3.08416 4.38434 3.16759 4.28865 5.02390 2.27915 2.67265 2.61285 3.32102 2.18277 1.82444 2.83013 6.41587 4.35727 78 t - - T + 2.68621 4.42251 2.77546 2.73149 3.46380 2.40468 3.72521 3.29380 2.67767 2.69252 4.24716 2.90344 2.73766 3.18134 2.89827 2.37913 2.77442 2.98545 4.58503 3.61529 + 0.07130 2.69245 6.81068 1.11635 0.39671 0.48576 0.95510 + 56 2.32530 5.97446 3.57954 1.89562 5.31575 4.24796 3.32554 3.73278 2.42253 2.98562 5.01611 3.71687 3.10116 2.71107 2.91871 2.60336 1.70360 3.15915 6.40941 5.00074 83 t - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.35248 6.08833 1.22151 0.61958 0.77255 0.48576 0.95510 + 57 2.95924 5.72336 2.75932 2.63159 3.96190 3.29462 3.22449 3.40062 2.77057 3.18108 3.56769 2.46117 2.98702 3.05715 2.72729 2.56520 1.96589 3.52719 6.16591 2.96938 84 t - - S + 2.68622 4.42162 2.77539 2.73088 3.46349 2.40510 3.72514 3.29311 2.67761 2.69358 4.24710 2.90367 2.73759 3.18166 2.89753 2.37894 2.77488 2.98538 4.58497 3.61523 + 0.23969 1.55321 6.46298 0.15973 1.91309 0.51157 0.91517 + 58 2.78411 5.86726 3.65151 2.46190 3.55121 3.32277 3.71415 3.82816 2.87545 3.69015 4.27003 2.90512 3.60994 2.68731 2.37548 1.72361 1.95655 3.42914 6.30822 3.85760 87 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00384 5.96109 6.68344 0.61958 0.77255 0.21363 1.64843 + 59 2.13080 3.38910 5.56698 4.95075 2.41578 4.20194 3.39215 2.83299 4.73282 2.14660 3.19234 4.92810 5.12527 4.86169 4.18461 4.07348 3.03808 1.63705 4.66089 1.78369 88 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 60 3.12543 5.93769 2.99354 2.53954 5.26303 4.25659 3.21054 2.85212 2.62935 2.82513 3.45830 2.90110 4.19559 2.80624 3.10357 2.88568 1.50190 2.67316 6.38237 3.93622 89 t - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 61 3.61965 4.99402 3.63828 4.95783 2.26826 4.79135 5.12555 1.86647 4.74679 1.34194 3.74460 4.94944 5.15281 3.10559 4.75989 3.74420 3.85186 1.42486 5.61987 4.44474 90 l - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 62 3.10387 5.98366 3.06368 2.31445 4.05906 3.57903 3.48488 4.81531 2.43543 4.01680 3.91148 2.67498 2.99920 2.70828 2.56621 2.14984 1.90367 3.06274 4.55677 4.37671 91 t - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 63 3.34220 5.98744 1.86090 2.69096 5.33359 1.40608 3.63608 4.82043 2.48624 4.29318 4.45099 1.96888 4.06897 3.19339 3.48838 2.73868 3.70514 4.37867 6.41942 4.25681 92 g - - S + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 64 5.18530 6.36522 4.58586 6.57578 3.53131 6.59442 6.84537 2.81242 6.44067 0.21363 3.54046 6.78308 6.53953 6.19263 6.31583 5.99910 5.37457 3.39834 6.73440 5.83217 93 L - - - + 2.68590 4.42227 2.77521 2.73125 3.46356 2.40515 3.72496 3.29356 2.67743 2.69357 4.24692 2.90349 2.73741 3.18148 2.89803 2.37889 2.77521 2.98520 4.58479 3.61505 + 0.02033 3.96193 6.81068 0.31431 1.31041 0.48576 0.95510 + 65 2.93361 5.98253 3.16620 2.07447 5.32745 3.84017 3.84639 3.52003 2.07989 2.71701 4.56317 3.05465 3.94228 2.39023 2.13660 2.81003 2.42767 2.98359 6.41531 3.87097 95 e - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 66 2.17452 5.85112 3.79178 2.44872 5.14174 4.27993 4.47388 4.59086 3.04069 4.13287 4.42378 3.36057 0.82761 3.31072 3.71538 3.13243 3.15654 3.97958 4.90439 4.38214 96 p - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 67 2.72531 5.97666 2.50761 2.79752 4.22378 1.29966 2.70734 4.80294 2.85170 4.02964 5.01805 2.59981 4.64085 3.32835 3.25617 2.51345 3.59137 3.91820 4.88800 2.97800 97 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 68 2.39925 4.86641 3.79312 2.74568 5.13568 4.27988 3.97435 3.95098 2.69562 3.65359 3.00813 3.38952 4.67180 3.12070 2.33490 2.43668 1.27713 2.90106 6.31421 4.93977 98 t - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 69 2.87821 5.98261 2.71299 2.05681 3.93787 3.36966 3.57296 3.81023 2.25993 3.03102 3.49917 2.39917 3.09415 2.62154 2.82818 2.67359 2.51409 3.67730 4.58228 5.00448 99 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 70 6.32206 7.09639 6.95855 7.01624 2.70399 6.62558 5.12529 5.84365 6.77161 4.03604 6.32463 4.32154 6.86163 6.30239 6.48747 6.05185 6.49899 5.81871 5.18730 0.14189 100 Y - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 71 3.06725 5.97020 3.56838 1.93769 4.23056 3.77167 3.39655 3.53252 2.56448 3.45405 4.47893 2.47898 4.64226 2.55695 2.74362 2.36648 2.01401 2.66399 6.40629 3.70776 101 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 72 3.19486 4.19171 5.58508 4.96942 1.44027 4.15574 5.11433 1.81297 4.75161 2.09873 3.37140 4.94615 5.14143 4.88008 4.75485 4.09123 3.83769 1.47173 5.60267 3.09551 102 f - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 73 3.18039 4.06436 3.15201 2.27681 5.32468 3.77041 3.95744 3.70705 2.23538 4.28548 4.11883 2.88564 4.63997 2.58030 1.70576 2.27707 2.39981 3.62914 4.03739 3.61343 103 r - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 74 3.76685 5.84337 6.79391 6.31497 3.84743 6.27452 6.95358 1.59565 6.25134 2.11498 4.30213 6.44619 6.46746 6.44080 6.36566 5.70153 4.90672 0.53161 7.20703 6.03175 104 V - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 75 2.31005 4.88319 3.40675 2.63903 3.58848 4.26911 3.49342 3.09105 2.39543 3.00463 4.93879 3.41670 4.66153 1.98639 2.22144 3.11070 2.61129 2.78609 6.34491 2.92043 105 q - - E + 2.68621 4.42228 2.77522 2.73126 3.46357 2.40516 3.72497 3.29357 2.67744 2.69312 4.24693 2.90350 2.73743 3.18149 2.89804 2.37890 2.77522 2.98521 4.58480 3.61506 + 0.03738 3.58894 4.70319 0.25135 1.50394 0.48576 0.95510 + 76 0.79499 5.17226 4.80437 3.93376 4.33120 3.17569 4.96596 3.30029 4.15773 2.86829 4.32533 4.52823 5.01384 4.41886 4.42465 2.28661 2.19420 2.76335 5.81537 4.60940 107 a - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00340 6.08033 6.80268 0.61958 0.77255 0.44741 1.01966 + 77 2.84306 4.15407 4.98296 3.19564 3.23517 4.66606 3.67524 2.49603 3.23224 2.21212 3.84796 4.62630 5.03633 2.88555 2.43211 3.49088 3.22704 1.33993 5.67363 2.88123 108 v - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 78 3.27061 4.75060 2.81965 3.10410 5.31934 3.95942 3.99367 3.88107 2.62205 4.02823 5.01830 1.35628 3.08534 3.32913 3.08546 1.88067 2.21938 4.02145 6.41122 3.76470 109 n - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00992 6.08833 4.87890 0.61958 0.77255 0.48576 0.95510 + 79 2.39836 4.69624 2.57939 2.56364 4.72011 1.55094 3.74815 4.26504 2.61409 4.28517 5.02018 2.82673 4.26340 2.69971 2.87382 2.73983 2.53993 3.07568 6.41202 5.00074 110 g - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00340 6.08180 6.80415 0.61958 0.77255 0.45398 1.00812 + 80 2.22211 4.94595 2.69424 2.44928 4.84552 2.32005 3.06335 2.95704 2.33976 3.55821 4.09648 2.87488 4.09930 2.85656 2.97877 3.08279 3.07714 2.39346 6.40553 4.01548 111 a - - T + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.38398 6.08833 1.15015 0.61958 0.77255 0.48576 0.95510 + 81 2.96920 5.43248 3.46409 2.76236 3.93019 1.02513 4.29951 4.07917 3.10833 3.39330 4.50784 3.40559 4.48149 3.45547 3.56956 2.50552 2.39680 3.76237 5.94228 3.01765 112 g - - E + 2.68652 4.42259 2.77488 2.73144 3.46170 2.40466 3.72529 3.29388 2.67703 2.69373 4.24724 2.90335 2.73774 3.18162 2.89801 2.37895 2.77529 2.98552 4.58511 3.61537 + 0.29928 1.35852 6.43163 0.48724 0.95274 1.77816 0.18506 + 82 2.84273 4.18992 3.05053 2.12883 3.36284 2.75189 4.25559 3.03507 2.66396 2.65563 4.59024 2.63081 3.84786 2.76844 3.19058 2.84597 2.82776 2.89016 3.06821 3.41272 117 e - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00494 5.70928 6.43163 0.61958 0.77255 1.56406 0.23482 + 83 3.37920 5.61493 3.74277 3.20384 4.92800 1.01625 3.96683 4.35082 2.94708 2.91738 4.72998 3.71516 3.70329 3.52945 3.00683 1.61777 3.61882 4.00263 6.13360 4.80162 118 g - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00481 5.73459 6.45693 0.61958 0.77255 0.30535 1.33510 + 84 2.58463 5.93784 3.04102 2.09605 4.57465 2.51630 3.24109 4.26208 2.60545 3.44607 3.62705 3.20484 1.89678 2.68661 2.74662 2.97880 3.02092 3.23569 6.37074 4.50367 119 p - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00361 6.02233 6.74467 0.61958 0.77255 0.28862 1.38348 + 85 2.48488 5.72055 3.87501 1.97538 3.04853 3.48010 4.51877 3.51898 2.88839 2.73568 4.42660 3.64380 2.08811 3.48814 2.70856 2.40769 2.92982 4.05679 2.77386 3.43366 120 e - - B + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00338 6.08833 6.81068 0.61958 0.77255 0.48576 0.95510 + 86 3.03720 5.94099 3.75455 2.96917 5.26587 2.91682 3.66571 4.11840 2.98472 4.23738 4.98891 3.74380 4.66031 3.40955 3.12788 0.72443 2.46104 4.32115 6.38683 4.99111 121 s - - E + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00227 6.08723 * 0.61958 0.77255 0.00000 * +// diff --git a/test/jalview/io/vcf/VCFLoaderTest.java b/test/jalview/io/vcf/VCFLoaderTest.java index 7099282..7e3c0b4 100644 --- a/test/jalview/io/vcf/VCFLoaderTest.java +++ b/test/jalview/io/vcf/VCFLoaderTest.java @@ -577,7 +577,7 @@ public class VCFLoaderTest assertEquals(sf.getBegin(), 1); assertEquals(sf.getEnd(), 1); assertEquals(sf.getType(), SequenceOntologyI.SYNONYMOUS_VARIANT); - assertEquals(sf.getDescription(), "AGT"); + assertEquals(sf.getDescription(), "agC/agT"); sf = proteinFeatures.get(1); assertEquals(sf.getFeatureGroup(), "VCF"); assertEquals(sf.getBegin(), 4); diff --git a/test/jalview/renderer/OverviewResColourFinderTest.java b/test/jalview/renderer/OverviewResColourFinderTest.java index 1687516..d01e53f 100644 --- a/test/jalview/renderer/OverviewResColourFinderTest.java +++ b/test/jalview/renderer/OverviewResColourFinderTest.java @@ -22,6 +22,7 @@ package jalview.renderer; import static org.testng.AssertJUnit.assertEquals; +import jalview.api.AlignViewportI; import jalview.bin.Cache; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; @@ -33,6 +34,7 @@ import jalview.gui.JvOptionPane; import jalview.schemes.ColourSchemeI; import jalview.schemes.UserColourScheme; import jalview.schemes.ZappoColourScheme; +import jalview.viewmodel.AlignmentViewport; import java.awt.Color; import java.util.ArrayList; @@ -56,7 +58,7 @@ public class OverviewResColourFinderTest { SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF"); AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new OverviewResColourFinder(); // gaps are grey, residues white @@ -80,7 +82,7 @@ public class OverviewResColourFinderTest SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a // gap AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new OverviewResColourFinder(); av.setGlobalColourScheme(new ZappoColourScheme()); @@ -126,7 +128,7 @@ public class OverviewResColourFinderTest SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a // gap AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new OverviewResColourFinder(); Color[] newColours = new Color[24]; @@ -179,7 +181,7 @@ public class OverviewResColourFinderTest SequenceGroup[] groups = new SequenceGroup[1]; groups[0] = sg; - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new OverviewResColourFinder(); // G in group specified as magenta in Zappo @@ -230,8 +232,6 @@ public class OverviewResColourFinderTest { SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a // gap - AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); // non-legacy colouring ResidueColourFinder rcf = new OverviewResColourFinder(); @@ -269,9 +269,7 @@ public class OverviewResColourFinderTest // gaps gap colour c = rcf.getBoxColour(shader, seq, 3); - assertEquals( - jalview.renderer.OverviewResColourFinder.OVERVIEW_DEFAULT_GAP, - c); + assertEquals(OverviewResColourFinder.OVERVIEW_DEFAULT_GAP, c); // non legacy colouring with colour scheme rcf = new OverviewResColourFinder(false, Color.blue, Color.red); diff --git a/test/jalview/renderer/ResidueColourFinderTest.java b/test/jalview/renderer/ResidueColourFinderTest.java index 81fb2c0..24f653c 100644 --- a/test/jalview/renderer/ResidueColourFinderTest.java +++ b/test/jalview/renderer/ResidueColourFinderTest.java @@ -22,6 +22,7 @@ package jalview.renderer; import static org.testng.AssertJUnit.assertEquals; +import jalview.api.AlignViewportI; import jalview.datamodel.Alignment; import jalview.datamodel.AlignmentI; import jalview.datamodel.Sequence; @@ -30,6 +31,7 @@ import jalview.gui.AlignViewport; import jalview.gui.JvOptionPane; import jalview.schemes.UserColourScheme; import jalview.schemes.ZappoColourScheme; +import jalview.viewmodel.AlignmentViewport; import java.awt.Color; @@ -51,7 +53,7 @@ public class ResidueColourFinderTest { SequenceI seq = new Sequence("name", "MATVLGSPRAPAFF"); // FER1_MAIZE... AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new ResidueColourFinder(); av.setGlobalColourScheme(new ZappoColourScheme()); @@ -86,7 +88,7 @@ public class ResidueColourFinderTest { SequenceI seq = new Sequence("name", "MA--TVLGSPRAPAFF"); AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new ResidueColourFinder(); assertEquals(Color.white, @@ -109,7 +111,7 @@ public class ResidueColourFinderTest SequenceI seq = new Sequence("name", "MAT--GSPRAPAFF"); // FER1_MAIZE... + a // gap AlignmentI al = new Alignment(new SequenceI[] { seq }); - final AlignViewport av = new AlignViewport(al); + final AlignViewportI av = new AlignViewport(al); ResidueColourFinder rcf = new ResidueColourFinder(); Color[] newColours = new Color[24]; diff --git a/test/jalview/renderer/ScaleRendererTest.java b/test/jalview/renderer/ScaleRendererTest.java index 0af67cd..e78fc5a 100644 --- a/test/jalview/renderer/ScaleRendererTest.java +++ b/test/jalview/renderer/ScaleRendererTest.java @@ -6,10 +6,10 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.io.DataSourceType; import jalview.io.FileLoader; import jalview.renderer.ScaleRenderer.ScaleMark; +import jalview.viewmodel.AlignmentViewport; import java.util.List; @@ -23,7 +23,7 @@ public class ScaleRendererTest String data = ">Seq/20-45\nABCDEFGHIJKLMNOPQRSTUVWXYS\n"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(data, DataSourceType.PASTE); - AlignViewport av = af.getViewport(); + AlignmentViewport av = af.getViewport(); /* * scale has minor ticks at 5, 15, 25, major at 10 and 20 diff --git a/test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java b/test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java index d8b905e..76e4fc5 100644 --- a/test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java +++ b/test/jalview/renderer/seqfeatures/FeatureColourFinderTest.java @@ -6,11 +6,11 @@ import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; +import jalview.api.AlignViewportI; import jalview.api.FeatureColourI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.gui.FeatureRenderer; import jalview.io.DataSourceType; import jalview.io.FileLoader; @@ -43,7 +43,7 @@ import org.testng.annotations.Test; */ public class FeatureColourFinderTest { - private AlignViewport av; + private AlignViewportI av; private SequenceI seq; diff --git a/test/jalview/schemes/ClustalxColourSchemeTest.java b/test/jalview/schemes/ClustalxColourSchemeTest.java index d35ca76..af7036f 100644 --- a/test/jalview/schemes/ClustalxColourSchemeTest.java +++ b/test/jalview/schemes/ClustalxColourSchemeTest.java @@ -85,8 +85,6 @@ public class ClustalxColourSchemeTest // TODO more test cases; check if help documentation matches implementation } - - // @formatter:on /** * Test for colour calculation when the consensus percentage ignores gapped diff --git a/test/jalview/schemes/HmmerGlobalBackgroundTest.java b/test/jalview/schemes/HmmerGlobalBackgroundTest.java new file mode 100644 index 0000000..13bf47b --- /dev/null +++ b/test/jalview/schemes/HmmerGlobalBackgroundTest.java @@ -0,0 +1,91 @@ +package jalview.schemes; + +import static org.testng.Assert.assertEquals; + +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.HMMFile; + +import java.awt.Color; +import java.io.IOException; +import java.net.MalformedURLException; + +import org.testng.annotations.Test; + +public class HmmerGlobalBackgroundTest { + + @Test(groups = "Functional") + public void testFindColour() throws MalformedURLException, IOException + { + HMMFile file = new HMMFile("test/jalview/io/test_PKinase_hmm.txt", + DataSourceType.FILE); + + SequenceI hmmSeq = file.getSeqsAsArray()[0]; + AlignmentI al = new Alignment(new SequenceI[] { hmmSeq }); + al.setHmmConsensus(hmmSeq); + ColourSchemeI scheme = new HmmerGlobalBackground(al); + + /* + * 'A' in column 1, node 2, match emission 2.77204 + * e-2.77204 = 0.0625 + * background frequency is 0.0826 + * ratio is 0.757, log is negative, colour is Orange + */ + Color actual = scheme.findColour('A', 1, null, null, 0); + assertEquals(actual, Color.ORANGE); + + // gap is white + actual = scheme.findColour('-', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + actual = scheme.findColour(' ', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + actual = scheme.findColour('.', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + + /* + * 'Y' in column 4, node 5, match emission 4.41426 + * e-4.41426 = 0.0121 + * background frequency is 0.0292 + * ratio is 0.414, log is negative, colour is Orange + */ + actual = scheme.findColour('Y', 4, null, null, 0); + assertEquals(actual, Color.ORANGE); + + /* + * 'M' in column 109, no matching node, colour is reddish + */ + actual = scheme.findColour('M', 109, null, null, 0); + assertEquals(actual, new Color(230, 0, 0)); + + /* + * 'I' in column 6, node 7, match emission 1.33015 + * e-1.33015 = 0.2644 + * background frequency is 0.0593 + * ratio is 4.459, log is 1.495 + * colour is graduated 1.495/4.52 or 84/255 of the way from + * white(255, 255, 255) to blue(0, 0, 255) + */ + actual = scheme.findColour('I', 6, null, null, 0); + assertEquals(actual, new Color(171, 171, 255)); + + /* + * 'V' in column 14, node 15, match emission 0.44769 + * e-0.44769 = 0.6391 + * background frequency is 0.0686 + * ratio is 9.316, log is 2.232 + * colour is graduated 2.232/4.52 or 126/255 of the way from + * white(255, 255, 255) to blue(0, 0, 255) + */ + actual = scheme.findColour('V', 14, null, null, 0); + assertEquals(actual, new Color(129, 129, 255)); + + /* + * invalid symbol is White + */ + actual = scheme.findColour('X', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + } + +} diff --git a/test/jalview/schemes/HmmerLocalBackgroundTest.java b/test/jalview/schemes/HmmerLocalBackgroundTest.java new file mode 100644 index 0000000..7467ab2 --- /dev/null +++ b/test/jalview/schemes/HmmerLocalBackgroundTest.java @@ -0,0 +1,78 @@ +package jalview.schemes; + +import static org.testng.Assert.assertEquals; + +import jalview.datamodel.Alignment; +import jalview.datamodel.AnnotatedCollectionI; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; +import jalview.io.DataSourceType; +import jalview.io.HMMFile; + +import java.awt.Color; +import java.io.IOException; +import java.net.MalformedURLException; + +import org.testng.annotations.Test; + +public class HmmerLocalBackgroundTest { + + @Test(groups = "Functional") + public void testFindColour() throws MalformedURLException, IOException + { + HMMFile file = new HMMFile("test/jalview/io/test_PKinase_hmm.txt", + DataSourceType.FILE); + + /* + * alignment with 20 residues and background frequencies: + * A/a, S 3/20 = 0.15 + * M, K 4/20 = 0.2 + * V 2/20 = 0.1 + * Q, R, L 1/20 = 0.05 + * log(totalCount) = log(20) = 2.996 + */ + SequenceI seq1 = new Sequence("seq1", "AAMMMKKKVV"); + SequenceI seq2 = new Sequence("seq2", "aAM-QKRSSSL"); + SequenceI hmmSeq = file.getSeqsAsArray()[0]; + AnnotatedCollectionI ac = new Alignment( + new SequenceI[] + { hmmSeq, seq1, seq2 }); + ac.setHmmConsensus(hmmSeq); + ColourSchemeI scheme = new HmmerLocalBackground(ac); + + /* + * 'A' in column 1, node 2, match emission 2.77204 + * e-2.77204 = 0.0625 + * background frequency is 0.15 + * ratio is < 1, log is negative, colour is Orange + */ + Color actual = scheme.findColour('A', 1, null, null, 0); + assertEquals(actual, Color.ORANGE); + + // gap is white + actual = scheme.findColour('-', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + actual = scheme.findColour(' ', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + actual = scheme.findColour('.', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + + /* + * 'L' in column 3, node 4, match emission 1.98342 + * e-1.98342 = 0.1376 + * background frequency is 0.05 + * ratio is 2.752, log is 1.012 + * colour is graduated 1.012/2.996 or 86/255 of the way from + * white(255, 255, 255) to blue(0, 0, 255) + */ + actual = scheme.findColour('L', 3, null, null, 0); + assertEquals(actual, new Color(169, 169, 255)); + + /* + * invalid symbol is White + */ + actual = scheme.findColour('X', 2, null, null, 0); + assertEquals(actual, Color.WHITE); + } + +} diff --git a/test/jalview/schemes/PIDColourSchemeTest.java b/test/jalview/schemes/PIDColourSchemeTest.java index fa4b5d9..c2f86d6 100644 --- a/test/jalview/schemes/PIDColourSchemeTest.java +++ b/test/jalview/schemes/PIDColourSchemeTest.java @@ -4,9 +4,9 @@ import static org.testng.Assert.assertEquals; import jalview.datamodel.SequenceI; import jalview.gui.AlignFrame; -import jalview.gui.AlignViewport; import jalview.io.DataSourceType; import jalview.io.FileLoader; +import jalview.viewmodel.AlignmentViewport; import java.awt.Color; @@ -83,7 +83,7 @@ public class PIDColourSchemeTest */ AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(seqs, DataSourceType.PASTE); - AlignViewport viewport = af.getViewport(); + AlignmentViewport viewport = af.getViewport(); viewport.setIgnoreGapsConsensus(false, af.alignPanel); while (viewport.getConsensusSeq() == null) { diff --git a/test/jalview/structure/StructureSelectionManagerTest.java b/test/jalview/structure/StructureSelectionManagerTest.java index a59fbde..286be1b 100644 --- a/test/jalview/structure/StructureSelectionManagerTest.java +++ b/test/jalview/structure/StructureSelectionManagerTest.java @@ -20,28 +20,53 @@ */ package jalview.structure; +import static org.junit.Assert.assertArrayEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; +import jalview.analysis.AlignmentUtils; +import jalview.api.structures.JalviewStructureDisplayI; +import jalview.bin.Cache; import jalview.datamodel.AlignedCodonFrame; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.PDBEntry; import jalview.datamodel.Sequence; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; +import jalview.ext.jmol.JmolCommands; +import jalview.gui.AlignFrame; +import jalview.gui.Desktop; import jalview.gui.JvOptionPane; +import jalview.gui.SequenceRenderer; +import jalview.gui.StructureChooser; import jalview.io.DataSourceType; +import jalview.io.FileLoader; +import jalview.io.Jalview2xmlBase; import jalview.io.StructureFile; import jalview.util.MapList; +import jalview.ws.DBRefFetcher; +import jalview.ws.sifts.SiftsSettings; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -public class StructureSelectionManagerTest +@Test(singleThreaded = true) +public class StructureSelectionManagerTest extends Jalview2xmlBase { + @Override @BeforeClass(alwaysRun = true) public void setUpJvOptionPane() { @@ -160,4 +185,313 @@ public class StructureSelectionManagerTest assertEquals("1gaq", sf.getFeatureGroup()); assertEquals("ALA: 1 1gaqB", sf.getDescription()); } + + /** + * Verify that RESNUM sequence features are present after creating a PDB + * mapping from a local file, then that everything stays in the same place + * when the file is viewed. The corner case is that 4IM2 is a fragment of a + * PDB file, which still includes the 'ID' field - a bug in Jalview 2.10.3 + * causes features, annotation and positions to be remapped to the wrong place + * on viewing the structure + */ + @Test(groups = { "Network" }) + public void testMapping_EqualsFeatures() + { + // for some reason 'BeforeMethod' (which should be inherited from + // Jalview2XmlBase isn't always called)... + Desktop.instance.closeAll_actionPerformed(null); + try { + Thread.sleep(200); + } catch (Exception foo) {}; + SequenceI seq = new Sequence("4IM2|A", + "LDFCIRNIEKTVMGEISDIHTKLLRLSSSQGTIE"); + String P4IM2_MISSING = "examples/testdata/4IM2_missing.pdb"; + StructureSelectionManager sm = new StructureSelectionManager(); + sm.setProcessSecondaryStructure(true); + sm.setAddTempFacAnnot(true); + StructureFile pmap = sm.setMapping(true, new SequenceI[] { seq }, + new String[] + { null }, P4IM2_MISSING, + DataSourceType.FILE); + assertTrue(pmap != null); + + assertEquals(1, pmap.getSeqs().size()); + assertEquals("4IM2|A", pmap.getSeqs().get(0).getName()); + + List structuremap1 = new ArrayList( + sm.getMapping(P4IM2_MISSING)[0] + .getPDBResNumRanges(seq.getStart(), seq.getEnd())); + + /* + * Verify a RESNUM sequence feature in the PDBfile sequence + * LEU468 - start+0 + * VAL479 - start+11 + * MET486 - start+12 + * GLY496 - start+13 + * GLU516 - start+33 (last) + * + * Expect features and mapping to resolve to same residues. + * Also try creating a view and test again + * + */ + String[] feats = new String[] { "LEU", "468", "VAL", "479", "MET", + "486", "GLY", "496", "GLU", "516" }; + int[] offset = new int[] { 0, 11, 12, 13, 33 }; + + List fdesc = new ArrayList<>(); + for (int f = 0; f < feats.length; f += 2) + { + fdesc.add(feats[f] + ": " + feats[f + 1] + " 4im2A"); + } + SequenceI pdbseq = pmap.getSeqs().get(0); + verifySeqFeats(pdbseq, offset, fdesc); + + /// Now load as a view + + AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded( + "examples/testdata/4IM2_missing.pdb", DataSourceType.FILE); + Desktop.addInternalFrame(alf, "examples/testdata/4IM2_missing.pdb", 800, + 400); + AlignmentI pdbal = alf.getViewport().getAlignment(); + SequenceI pdb_viewseq = pdbal.getSequenceAt(0); + assertEquals(pdb_viewseq.getSequenceAsString(), + seq.getSequenceAsString()); + // verify the feature location on the sequence when pdb imported as an + // alignment + verifySeqFeats(pdb_viewseq, offset, fdesc); + + + JalviewStructureDisplayI viewr = openStructureViaChooser(alf, + pdb_viewseq, "4IM2"); + + // and check all is good with feature location still + verifySeqFeats(pdb_viewseq, offset, fdesc); + + // finally check positional mapping for sequence and structure + PDBEntry pdbe = seq.getPDBEntry("4IM2"); + StructureSelectionManager apssm = alf.alignPanel + .getStructureSelectionManager(); + StructureMapping[] smap = apssm + .getMapping(pdbe.getFile()); + assertNotNull(smap); + assertNotNull(smap[0]); + // find the last position in the alignment sequence - this is not + // 'SequenceI.getEnd()' - which gets the last PDBRESNUM rather than + // SequenceI.getStart() + number of residues in file... + int realSeqEnd = pdb_viewseq.findPosition(pdb_viewseq.getLength()); + List ranges = smap[0].getPDBResNumRanges(pdb_viewseq.getStart(), + realSeqEnd); + assertEquals(structuremap1.size(), ranges.size()); + int tot_mapped = 0; + for (int p = 0; p < ranges.size(); p++) + { + assertArrayEquals(structuremap1.get(p), ranges.get(p)); + tot_mapped += 1 + (structuremap1.get(p)[1] - structuremap1.get(p)[0]); + } + + assertEquals(pdb_viewseq.getLength(), tot_mapped); + + int lastmappedp = StructureMapping.UNASSIGNED_VALUE; + for (int rp = pdb_viewseq.getStart(), rpEnd = pdb_viewseq + .findPosition(pdb_viewseq.getLength() - 1); rp <= rpEnd; rp++) + { + int mappedp = smap[0].getPDBResNum(rp); + if (mappedp != StructureMapping.UNASSIGNED_VALUE) + { + tot_mapped--; + if (lastmappedp == mappedp) + { + Assert.fail("Duplicate mapped position at " + rp + " (dupe = " + + mappedp + ")"); + } + } + } + + Assert.assertEquals(tot_mapped, 0, + "Different number of mapped residues compared to ranges of mapped residues"); + + // positional mapping to atoms for color by structure is still wrong, even + // though panel looks correct. + + StructureMappingcommandSet smcr[] = JmolCommands + .getColourBySequenceCommand(apssm, + new String[] + { pdbe.getFile() }, + new SequenceI[][] + { new SequenceI[] { pdb_viewseq } }, + new SequenceRenderer(alf.alignPanel.getAlignViewport()), + alf.alignPanel); + // Expected - all residues are white + for (StructureMappingcommandSet smm : smcr) + { + for (String c : smm.commands) + { + System.out.println(c); + } + } + } + + private void verifySeqFeats(SequenceI pdbseq, int[] offset, + List fdesc) + { + for (int o = 0; o < offset.length; o++) + { + int res = pdbseq.findPosition(offset[o]); + List sf = pdbseq.getFeatures().findFeatures(res, res, + "RESNUM"); + assertEquals("Expected sequence feature at position " + res + "(" + + offset[o] + ")", 1, sf.size()); + assertEquals("Wrong description at " + res + "(" + offset[o] + ")", + fdesc.get(o), sf.get(0).getDescription()); + } + + } + + @Test(groups = { "Network" }) + public void testAssociatedMappingToSubSeq() throws Exception + { + + // currently this test fails if trimming is enabled + Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, + Boolean.FALSE.toString()); + String TEMP_FACTOR_AA="Temperature Factor"; + String PDBID = "4IM2"; + String FullLengthSeq = ">TBK1_HUMAN Serine/threonine-protein kinase TBK1\n" + + "MQSTSNHLWLLSDILGQGATANVFRGRHKKTGDLFAIKVFNNISFLRPVDVQMREFEVLKKLNHKNIVKLFA\n" + + "IEEETTTRHKVLIMEFCPCGSLYTVLEEPSNAYGLPESEFLIVLRDVVGGMNHLRENGIVHRDIKPGNIMRV\n" + + "IGEDGQSVYKLTDFGAARELEDDEQFVSLYGTEEYLHPDMYERAVLRKDHQKKYGATVDLWSIGVTFYHAAT\n" + + "GSLPFRPFEGPRRNKEVMYKIITGKPSGAISGVQKAENGPIDWSGDMPVSCSLSRGLQVLLTPVLANILEAD\n" + + "QEKCWGFDQFFAETSDILHRMVIHVFSLQQMTAHKIYIHSYNTATIFHELVYKQTKIISSNQELIYEGRRLV\n" + + "LEPGRLAQHFPKTTEENPIFVVSREPLNTIGLIYEKISLPKVHPRYDLDGDASMAKAITGVVCYACRIASTL\n" + + "LLYQELMRKGIRWLIELIKDDYNETVHKKTEVVITLDFCIRNIEKTVKVYEKLMKINLEAAELGEISDIHTK\n" + + "LLRLSSSQGTIETSLQDIDSRLSPGGSLADAWAHQEGTHPKDRNVEKLQVLLNCMTEIYYQFKKDKAERRLA\n" + + "YNEEQIHKFDKQKLYYHATKAMTHFTDECVKKYEAFLNKSEEWIRKMLHLRKQLLSLTNQCFDIEEEVSKYQ\n" + + "EYTNELQETLPQKMFTASSGIKHTMTPIYPSSNTLVEMTLGMKKLKEEMEGVVKELAENNHILERFGSLTMD\n" + + "GGLRNVDCL"; + /* + * annotation exported after importing full length sequence to desktop, opening 4IM2 and selecting 'Add Reference Annotation'. + * + * Note - tabs must be replaced with \t - Eclipse expands them to spaces otherwise. + */ + String FullLengthAnnot = "JALVIEW_ANNOTATION\n" + + "# Created: Mon Feb 05 15:30:20 GMT 2018\n" + + "# Updated: Fri Feb 09 17:05:17 GMT 2018\n" + + "\n" + + "\n" + + "SEQUENCE_REF\tTBK1_HUMAN\n" + + "LINE_GRAPH\tTemperature Factor\tTemperature Factor for 4im2A\t125.22|128.51|120.35|113.12|122.6|114.44|91.49|102.53|98.22|111.41|111.32|116.64|103.55|100.53|95.07|105.55|114.76|128.29|133.55|142.14|121.12|110.36|95.79|95.39|87.14|99.56|93.55|94.21|100.33|110.68|97.85|82.37|75.87|76.53|77.85|82.49|80.92|96.88|122.58|133.31|160.15|180.51|||||242.88|258.97|247.01|227.12|223.24|211.62|184.65|183.51|168.96|160.04|150.88|131.68|130.43|139.87|148.59|136.57|125.7|96.51|74.49|74.08|85.87|70.93|86.47|101.59|97.51|97.39|117.19|114.27|129.5|112.98|147.52|170.26|154.98|168.18|157.51|131.95|105.85|97.78|97.35|76.51|76.31|72.55|71.43|78.82|79.94|75.04|79.54|77.95|83.56|88.5|71.51|71.73|75.96|82.36|81.75|66.51|67.23|69.35|67.92|54.75|71.19|61.85|65.34|67.97|64.51|67.41|62.28|72.85|72.76|70.64|65.23|71.07|67.73|87.72|64.93|75.92|94.02|99.35|93.71|103.59|106.29|115.46|118.69|147.18|130.62|171.64|158.95|164.11||107.42|88.53|83.52|88.06|94.06|80.82|59.01|59.73|78.89|69.21|70.34|81.95|74.53|60.92|64.65|55.79|75.71|68.86|70.95|75.08|87.76|85.43|105.84|||||||||||||||||137.46|151.33|145.17|122.79|111.56|126.72|124.06|161.75|176.84|180.51|198.49|196.75|187.41||195.23|202.27|203.16|226.55|221.75|193.83||||||172.33|177.97|151.47|132.65|99.22|93.7|91.15|88.24|72.35|70.05|70.0|74.92|66.51|68.37|65.76|70.12|74.97|76.89|80.83|70.21|69.48|79.54|82.65|96.54|114.31|140.46|168.51|176.99|205.08|209.27|155.83|139.41|151.3|129.33|111.31|119.62|121.37|102.26|115.39|129.97|128.65|110.38|110.66|116.1|82.53|84.02|82.17|87.63|86.42|77.23|91.23|95.53|102.21|120.73|133.26|109.67|108.49|93.25|92.85|86.39|95.66|94.92|85.82|80.13|76.17|86.61|78.9|77.97|105.6|70.66|69.35|78.94|66.68|63.03|69.91|79.05|75.43|70.73|70.02|80.57|81.74|77.99|84.1|91.66|92.42|94.03|116.47|132.01|154.55|163.99|161.37|155.23|132.78|109.3|90.38|101.83|99.61|91.68|82.77|86.12|82.73|90.13|85.14|79.54|74.27|74.06|72.88|86.34|72.0|69.32|60.9|68.15|52.99|63.53|61.3|66.01|68.28|77.41|71.52|67.18|66.17|71.51|65.47|52.63|65.08|66.37|73.76|77.79|67.58|79.53|84.75|87.42|78.9|79.19|85.57|73.67|80.56|86.19|72.17|66.27|72.8|86.28|78.89|74.5|90.6|80.42|92.5|92.84|96.18|92.08|88.5|87.25|64.6|68.95|65.56|67.55|71.62|78.24|84.95|71.35|86.41|84.73|94.41|95.09|84.74|87.64|88.85|75.1|86.42|79.28|73.14|78.54|80.81|60.66|67.93|71.64|59.85|64.7|61.22|63.84|65.9|62.18|74.95|72.92|93.37|90.47|96.0|93.8|88.46|79.78|83.4|66.55|68.7|73.2|78.76|85.67|84.8|89.59|96.52|79.53|103.51|134.72|126.7|145.31|156.17|149.35|128.48|117.29|118.98|131.59|109.36|90.39|87.68|91.81|78.77|80.11|91.39|75.57|78.98|71.53|76.85|70.9|64.71|73.55|73.45|60.0|69.92|57.89|69.07|66.45|62.85|57.83|57.89|66.4|61.61|60.85|66.47|63.53|63.84|65.96|73.06|70.82|64.51|63.66|73.37|73.59|68.09|78.93|76.99|75.05|71.32|88.4|78.88|93.08|110.61|94.32|99.24|128.99|129.49|132.74|124.21|120.32|142.06|166.41|149.87|153.29|172.19|165.89|181.6|223.11|237.73|176.41|171.09|189.65|188.61|154.84|142.72|154.25|170.99|175.65|||||||110.61||||||||||158.07|170.73|167.93|198.47|212.36|181.71|157.69|163.31|138.96|120.29|131.63|152.26|125.06|136.66|148.97|129.68|120.52|135.31|136.05|119.39|124.18|128.94|123.02|103.37|128.44|134.12|118.88|120.94|130.38|124.67|112.21|113.69|123.65|132.06|114.97|110.75|92.38|101.2|103.25|94.84|85.3|82.19|89.81|98.81|83.03|68.91|65.24|70.31|63.49|86.38|71.07|62.65|63.95|66.98|58.06|68.28|62.11|63.86|67.4|68.69|69.57|68.03|74.23|75.66|70.67|81.08|81.31|82.49|88.15|95.99|92.97|100.01|113.18|122.37|110.99|122.19|159.27|147.74|133.96|111.2|115.64|126.55|107.15|102.85|117.06|116.56|109.55|96.82|98.92|96.53|86.0|88.11|92.76|85.77|79.41|93.06|86.96|76.35|72.37|74.19|68.6|67.46|74.47|76.25|66.73|73.18|75.2|88.21|84.93|75.04|71.09|82.6|80.03|76.22|75.76|83.72|75.85|79.36|90.35|86.9|78.24|95.64|97.38|86.41|85.02|91.87|87.36|77.56|81.25|91.66|83.65|77.67|85.07|89.21|92.66|92.46|89.0|100.83|96.71|94.81|101.37|111.28|124.48|119.73|127.81|134.41|132.4|140.32|140.86|166.52|160.16|168.39|176.74|174.63|172.86|168.55|155.9|132.71|113.44|113.49|123.9|151.11|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n" + + + "\n" + + ""; + AlignFrame alf_full=new + FileLoader(false).LoadFileWaitTillLoaded(FullLengthSeq,DataSourceType.PASTE); + alf_full.loadJalviewDataFile(FullLengthAnnot, DataSourceType.PASTE, null, null); + AlignmentI al_full = alf_full.getViewport().getAlignment(); + AlignmentAnnotation fullseq_tf = al_full.findAnnotations(al_full.getSequences().get(0), null, TEMP_FACTOR_AA).iterator() + .next(); + assertNotNull(fullseq_tf); + + // getMappingFor + // AlignmentI al_full=alf_full.getViewport().getAlignment(); + // + // // load 4IM2 (full length, SIFTS onto full alingnment) + // SiftsSettings.setMapWithSifts(true); + // StructureChooser schoose = new StructureChooser(selectedSeqs_full, + // seq_full, + // alf_full.getViewport().getAlignPanel()); + // schoose.selectStructure(PDBID); + // schoose.ok_ActionPerformed(); + + AlignFrame alf = new FileLoader(false).LoadFileWaitTillLoaded( + ">TBK1_HUMAN/470-502 Serine/threonine-protein kinase TBK1\nFCIRNIEKTVKVYEKLMKINLEAAELGEISDIH", + DataSourceType.PASTE); + Desktop.addInternalFrame(alf, "Foo", 800, 600); + ; + AlignmentI al = alf.getViewport().getAlignment(); + SequenceI seq = al.getSequenceAt(0); + assertEquals(470, seq.getStart()); + // load 4IM2 (full length, SIFTS) + SiftsSettings.setMapWithSifts(true); + StructureImportSettings.setProcessSecondaryStructure(true); + StructureImportSettings.setVisibleChainAnnotation(true); + JalviewStructureDisplayI sview = openStructureViaChooser(alf, seq, + PDBID); + + AlignmentAnnotation subseq_tf=null; + assertTrue(seq.getDBRefs() != null && seq.getDBRefs().length > 0); + + if (!al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator().hasNext()) + { + // FIXME JAL-2321 - don't see reference annotation on alignment the first + // time + // around + SortedMap tipEntries = new TreeMap<>(); + final Map> candidates = new LinkedHashMap<>(); + + AlignmentUtils.findAddableReferenceAnnotations(al.getSequences(), + tipEntries, candidates, al); + AlignmentUtils.addReferenceAnnotations(candidates, al, null); + + if (!al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator() + .hasNext()) + { + Assert.fail( + "JAL-2321 or worse has occured. No secondary structure added to alignment."); + } + } + subseq_tf = al.findAnnotations(seq, null, TEMP_FACTOR_AA).iterator() + .next(); + // verify against annotation after loading 4IM2 to full length TBK1_HUMAN + // verify location of mapped residues + // verify location of secondary structure annotation + // Specific positions: LYS477 (h),THR478 (no helix), ... GLY496(no helix), + // GLU497 (helix), + + // check there is or is not a tempfactor for each mapped position, and that + // values are equal for those positions. + for (int p=seq.getStart();p<=seq.getEnd();p++) + { + Annotation orig,subseq; + orig = fullseq_tf.getAnnotationForPosition(p); + subseq = subseq_tf.getAnnotationForPosition(p); + if (orig == null) + { + Assert.assertNull(subseq, + "Expected no annotation transferred at position " + p); + } + ; + if (orig != null) + { + Assert.assertNotNull(subseq, + "Expected annotation transfer at position " + p); + assertEquals(orig.value, subseq.value); + } + ; + + } + } + + private JalviewStructureDisplayI openStructureViaChooser(AlignFrame alf, + SequenceI seq, + String pDBID) + { + + SequenceI[] selectedSeqs = new SequenceI[] { seq }; + + StructureChooser schoose = new StructureChooser(selectedSeqs, seq, + alf.getViewport().getAlignPanel()); + + try + { + Thread.sleep(5000); + } catch (InterruptedException q) + { + } + ; + Assert.assertTrue(schoose.selectStructure(pDBID), + "Couldn't select structure via structure chooser: " + pDBID); + schoose.showStructures(true); + return schoose.getOpenedStructureViewer(); + } + } diff --git a/test/jalview/util/Binned.csv b/test/jalview/util/Binned.csv new file mode 100644 index 0000000..f140646 --- /dev/null +++ b/test/jalview/util/Binned.csv @@ -0,0 +1,4 @@ +1.8, 4.53 +3.4, 2.65 +0, 5.4 +6.4, 10.8 \ No newline at end of file diff --git a/test/jalview/util/HMMProbabilityDistributionAnalyserTest.java b/test/jalview/util/HMMProbabilityDistributionAnalyserTest.java new file mode 100644 index 0000000..4dbf05e --- /dev/null +++ b/test/jalview/util/HMMProbabilityDistributionAnalyserTest.java @@ -0,0 +1,119 @@ +package jalview.util; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import jalview.datamodel.HMMNode; +import jalview.datamodel.HiddenMarkovModel; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceI; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.testng.annotations.Test; + +import junit.extensions.PA; + +public class HMMProbabilityDistributionAnalyserTest { + + HMMProbabilityDistributionAnalyser analyser = new HMMProbabilityDistributionAnalyser(); + + @Test + public void testMoveToFile() throws IOException + { + + BufferedReader br = new BufferedReader(new FileReader( + "test/jalview/util/test_Fams_for_probability_analysis")); + analyser.moveLocationBy(1, br); + + String line = br.readLine(); + assertEquals(line, "# STOCKHOLM 1.0"); + line = br.readLine(); + assertEquals(line, "seq1 ATW"); + line = br.readLine(); + assertEquals(line, "seq2 ATI"); + + } + + @Test + public void testCountValidResidues() + { + analyser.sequences = new Vector<>(); + analyser.hmm = new HiddenMarkovModel(); + analyser.hmm.setProperty("LENG", "8"); + + List nodes = new ArrayList<>(); + nodes.add(new HMMNode()); + for (int i = 1; i < 9; i++) + { + HMMNode node = new HMMNode(); + node.setResidueNumber(i - 1); + nodes.add(node); + + } + PA.setValue(analyser.hmm, "nodes", nodes); + + SequenceI[] sequence = new Sequence[] { + new Sequence("seq1", "ATGWWSCF"), new Sequence("seq2", "GGMKI"), + new Sequence("seq3", "--.ATccGc") }; + analyser.sequences.add(sequence[0]); + analyser.sequences.add(sequence[1]); + analyser.sequences.add(sequence[2]); + + int count = analyser.countValidResidues(); + assertEquals(count, 16); + } + + @Test(priority = 0) + public void testReadBinned() throws IOException + { + analyser.readBinned("test/jalview/util/"); + Map map = analyser.binned; + assertEquals(map.get("1.8"), 4.53); + assertEquals(map.get("3.4"), 2.65); + assertEquals(map.get("6.4"), 10.8); + assertEquals(map.get("0"), 5.4); + } + + @Test + public void testReadRaw() throws IOException + { + analyser.readRaw("test/jalview/util/"); + List> list = analyser.raw; + + assertEquals(list.get(0).get(0), 1.43); + assertNull(list.get(0).get(2)); + assertEquals(list.get(1).get(1), 1.2); + assertEquals(list.get(2).get(0), 5.6); + assertEquals(list.get(2).get(2), 6.8); + + } + + @Test(priority = 1) + public void testProcessData() throws IOException + { + analyser.keepRaw = true; + BufferedReader brFam = new BufferedReader(new FileReader( + "test/jalview/util/test_Fams_for_probability_analysis")); + BufferedReader brHMM = new BufferedReader(new FileReader( + "test/jalview/util/test_HMMs_for_probability_analysis")); + analyser.readStockholm(brFam); + analyser.readHMM(brHMM); + analyser.processData(6); + Map map = analyser.binned; + List> list = analyser.raw; + assertEquals(map.get("1.8"), 4.863, 0.001d); + assertEquals(map.get("3.4"), 2.65); + assertEquals(map.get("0"), 5.4); + assertEquals(map.get("6.4"), 10.8); + assertEquals(map.get("1.4"), 0.166667, 0.00001d); + assertEquals(map.get("4.4"), 0.5); + + } +} diff --git a/test/jalview/util/MapListTest.java b/test/jalview/util/MapListTest.java index 029b681..fd68e96 100644 --- a/test/jalview/util/MapListTest.java +++ b/test/jalview/util/MapListTest.java @@ -599,60 +599,6 @@ public class MapListTest assertEquals("[ [11, 16] ] 1:3 to [ [72, 53] ]", ml.toString()); } - @Test(groups = "Functional") - public void testAddRange() - { - int[] range = { 1, 5 }; - List ranges = new ArrayList<>(); - - // add to empty list: - MapList.addRange(range, ranges); - assertEquals(1, ranges.size()); - assertSame(range, ranges.get(0)); - - // extend contiguous (same position): - MapList.addRange(new int[] { 5, 10 }, ranges); - assertEquals(1, ranges.size()); - assertEquals(1, ranges.get(0)[0]); - assertEquals(10, ranges.get(0)[1]); - - // extend contiguous (next position): - MapList.addRange(new int[] { 11, 15 }, ranges); - assertEquals(1, ranges.size()); - assertEquals(1, ranges.get(0)[0]); - assertEquals(15, ranges.get(0)[1]); - - // change direction: range is not merged: - MapList.addRange(new int[] { 16, 10 }, ranges); - assertEquals(2, ranges.size()); - assertEquals(16, ranges.get(1)[0]); - assertEquals(10, ranges.get(1)[1]); - - // extend reverse contiguous (same position): - MapList.addRange(new int[] { 10, 8 }, ranges); - assertEquals(2, ranges.size()); - assertEquals(16, ranges.get(1)[0]); - assertEquals(8, ranges.get(1)[1]); - - // extend reverse contiguous (next position): - MapList.addRange(new int[] { 7, 6 }, ranges); - assertEquals(2, ranges.size()); - assertEquals(16, ranges.get(1)[0]); - assertEquals(6, ranges.get(1)[1]); - - // change direction: range is not merged: - MapList.addRange(new int[] { 6, 9 }, ranges); - assertEquals(3, ranges.size()); - assertEquals(6, ranges.get(2)[0]); - assertEquals(9, ranges.get(2)[1]); - - // not contiguous: not merged - MapList.addRange(new int[] { 11, 12 }, ranges); - assertEquals(4, ranges.size()); - assertEquals(11, ranges.get(3)[0]); - assertEquals(12, ranges.get(3)[1]); - } - /** * Check state after construction */ diff --git a/test/jalview/util/MappingUtilsTest.java b/test/jalview/util/MappingUtilsTest.java index d4cf98a..af82ac6 100644 --- a/test/jalview/util/MappingUtilsTest.java +++ b/test/jalview/util/MappingUtilsTest.java @@ -50,6 +50,7 @@ import java.awt.Color; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; import org.testng.annotations.BeforeClass; @@ -913,9 +914,9 @@ public class MappingUtilsTest MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); assertEquals("[]", dnaSelection.getSelected().toString()); - List hidden = dnaHidden.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[0, 4]", Arrays.toString(hidden.get(0))); + Iterator regions = dnaHidden.iterator(); + assertEquals(1, dnaHidden.getNumberOfRegions()); + assertEquals("[0, 4]", Arrays.toString(regions.next())); /* * Column 1 in protein picks up Seq1/K which maps to cols 0-3 in dna @@ -930,9 +931,9 @@ public class MappingUtilsTest proteinSelection.hideSelectedColumns(1, hiddenCols); MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); - hidden = dnaHidden.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[0, 3]", Arrays.toString(hidden.get(0))); + regions = dnaHidden.iterator(); + assertEquals(1, dnaHidden.getNumberOfRegions()); + assertEquals("[0, 3]", Arrays.toString(regions.next())); /* * Column 2 in protein picks up gaps only - no mapping @@ -944,7 +945,7 @@ public class MappingUtilsTest proteinSelection.hideSelectedColumns(2, hiddenCols); MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); - assertTrue(dnaHidden.getHiddenColumnsCopy().isEmpty()); + assertEquals(0, dnaHidden.getNumberOfRegions()); /* * Column 3 in protein picks up Seq1/P, Seq2/Q, Seq3/S which map to columns @@ -959,9 +960,9 @@ public class MappingUtilsTest MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); assertEquals("[0, 1, 2, 3]", dnaSelection.getSelected().toString()); - hidden = dnaHidden.getHiddenColumnsCopy(); - assertEquals(1, hidden.size()); - assertEquals("[5, 10]", Arrays.toString(hidden.get(0))); + regions = dnaHidden.iterator(); + assertEquals(1, dnaHidden.getNumberOfRegions()); + assertEquals("[5, 10]", Arrays.toString(regions.next())); /* * Combine hiding columns 1 and 3 to get discontiguous hidden columns @@ -974,10 +975,10 @@ public class MappingUtilsTest proteinSelection.hideSelectedColumns(3, hiddenCols); MappingUtils.mapColumnSelection(proteinSelection, hiddenCols, proteinView, dnaView, dnaSelection, dnaHidden); - hidden = dnaHidden.getHiddenColumnsCopy(); - assertEquals(2, hidden.size()); - assertEquals("[0, 3]", Arrays.toString(hidden.get(0))); - assertEquals("[5, 10]", Arrays.toString(hidden.get(1))); + regions = dnaHidden.iterator(); + assertEquals(2, dnaHidden.getNumberOfRegions()); + assertEquals("[0, 3]", Arrays.toString(regions.next())); + assertEquals("[5, 10]", Arrays.toString(regions.next())); } @Test(groups = { "Functional" }) @@ -1283,4 +1284,58 @@ public class MappingUtilsTest assertEquals(1, ranges.size()); assertEquals(9, ranges.get(0)[1]); } + + @Test(groups = "Functional") + public void testAddRange() + { + int[] range = { 1, 5 }; + List ranges = new ArrayList<>(); + + // add to empty list: + MappingUtils.addRange(range, ranges); + assertEquals(1, ranges.size()); + assertSame(range, ranges.get(0)); + + // extend contiguous (same position): + MappingUtils.addRange(new int[] { 5, 10 }, ranges); + assertEquals(1, ranges.size()); + assertEquals(1, ranges.get(0)[0]); + assertEquals(10, ranges.get(0)[1]); + + // extend contiguous (next position): + MappingUtils.addRange(new int[] { 11, 15 }, ranges); + assertEquals(1, ranges.size()); + assertEquals(1, ranges.get(0)[0]); + assertEquals(15, ranges.get(0)[1]); + + // change direction: range is not merged: + MappingUtils.addRange(new int[] { 16, 10 }, ranges); + assertEquals(2, ranges.size()); + assertEquals(16, ranges.get(1)[0]); + assertEquals(10, ranges.get(1)[1]); + + // extend reverse contiguous (same position): + MappingUtils.addRange(new int[] { 10, 8 }, ranges); + assertEquals(2, ranges.size()); + assertEquals(16, ranges.get(1)[0]); + assertEquals(8, ranges.get(1)[1]); + + // extend reverse contiguous (next position): + MappingUtils.addRange(new int[] { 7, 6 }, ranges); + assertEquals(2, ranges.size()); + assertEquals(16, ranges.get(1)[0]); + assertEquals(6, ranges.get(1)[1]); + + // change direction: range is not merged: + MappingUtils.addRange(new int[] { 6, 9 }, ranges); + assertEquals(3, ranges.size()); + assertEquals(6, ranges.get(2)[0]); + assertEquals(9, ranges.get(2)[1]); + + // not contiguous: not merged + MappingUtils.addRange(new int[] { 11, 12 }, ranges); + assertEquals(4, ranges.size()); + assertEquals(11, ranges.get(3)[0]); + assertEquals(12, ranges.get(3)[1]); + } } diff --git a/test/jalview/util/Raw.csv b/test/jalview/util/Raw.csv new file mode 100644 index 0000000..83d3452 --- /dev/null +++ b/test/jalview/util/Raw.csv @@ -0,0 +1,4 @@ +Seq1, Seq2, Seq3 +1.43, 2.34, 5.6, +EMPTY, 1.2, 0.05, +EMPTY, 5.4, 6.8, \ No newline at end of file diff --git a/test/jalview/util/test_Fams_for_probability_analysis b/test/jalview/util/test_Fams_for_probability_analysis new file mode 100644 index 0000000..74fbab0 --- /dev/null +++ b/test/jalview/util/test_Fams_for_probability_analysis @@ -0,0 +1,13 @@ +# STOCKHOLM 1.0 +seq1 AW +seq2 GW +seq3 AW +// +# STOCKHOLM 1.0 +seq1 ATW +seq2 ATI +// +# STOCKHOLM 1.0 +seq1 R-WW +seq2 RAWW +// \ No newline at end of file diff --git a/test/jalview/util/test_hmms_for_probability_analysis b/test/jalview/util/test_hmms_for_probability_analysis new file mode 100644 index 0000000..b70d42b --- /dev/null +++ b/test/jalview/util/test_hmms_for_probability_analysis @@ -0,0 +1,99 @@ +HMMER3/f [3.1b2 | February 2015] +NAME test1 +LENG 4 +ALPH amino +RF no +MM no +CONS yes +CS no +MAP yes +DATE Fri Jul 21 06:35:06 2017 +NSEQ 3 +EFFN 3.000000 +CKSUM 657102310 +STATS LOCAL MSV -5.0223 0.82341 +STATS LOCAL VITERBI -4.9569 0.82341 +STATS LOCAL FORWARD -2.0282 0.82341 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 1.94296 5.20658 4.78882 4.52987 4.66525 2.54188 5.19553 2.25221 4.08549 3.87133 5.00250 4.55734 4.73106 4.65220 2.77287 3.67799 1.53923 3.75384 1.48526 4.84023 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01083 4.92694 5.64929 0.61958 0.77255 0.00000 * + 1 0.67027 4.79120 4.60974 4.51892 5.43734 1.28080 5.43621 4.90028 4.64310 4.61059 5.39837 4.28688 4.41468 4.80804 4.79047 3.08135 3.44468 4.10506 6.74908 5.67939 1 A - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01083 4.92694 5.64929 0.61958 0.77255 0.48576 0.95510 + 2 5.43405 6.34487 5.85697 5.84679 4.39288 5.10370 5.65594 5.70664 5.69821 4.87848 6.25251 5.89664 5.70261 6.00722 5.60902 5.64576 5.80049 5.59366 0.08910 4.36301 2 W - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01083 4.92694 5.64929 0.61958 0.77255 0.48576 0.95510 + 3 3.42384 5.23617 4.84601 4.77568 5.39247 4.01365 5.64153 4.72950 4.75585 4.52264 5.55782 4.69647 4.81267 5.08969 4.87301 3.64217 0.20934 4.25217 6.65833 5.63018 3 T - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01083 4.92694 5.64929 0.61958 0.77255 0.48576 0.95510 + 4 3.53954 5.09963 4.71395 4.06038 4.20429 4.44020 4.65482 0.90152 3.16536 2.96072 4.13056 4.31689 4.83725 3.95143 1.46549 3.86829 3.78084 2.85654 5.74911 4.54685 4 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00730 4.92341 * 0.61958 0.77255 0.00000 * +// +HMMER3/f [3.1b2 | February 2015] +NAME test2 +LENG 3 +ALPH amino +RF no +MM no +CONS yes +CS no +MAP yes +DATE Fri Jul 21 06:36:50 2017 +NSEQ 2 +EFFN 2.000000 +CKSUM 777554360 +STATS LOCAL MSV -5.2452 0.95763 +STATS LOCAL VITERBI -5.2886 0.95763 +STATS LOCAL FORWARD -1.5134 0.95763 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 1.33364 4.79082 4.44132 4.24796 3.91456 3.75718 4.85762 2.23342 4.16821 3.09137 4.29744 4.25088 4.41741 4.46803 4.31080 3.33397 1.39376 3.21010 2.54819 4.14914 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01467 4.62483 5.34718 0.61958 0.77255 0.00000 * + 1 0.32372 4.76536 4.42980 4.32857 5.00499 3.55951 5.22620 4.27004 4.37081 4.10495 5.08789 4.22499 4.36948 4.63911 4.51684 3.12947 3.46009 3.76842 6.33337 5.25783 1 A - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01467 4.62483 5.34718 0.61958 0.77255 0.48576 0.95510 + 2 3.04414 4.87155 4.35068 4.21532 4.89213 3.66881 5.13994 4.14202 4.17893 3.96810 5.00600 4.23490 4.44590 4.53729 4.35178 3.25814 0.35496 3.73038 6.23308 5.12388 2 T - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01467 4.62483 5.34718 0.61958 0.77255 0.48576 0.95510 + 3 3.41901 4.77187 4.98694 4.49106 3.10447 4.49364 4.52024 1.21391 4.22709 2.30875 3.57865 4.53952 4.83367 4.43564 4.31127 3.88439 3.66452 2.61326 1.44329 3.34125 3 i - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 4.62006 * 0.61958 0.77255 0.00000 * +// +HMMER3/f [3.1b2 | February 2015] +NAME test3 +LENG 4 +ALPH amino +RF no +MM no +CONS yes +CS no +MAP yes +DATE Fri Jul 21 06:37:01 2017 +NSEQ 2 +EFFN 2.000000 +CKSUM 986955970 +STATS LOCAL MSV -5.4578 0.80004 +STATS LOCAL VITERBI -5.2499 0.80004 +STATS LOCAL FORWARD -2.1856 0.80004 +HMM A C D E F G H I K L M N P Q R S T V W Y + m->m m->i m->d i->m i->i d->m d->d + COMPO 2.16700 5.33023 4.57707 4.32329 4.15728 4.03215 4.83242 4.49728 3.73978 4.00181 5.18156 4.45520 4.63709 4.41734 1.53081 3.84281 4.10073 4.20172 0.82417 4.15750 + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01467 4.62483 5.34718 0.61958 0.77255 0.00000 * + 1 4.09153 5.75008 4.67229 4.09411 5.31638 4.34678 4.67762 4.97541 2.93879 4.35023 5.37643 4.37234 4.85576 3.90366 0.27042 4.17197 4.33362 4.67489 6.11461 5.14175 1 R - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.39762 4.62483 1.14482 0.61958 0.77255 0.48576 0.95510 + 2 0.58385 4.42717 3.89187 3.72118 4.47383 3.23815 4.69159 3.65968 3.74862 3.52210 4.52478 3.76053 4.01438 4.05655 3.96007 2.78076 3.08518 3.24526 5.86063 4.71068 2 A - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.02145 4.24866 4.97100 0.61958 0.77255 0.27360 1.42978 + 3 4.82318 5.87391 5.36844 5.28961 3.81117 4.70308 5.10523 4.98084 5.06729 4.21822 5.56037 5.33222 5.28501 5.40387 5.04111 5.02415 5.17266 4.88017 0.16601 3.78547 3 W - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.01467 4.62483 5.34718 0.61958 0.77255 0.48576 0.95510 + 4 4.82318 5.87391 5.36844 5.28961 3.81117 4.70308 5.10523 4.98084 5.06729 4.21822 5.56037 5.33222 5.28501 5.40387 5.04111 5.02415 5.17266 4.88017 0.16601 3.78547 4 W - - - + 2.68618 4.42225 2.77519 2.73123 3.46354 2.40513 3.72494 3.29354 2.67741 2.69355 4.24690 2.90347 2.73739 3.18146 2.89801 2.37887 2.77519 2.98518 4.58477 3.61503 + 0.00990 4.62006 * 0.61958 0.77255 0.00000 * +// \ No newline at end of file diff --git a/test/jalview/ws/PDBSequenceFetcherTest.java b/test/jalview/ws/PDBSequenceFetcherTest.java index 95863e7..cc3dca8 100644 --- a/test/jalview/ws/PDBSequenceFetcherTest.java +++ b/test/jalview/ws/PDBSequenceFetcherTest.java @@ -20,18 +20,22 @@ */ package jalview.ws; +import static org.testng.Assert.assertEquals; import static org.testng.AssertJUnit.assertTrue; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; +import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.gui.JvOptionPane; import jalview.structure.StructureImportSettings; import jalview.structure.StructureImportSettings.StructureParser; import jalview.ws.seqfetcher.DbSourceProxy; +import java.util.Arrays; import java.util.List; +import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -106,23 +110,76 @@ public class PDBSequenceFetcherTest testRetrieveProteinSeqFromPDB(); } + private class TestRetrieveObject + { + String id; + + int expectedHeight; + + public TestRetrieveObject(String id, int expectedHeight) + { + super(); + this.id = id; + this.expectedHeight = expectedHeight; + } + + } + + private List toRetrieve = Arrays.asList( + new TestRetrieveObject("1QIP", 4), + new TestRetrieveObject("4IM2", 1)); + private void testRetrieveProteinSeqFromPDB() throws Exception { List sps = sf.getSourceProxy("PDB"); - AlignmentI response = sps.get(0).getSequenceRecords("1QIP"); - assertTrue(response != null); - assertTrue(response.getHeight() == 4); - for (SequenceI sq : response.getSequences()) + StringBuilder errors = new StringBuilder(); + for (TestRetrieveObject str : toRetrieve) { - assertTrue("No annotation transfered to sequence.", - sq.getAnnotation().length > 0); - assertTrue("No PDBEntry on sequence.", - sq.getAllPDBEntries().size() > 0); - org.testng.Assert - .assertEquals(sq.getEnd() - sq.getStart() + 1, - sq.getLength(), - "Sequence start/end doesn't match number of residues in sequence"); + AlignmentI response = sps.get(0).getSequenceRecords(str.id); + assertTrue("No aligment for " + str.id, response != null); + assertEquals(response.getHeight(), str.expectedHeight, + "Number of chains for " + str.id); + for (SequenceI sq : response.getSequences()) + { + assertTrue("No annotation transfered to sequence " + sq.getName(), + sq.getAnnotation().length > 0); + assertTrue("No PDBEntry on sequence " + sq.getName(), + sq.getAllPDBEntries().size() > 0); + // FIXME: should test that all residues extracted as sequences from + // chains in structure have a mapping to data in the structure + List prev = null; + int lastp = -1; + for (int col = 1; col <= sq.getLength(); col++) + { + List sf = sq.findFeatures(col, col, "RESNUM"); + if (sf.size() != 1) + { + errors.append( + str.id + ": " + + "Expected one feature at column (position): " + + (col - 1) + + " (" + sq.findPosition(col - 1) + ")" + + ": saw " + + sf.size()); + errors.append("\n"); + if (prev != null) + { + errors.append("Last Feature was at position " + lastp + ": " + + prev.get(0).toString()); + errors.append("\n"); + } + } + else + { + prev = sf; + lastp = sq.findPosition(col - 1); + } + } + } + } + if (errors.length() > 0) + { + Assert.fail(errors.toString()); } } - } diff --git a/test/jalview/ws/dbsources/PfamFullTest.java b/test/jalview/ws/dbsources/PfamFullTest.java new file mode 100644 index 0000000..b914a45 --- /dev/null +++ b/test/jalview/ws/dbsources/PfamFullTest.java @@ -0,0 +1,32 @@ +package jalview.ws.dbsources; + +import static org.testng.Assert.assertEquals; + +import jalview.bin.Cache; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class PfamFullTest +{ + @BeforeClass(alwaysRun = true) + public void setUp() + { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + } + + @Test(groups = "Functional") + public void testGetURL() + { + String path = "pfam.xfam.org/family/ABC/alignment/full"; + + // with default value for domain + String url = new PfamFull().getURL(" abc "); + assertEquals(url, "https://" + path); + + // with override in properties + Cache.setProperty(Pfam.PFAM_BASEURL_KEY, "http://pfam.xfam.org"); + url = new PfamFull().getURL(" abc "); + assertEquals(url, "http://" + path); + } +} diff --git a/test/jalview/ws/dbsources/PfamSeedTest.java b/test/jalview/ws/dbsources/PfamSeedTest.java new file mode 100644 index 0000000..2fa1871 --- /dev/null +++ b/test/jalview/ws/dbsources/PfamSeedTest.java @@ -0,0 +1,32 @@ +package jalview.ws.dbsources; + +import static org.testng.Assert.assertEquals; + +import jalview.bin.Cache; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class PfamSeedTest +{ + @BeforeClass(alwaysRun = true) + public void setUp() + { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + } + + @Test(groups = "Functional") + public void testGetURL() + { + String path = "pfam.xfam.org/family/ABC/alignment/seed"; + + // with default value for domain + String url = new PfamSeed().getURL(" abc "); + assertEquals(url, "https://" + path); + + // with override in properties + Cache.setProperty(Pfam.PFAM_BASEURL_KEY, "http://pfam.xfam.org"); + url = new PfamSeed().getURL(" abc "); + assertEquals(url, "http://" + path); + } +} diff --git a/test/jalview/ws/dbsources/RfamFullTest.java b/test/jalview/ws/dbsources/RfamFullTest.java new file mode 100644 index 0000000..cb60b14 --- /dev/null +++ b/test/jalview/ws/dbsources/RfamFullTest.java @@ -0,0 +1,32 @@ +package jalview.ws.dbsources; + +import static org.testng.Assert.assertEquals; + +import jalview.bin.Cache; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class RfamFullTest +{ + @BeforeClass(alwaysRun = true) + public void setUp() + { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + } + + @Test(groups = "Functional") + public void testGetURL() + { + String path = "rfam.xfam.org/family/ABC/alignment/full"; + + // with default value for domain + String url = new RfamFull().getURL(" abc "); + assertEquals(url, "https://" + path); + + // with override in properties + Cache.setProperty(Rfam.RFAM_BASEURL_KEY, "http://rfam.xfam.org"); + url = new RfamFull().getURL(" abc "); + assertEquals(url, "http://" + path); + } +} diff --git a/test/jalview/ws/dbsources/RfamSeedTest.java b/test/jalview/ws/dbsources/RfamSeedTest.java new file mode 100644 index 0000000..5ca72c2 --- /dev/null +++ b/test/jalview/ws/dbsources/RfamSeedTest.java @@ -0,0 +1,32 @@ +package jalview.ws.dbsources; + +import static org.testng.Assert.assertEquals; + +import jalview.bin.Cache; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class RfamSeedTest +{ + @BeforeClass(alwaysRun = true) + public void setUp() + { + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + } + + @Test(groups = "Functional") + public void testGetURL() + { + String path = "rfam.xfam.org/family/ABC/alignment/stockholm"; + + // with default value for domain + String url = new RfamSeed().getURL(" abc "); + assertEquals(url, "https://" + path); + + // with override in properties + Cache.setProperty(Rfam.RFAM_BASEURL_KEY, "http://rfam.xfam.org"); + url = new RfamSeed().getURL(" abc "); + assertEquals(url, "http://" + path); + } +} diff --git a/test/jalview/ws/dbsources/XfamFetcherTest.java b/test/jalview/ws/dbsources/XfamFetcherTest.java index 573022d..51cff6e 100644 --- a/test/jalview/ws/dbsources/XfamFetcherTest.java +++ b/test/jalview/ws/dbsources/XfamFetcherTest.java @@ -58,7 +58,7 @@ public class XfamFetcherTest @Test(groups = { "External" }) public void testPfamFullAndSeed() throws Exception { - PfamFull pff = new PfamFull(); + Pfam pff = new PfamFull(); PfamSeed pfseed = new PfamSeed(); AlignmentI fullpf = pff.getSequenceRecords(pff.getTestQuery()); diff --git a/test/jalview/ws/sifts/SiftsClientTest.java b/test/jalview/ws/sifts/SiftsClientTest.java index b92766e..75c1413 100644 --- a/test/jalview/ws/sifts/SiftsClientTest.java +++ b/test/jalview/ws/sifts/SiftsClientTest.java @@ -83,103 +83,103 @@ public class SiftsClientTest @BeforeTest(alwaysRun = true) public void populateExpectedMapping() throws SiftsException { - expectedMapping.put(51, new int[] { 1, 2 }); - expectedMapping.put(52, new int[] { 2, 7 }); - expectedMapping.put(53, new int[] { 3, 12 }); - expectedMapping.put(54, new int[] { 4, 24 }); - expectedMapping.put(55, new int[] { 5, 33 }); - expectedMapping.put(56, new int[] { 6, 40 }); - expectedMapping.put(57, new int[] { 7, 47 }); - expectedMapping.put(58, new int[] { 8, 55 }); - expectedMapping.put(59, new int[] { 9, 62 }); - expectedMapping.put(60, new int[] { 10, 69 }); - expectedMapping.put(61, new int[] { 11, 76 }); - expectedMapping.put(62, new int[] { 12, 83 }); - expectedMapping.put(63, new int[] { 13, 87 }); - expectedMapping.put(64, new int[] { 14, 95 }); - expectedMapping.put(65, new int[] { 15, 102 }); - expectedMapping.put(66, new int[] { 16, 111 }); - expectedMapping.put(67, new int[] { 17, 122 }); - expectedMapping.put(68, new int[] { 18, 131 }); - expectedMapping.put(69, new int[] { 19, 137 }); - expectedMapping.put(70, new int[] { 20, 144 }); - expectedMapping.put(71, new int[] { 21, 152 }); - expectedMapping.put(72, new int[] { 22, 160 }); - expectedMapping.put(73, new int[] { 23, 167 }); - expectedMapping.put(74, new int[] { 24, 179 }); - expectedMapping.put(75, new int[] { 25, 187 }); - expectedMapping.put(76, new int[] { 26, 195 }); - expectedMapping.put(77, new int[] { 27, 203 }); - expectedMapping.put(78, new int[] { 28, 208 }); - expectedMapping.put(79, new int[] { 29, 213 }); - expectedMapping.put(80, new int[] { 30, 222 }); - expectedMapping.put(81, new int[] { 31, 231 }); - expectedMapping.put(82, new int[] { 32, 240 }); - expectedMapping.put(83, new int[] { 33, 244 }); - expectedMapping.put(84, new int[] { 34, 252 }); - expectedMapping.put(85, new int[] { 35, 260 }); - expectedMapping.put(86, new int[] { 36, 268 }); - expectedMapping.put(87, new int[] { 37, 275 }); - expectedMapping.put(88, new int[] { 38, 287 }); - expectedMapping.put(89, new int[] { 39, 293 }); - expectedMapping.put(90, new int[] { 40, 299 }); - expectedMapping.put(91, new int[] { 41, 310 }); - expectedMapping.put(92, new int[] { 42, 315 }); - expectedMapping.put(93, new int[] { 43, 319 }); - expectedMapping.put(94, new int[] { 44, 325 }); - expectedMapping.put(95, new int[] { 45, 331 }); - expectedMapping.put(96, new int[] { 46, 337 }); - expectedMapping.put(97, new int[] { 47, 343 }); - expectedMapping.put(98, new int[] { 48, 349 }); - expectedMapping.put(99, new int[] { 49, 354 }); - expectedMapping.put(100, new int[] { 50, 358 }); - expectedMapping.put(101, new int[] { 51, 367 }); - expectedMapping.put(102, new int[] { 52, 375 }); - expectedMapping.put(103, new int[] { 53, 384 }); - expectedMapping.put(104, new int[] { 54, 391 }); - expectedMapping.put(105, new int[] { 55, 395 }); - expectedMapping.put(106, new int[] { 56, 401 }); - expectedMapping.put(107, new int[] { 57, 409 }); - expectedMapping.put(108, new int[] { 58, 417 }); - expectedMapping.put(109, new int[] { 59, 426 }); - expectedMapping.put(110, new int[] { 60, 434 }); - expectedMapping.put(111, new int[] { 61, 442 }); - expectedMapping.put(112, new int[] { 62, 451 }); - expectedMapping.put(113, new int[] { 63, 457 }); - expectedMapping.put(114, new int[] { 64, 468 }); - expectedMapping.put(115, new int[] { 65, 476 }); - expectedMapping.put(116, new int[] { 66, 484 }); - expectedMapping.put(117, new int[] { 67, 492 }); - expectedMapping.put(118, new int[] { 68, 500 }); - expectedMapping.put(119, new int[] { 69, 509 }); - expectedMapping.put(120, new int[] { 70, 517 }); - expectedMapping.put(121, new int[] { 71, 525 }); - expectedMapping.put(122, new int[] { 72, 534 }); - expectedMapping.put(123, new int[] { 73, 538 }); - expectedMapping.put(124, new int[] { 74, 552 }); - expectedMapping.put(125, new int[] { 75, 559 }); - expectedMapping.put(126, new int[] { 76, 567 }); - expectedMapping.put(127, new int[] { 77, 574 }); - expectedMapping.put(128, new int[] { 78, 580 }); - expectedMapping.put(129, new int[] { 79, 585 }); - expectedMapping.put(130, new int[] { 80, 590 }); - expectedMapping.put(131, new int[] { 81, 602 }); - expectedMapping.put(132, new int[] { 82, 609 }); - expectedMapping.put(133, new int[] { 83, 616 }); - expectedMapping.put(134, new int[] { 84, 622 }); - expectedMapping.put(135, new int[] { 85, 630 }); - expectedMapping.put(136, new int[] { 86, 637 }); - expectedMapping.put(137, new int[] { 87, 644 }); - expectedMapping.put(138, new int[] { 88, 652 }); - expectedMapping.put(139, new int[] { 89, 661 }); - expectedMapping.put(140, new int[] { 90, 668 }); - expectedMapping.put(141, new int[] { 91, 678 }); - expectedMapping.put(142, new int[] { 92, 687 }); - expectedMapping.put(143, new int[] { 93, 696 }); - expectedMapping.put(144, new int[] { 94, 705 }); - expectedMapping.put(145, new int[] { 95, 714 }); - expectedMapping.put(146, new int[] { 96, 722 }); - expectedMapping.put(147, new int[] { 97, 729 }); + expectedMapping.put(51, new int[] { 1, 2, 1 }); + expectedMapping.put(52, new int[] { 2, 7, 2 }); + expectedMapping.put(53, new int[] { 3, 12, 3 }); + expectedMapping.put(54, new int[] { 4, 24, 4 }); + expectedMapping.put(55, new int[] { 5, 33, 5 }); + expectedMapping.put(56, new int[] { 6, 40, 6 }); + expectedMapping.put(57, new int[] { 7, 47, 7 }); + expectedMapping.put(58, new int[] { 8, 55, 8 }); + expectedMapping.put(59, new int[] { 9, 62, 9 }); + expectedMapping.put(60, new int[] { 10, 69, 10 }); + expectedMapping.put(61, new int[] { 11, 76, 11 }); + expectedMapping.put(62, new int[] { 12, 83, 12 }); + expectedMapping.put(63, new int[] { 13, 87, 13 }); + expectedMapping.put(64, new int[] { 14, 95, 14 }); + expectedMapping.put(65, new int[] { 15, 102, 15 }); + expectedMapping.put(66, new int[] { 16, 111, 16 }); + expectedMapping.put(67, new int[] { 17, 122, 17 }); + expectedMapping.put(68, new int[] { 18, 131, 18 }); + expectedMapping.put(69, new int[] { 19, 137, 19 }); + expectedMapping.put(70, new int[] { 20, 144, 20 }); + expectedMapping.put(71, new int[] { 21, 152, 21 }); + expectedMapping.put(72, new int[] { 22, 160, 22 }); + expectedMapping.put(73, new int[] { 23, 167, 23 }); + expectedMapping.put(74, new int[] { 24, 179, 24 }); + expectedMapping.put(75, new int[] { 25, 187, 25 }); + expectedMapping.put(76, new int[] { 26, 195, 26 }); + expectedMapping.put(77, new int[] { 27, 203, 27 }); + expectedMapping.put(78, new int[] { 28, 208, 28 }); + expectedMapping.put(79, new int[] { 29, 213, 29 }); + expectedMapping.put(80, new int[] { 30, 222, 30 }); + expectedMapping.put(81, new int[] { 31, 231, 31 }); + expectedMapping.put(82, new int[] { 32, 240, 32 }); + expectedMapping.put(83, new int[] { 33, 244, 33 }); + expectedMapping.put(84, new int[] { 34, 252, 34 }); + expectedMapping.put(85, new int[] { 35, 260, 35 }); + expectedMapping.put(86, new int[] { 36, 268, 36 }); + expectedMapping.put(87, new int[] { 37, 275, 37 }); + expectedMapping.put(88, new int[] { 38, 287, 38 }); + expectedMapping.put(89, new int[] { 39, 293, 39 }); + expectedMapping.put(90, new int[] { 40, 299, 40 }); + expectedMapping.put(91, new int[] { 41, 310, 41 }); + expectedMapping.put(92, new int[] { 42, 315, 42 }); + expectedMapping.put(93, new int[] { 43, 319, 43 }); + expectedMapping.put(94, new int[] { 44, 325, 44 }); + expectedMapping.put(95, new int[] { 45, 331, 45 }); + expectedMapping.put(96, new int[] { 46, 337, 46 }); + expectedMapping.put(97, new int[] { 47, 343, 47 }); + expectedMapping.put(98, new int[] { 48, 349, 48 }); + expectedMapping.put(99, new int[] { 49, 354, 49 }); + expectedMapping.put(100, new int[] { 50, 358, 50 }); + expectedMapping.put(101, new int[] { 51, 367, 51 }); + expectedMapping.put(102, new int[] { 52, 375, 52 }); + expectedMapping.put(103, new int[] { 53, 384, 53 }); + expectedMapping.put(104, new int[] { 54, 391, 54 }); + expectedMapping.put(105, new int[] { 55, 395, 55 }); + expectedMapping.put(106, new int[] { 56, 401, 56 }); + expectedMapping.put(107, new int[] { 57, 409, 57 }); + expectedMapping.put(108, new int[] { 58, 417, 58 }); + expectedMapping.put(109, new int[] { 59, 426, 59 }); + expectedMapping.put(110, new int[] { 60, 434, 60 }); + expectedMapping.put(111, new int[] { 61, 442, 61 }); + expectedMapping.put(112, new int[] { 62, 451, 62 }); + expectedMapping.put(113, new int[] { 63, 457, 63 }); + expectedMapping.put(114, new int[] { 64, 468, 64 }); + expectedMapping.put(115, new int[] { 65, 476, 65 }); + expectedMapping.put(116, new int[] { 66, 484, 66 }); + expectedMapping.put(117, new int[] { 67, 492, 67 }); + expectedMapping.put(118, new int[] { 68, 500, 68 }); + expectedMapping.put(119, new int[] { 69, 509, 69 }); + expectedMapping.put(120, new int[] { 70, 517, 70 }); + expectedMapping.put(121, new int[] { 71, 525, 71 }); + expectedMapping.put(122, new int[] { 72, 534, 72 }); + expectedMapping.put(123, new int[] { 73, 538, 73 }); + expectedMapping.put(124, new int[] { 74, 552, 74 }); + expectedMapping.put(125, new int[] { 75, 559, 75 }); + expectedMapping.put(126, new int[] { 76, 567, 76 }); + expectedMapping.put(127, new int[] { 77, 574, 77 }); + expectedMapping.put(128, new int[] { 78, 580, 78 }); + expectedMapping.put(129, new int[] { 79, 585, 79 }); + expectedMapping.put(130, new int[] { 80, 590, 80 }); + expectedMapping.put(131, new int[] { 81, 602, 81 }); + expectedMapping.put(132, new int[] { 82, 609, 82 }); + expectedMapping.put(133, new int[] { 83, 616, 83 }); + expectedMapping.put(134, new int[] { 84, 622, 84 }); + expectedMapping.put(135, new int[] { 85, 630, 85 }); + expectedMapping.put(136, new int[] { 86, 637, 86 }); + expectedMapping.put(137, new int[] { 87, 644, 87 }); + expectedMapping.put(138, new int[] { 88, 652, 88 }); + expectedMapping.put(139, new int[] { 89, 661, 89 }); + expectedMapping.put(140, new int[] { 90, 668, 90 }); + expectedMapping.put(141, new int[] { 91, 678, 91 }); + expectedMapping.put(142, new int[] { 92, 687, 92 }); + expectedMapping.put(143, new int[] { 93, 696, 93 }); + expectedMapping.put(144, new int[] { 94, 705, 94 }); + expectedMapping.put(145, new int[] { 95, 714, 95 }); + expectedMapping.put(146, new int[] { 96, 722, 96 }); + expectedMapping.put(147, new int[] { 97, 729, 97 }); } @BeforeTest(alwaysRun = true) @@ -311,7 +311,7 @@ public class SiftsClientTest atom.atomIndex = 7; atoms.add(atom); int actualAtomIndex = siftsClient.getAtomIndex(1, atoms); - Assert.assertEquals(actualAtomIndex, -1); + Assert.assertEquals(actualAtomIndex, siftsClient.UNASSIGNED); actualAtomIndex = siftsClient.getAtomIndex(43, atoms); Assert.assertEquals(actualAtomIndex, 7); } -- 1.7.10.2