├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .idea ├── encodings.xml ├── misc.xml └── vcs.xml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── motifs.png ├── pom.xml ├── strucmotif-search-benchmark ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── rcsb │ └── strucmotif │ └── benchmark │ ├── integration │ ├── MyState.java │ ├── StructureSearchBenchmark.java │ └── ToleranceBenchmark.java │ └── io │ └── InvertedIndexRunner.java ├── strucmotif-search-core ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── rcsb │ │ │ └── strucmotif │ │ │ ├── NoSuchFileFailureAnalyzer.java │ │ │ ├── Strucmotif.java │ │ │ ├── StrucmotifApplication.java │ │ │ ├── align │ │ │ ├── AlignmentService.java │ │ │ └── QuaternionAlignmentService.java │ │ │ ├── config │ │ │ ├── AmbiguousMonomerStrategy.java │ │ │ ├── InMemoryStrategy.java │ │ │ ├── InvertedIndexBackend.java │ │ │ ├── MissingCategoryStrategy.java │ │ │ ├── ModifiedResidueStrategy.java │ │ │ ├── MotifPruningStrategy.java │ │ │ ├── ReadErrorStrategy.java │ │ │ ├── ResidueGraphStrategy.java │ │ │ ├── ResidueQualityStrategy.java │ │ │ └── StrucmotifConfig.java │ │ │ ├── core │ │ │ ├── DefaultMotifDefinitionRegistry.java │ │ │ ├── DefaultStrucmotifRuntime.java │ │ │ ├── DefaultTargetAssembler.java │ │ │ ├── HitScorer.java │ │ │ ├── IllegalQueryDefinitionException.java │ │ │ ├── KruskalMotifPruner.java │ │ │ ├── MotifDefinitionRegistry.java │ │ │ ├── MotifPruner.java │ │ │ ├── NoOperationMotifPruner.java │ │ │ ├── QueryExecutionException.java │ │ │ ├── QueryTimeoutException.java │ │ │ ├── StrucmotifRuntime.java │ │ │ └── TargetAssembler.java │ │ │ ├── domain │ │ │ ├── AbstractSearchContext.java │ │ │ ├── MotifSearchContext.java │ │ │ ├── Pair.java │ │ │ ├── SearchContext.java │ │ │ ├── StructureSearchContext.java │ │ │ ├── align │ │ │ │ ├── AlignmentResult.java │ │ │ │ ├── AtomCorrespondence.java │ │ │ │ └── AtomPairingScheme.java │ │ │ ├── bucket │ │ │ │ ├── ArrayBucket.java │ │ │ │ └── Bucket.java │ │ │ ├── motif │ │ │ │ ├── AngleType.java │ │ │ │ ├── DistanceType.java │ │ │ │ ├── EnrichedMotifDefinition.java │ │ │ │ ├── MotifDefinition.java │ │ │ │ ├── Overlap.java │ │ │ │ ├── ResiduePairDescriptor.java │ │ │ │ ├── ResiduePairIdentifier.java │ │ │ │ └── ResiduePairOccurrence.java │ │ │ ├── query │ │ │ │ ├── ContextBuilder.java │ │ │ │ ├── MotifContextBuilder.java │ │ │ │ ├── MotifParameters.java │ │ │ │ ├── MotifQuery.java │ │ │ │ ├── MotifQueryStructure.java │ │ │ │ ├── Parameters.java │ │ │ │ ├── PositionSpecificExchange.java │ │ │ │ ├── QueryStructure.java │ │ │ │ ├── ResultsContentType.java │ │ │ │ ├── SearchQuery.java │ │ │ │ ├── StructureContextBuilder.java │ │ │ │ ├── StructureParameters.java │ │ │ │ ├── StructureQuery.java │ │ │ │ └── StructureQueryStructure.java │ │ │ ├── result │ │ │ │ ├── Hit.java │ │ │ │ ├── MotifHit.java │ │ │ │ ├── MotifSearchResult.java │ │ │ │ ├── MotifTimings.java │ │ │ │ ├── SearchResult.java │ │ │ │ ├── StructureHit.java │ │ │ │ ├── StructureSearchResult.java │ │ │ │ ├── StructureTimings.java │ │ │ │ ├── TargetStructure.java │ │ │ │ ├── Timer.java │ │ │ │ └── Timings.java │ │ │ └── structure │ │ │ │ ├── DefaultStructure.java │ │ │ │ ├── LabelAtomId.java │ │ │ │ ├── LabelSelection.java │ │ │ │ ├── PolymerType.java │ │ │ │ ├── ResidueGraph.java │ │ │ │ ├── ResidueGrid.java │ │ │ │ ├── ResidueType.java │ │ │ │ ├── Structure.java │ │ │ │ └── StructureInformation.java │ │ │ ├── io │ │ │ ├── Committable.java │ │ │ ├── DefaultInvertedIndex.java │ │ │ ├── DefaultResidueTypeResolver.java │ │ │ ├── DefaultStateRepository.java │ │ │ ├── DefaultStructureDataProvider.java │ │ │ ├── DefaultStructureIndexProvider.java │ │ │ ├── DefaultStructureReader.java │ │ │ ├── DefaultStructureWriter.java │ │ │ ├── InvertedIndex.java │ │ │ ├── ResidueTypeResolver.java │ │ │ ├── SingleStructureDataProvider.java │ │ │ ├── SingleStructureIndexProvider.java │ │ │ ├── SingleStructureInvertedIndex.java │ │ │ ├── StateRepository.java │ │ │ ├── StructureDataProvider.java │ │ │ ├── StructureIndexProvider.java │ │ │ ├── StructureReader.java │ │ │ ├── StructureWriter.java │ │ │ └── codec │ │ │ │ ├── BucketCodec.java │ │ │ │ ├── ColferCodec.java │ │ │ │ └── JsonCodec.java │ │ │ └── math │ │ │ ├── Algebra.java │ │ │ └── Partition.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.properties │ │ ├── motifs.json │ │ └── residue-type-mapping.json │ └── test │ ├── java │ └── org │ │ └── rcsb │ │ └── strucmotif │ │ ├── Demo.java │ │ ├── Helpers.java │ │ ├── UpdateTestData.java │ │ ├── align │ │ └── QuaternionAlignmentServiceTest.java │ │ ├── core │ │ ├── KruskalMotifPrunerTest.java │ │ ├── MotifDefinitionRegistryTest.java │ │ ├── MotifIntegrationTest.java │ │ ├── QueryTimeoutTest.java │ │ └── StructureIntegrationTest.java │ │ ├── domain │ │ ├── motif │ │ │ └── ResiduePairOccurrenceTest.java │ │ ├── query │ │ │ └── ResultsContentTypeTest.java │ │ └── structure │ │ │ ├── ConnectednessTest.java │ │ │ ├── OffsetArrayIndexOfTest.java │ │ │ ├── ResidueGraphOptionTest.java │ │ │ ├── ResidueGraphTest.java │ │ │ ├── ResiduePairDescriptorTest.java │ │ │ └── TransformationInformationTest.java │ │ └── io │ │ ├── AssemblyInformationTest.java │ │ ├── DefaultInvertedIndexTest.java │ │ ├── DefaultStructureReaderTest.java │ │ ├── ResidueTypeResolverTest.java │ │ └── StructureWriterImplTest.java │ └── resources │ ├── cif │ ├── 1acj-456.cif │ ├── 1acj-465.cif │ ├── 1acj-546.cif │ ├── 1acj-564.cif │ ├── 1acj-645.cif │ ├── 1acj-654.cif │ └── AF-Q76EI6-F1-model_v4.cif │ ├── index.data │ ├── index.ffindex │ ├── known.list │ ├── orig │ ├── 1acj.bcif │ ├── 1c3c.bcif │ ├── 1ec6.bcif │ ├── 1eta.bcif │ ├── 1exr.bcif │ ├── 1ezc.bcif │ ├── 1g2f.bcif │ ├── 1kp0.bcif │ ├── 1lap.bcif │ ├── 1m4x.bcif │ ├── 1nmr.bcif │ ├── 1qd6.bcif │ ├── 1w27.bcif │ ├── 1zdm.bcif │ ├── 200l.bcif │ ├── 2bfu.bcif │ ├── 2bwx.bcif │ ├── 2mnr.bcif │ ├── 3djy.bcif │ ├── 3ibk.bcif │ ├── 3pei.bcif │ ├── 3uud.bcif │ ├── 4cha.bcif │ ├── 4oog.bcif │ ├── 6lxk.bcif │ ├── 6tne.bcif │ ├── 6zwf.bcif │ ├── 7a3x.bcif │ ├── 7els.bcif │ └── AF_AFA0A0R0FWM3F1.bcif │ ├── renum │ ├── 1DTN.bcif.gz │ ├── 1MDL.bcif.gz │ ├── 1MDR.bcif.gz │ ├── 1MNS.bcif.gz │ ├── 1MRA.bcif.gz │ ├── 1TZZ.bcif.gz │ ├── 1YEY.bcif.gz │ ├── 1ZDM.bcif.gz │ ├── 1acj.bcif │ ├── 1dsd.bcif │ ├── 1eta.bcif │ ├── 1exr.bcif │ ├── 1m4x.bcif │ ├── 200l.bcif │ ├── 2DW6.bcif.gz │ ├── 2DW7.bcif.gz │ ├── 2GDQ.bcif.gz │ ├── 2GGE.bcif.gz │ ├── 2GSH.bcif.gz │ ├── 2HNE.bcif.gz │ ├── 2HXT.bcif.gz │ ├── 2HXU.bcif.gz │ ├── 2HZG.bcif.gz │ ├── 2I5Q.bcif.gz │ ├── 2MNR.bcif.gz │ ├── 2NQL.bcif.gz │ ├── 2OG9.bcif.gz │ ├── 2OO6.bcif.gz │ ├── 2OVL.bcif.gz │ ├── 2OZ3.bcif.gz │ ├── 2P0I.bcif.gz │ ├── 2P3Z.bcif.gz │ ├── 2POZ.bcif.gz │ ├── 2PP0.bcif.gz │ ├── 2PP1.bcif.gz │ ├── 2PP3.bcif.gz │ ├── 2PPG.bcif.gz │ ├── 2QGY.bcif.gz │ ├── 2QQ6.bcif.gz │ ├── 2bfu.bcif │ ├── 2bwx.bcif │ ├── 3BJS.bcif.gz │ ├── 3BOX.bcif.gz │ ├── 3CB3.bcif.gz │ ├── 3CK5.bcif.gz │ ├── 3CXO.bcif.gz │ ├── 3CYJ.bcif.gz │ ├── 3D46.bcif.gz │ ├── 3D47.bcif.gz │ ├── 3EKG.bcif.gz │ ├── 3FXG.bcif.gz │ ├── 3GO2.bcif.gz │ ├── 3H12.bcif.gz │ ├── 3MSY.bcif.gz │ ├── 3N4E.bcif.gz │ ├── 3N4F.bcif.gz │ ├── 3NO1.bcif.gz │ ├── 3OP2.bcif.gz │ ├── 3OPS.bcif.gz │ ├── 3OZM.bcif.gz │ ├── 3OZY.bcif.gz │ ├── 3P3B.bcif.gz │ ├── 3QPE.bcif.gz │ ├── 3RR1.bcif.gz │ ├── 3RRA.bcif.gz │ ├── 3SJN.bcif.gz │ ├── 3SN0.bcif.gz │ ├── 3SN1.bcif.gz │ ├── 3SN4.bcif.gz │ ├── 3T8Q.bcif.gz │ ├── 3T9P.bcif.gz │ ├── 3TCS.bcif.gz │ ├── 3TJ4.bcif.gz │ ├── 3TOY.bcif.gz │ ├── 3TTE.bcif.gz │ ├── 3U4F.bcif.gz │ ├── 3UGV.bcif.gz │ ├── 3UXK.bcif.gz │ ├── 3UXL.bcif.gz │ ├── 3V5C.bcif.gz │ ├── 3V5F.bcif.gz │ ├── 3VCC.bcif.gz │ ├── 3uud.bcif │ ├── 3vk6.bcif │ ├── 3vvk.bcif │ ├── 4A35.bcif.gz │ ├── 4DN1.bcif.gz │ ├── 4DWD.bcif.gz │ ├── 4FP1.bcif.gz │ ├── 4GGB.bcif.gz │ ├── 4H19.bcif.gz │ ├── 4H1Z.bcif.gz │ ├── 4H83.bcif.gz │ ├── 4HNC.bcif.gz │ ├── 4HPN.bcif.gz │ ├── 4IP4.bcif.gz │ ├── 4IP5.bcif.gz │ ├── 4JN7.bcif.gz │ ├── 4JN8.bcif.gz │ ├── 4KEM.bcif.gz │ ├── 4M6U.bcif.gz │ ├── 4X2P.bcif.gz │ ├── 4cha.bcif │ ├── 4ob8.bcif │ ├── 5OLC.bcif.gz │ ├── 5XD7.bcif.gz │ ├── 5XD8.bcif.gz │ ├── 5ire.bcif │ ├── 6TNE.bcif.gz │ ├── 6VIM.bcif.gz │ └── 6j6q.bcif │ ├── renumbered.data │ └── renumbered.ffindex └── strucmotif-search-update ├── UPDATE.md ├── pom.xml └── src ├── main └── java │ └── org │ └── rcsb │ └── strucmotif │ └── update │ ├── Context.java │ ├── Operation.java │ ├── StrucmotifUpdate.java │ ├── UpdateItem.java │ └── extractor │ ├── AlphaFoldKeyExtractor.java │ ├── GenericKeyExtractor.java │ ├── KeyExtractor.java │ ├── KeyExtractorFactory.java │ └── ModelArchiveKeyExtractor.java └── test ├── java └── org │ └── rcsb │ └── strucmotif │ └── update │ ├── Demo.java │ ├── TestCases.java │ ├── UpdateIntegrationTest.java │ └── extractor │ └── KeyExtractorFactoryTest.java └── resources ├── 2RLL.cif.gz ├── 3UM4.cif ├── 3uln.cif.gz ├── 4TUT.bcif.gz ├── 5xes.bcif ├── 6fce.cif ├── af_afa0a0r0fwm3f1.bcif └── af_afq8sy76f1.bcif /.gitattributes: -------------------------------------------------------------------------------- 1 | *.colf binary 2 | *.bcif binary 3 | *.png binary 4 | *.data binary -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Set up JDK 17 19 | uses: actions/setup-java@v3 20 | with: 21 | distribution: 'zulu' 22 | java-version: '17' 23 | 24 | - name: Cache SonarCloud packages 25 | uses: actions/cache@v3 26 | with: 27 | path: ~/.sonar/cache 28 | key: ${{ runner.os }}-sonar 29 | restore-keys: ${{ runner.os }}-sonar 30 | 31 | - name: Cache Maven packages 32 | uses: actions/cache@v3 33 | with: 34 | path: ~/.m2 35 | key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} 36 | restore-keys: ${{ runner.os }}-m2 37 | 38 | - name: Build and analyze 39 | env: 40 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 41 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 42 | run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=rcsb_strucmotif-search 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | target/ 3 | .DS_Store 4 | 5 | # Created by https://www.toptal.com/developers/gitignore/api/phpstorm 6 | # Edit at https://www.toptal.com/developers/gitignore?templates=phpstorm 7 | 8 | ### PhpStorm ### 9 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 10 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 11 | 12 | # User-specific stuff 13 | .idea/**/workspace.xml 14 | .idea/**/tasks.xml 15 | .idea/**/usage.statistics.xml 16 | .idea/**/dictionaries 17 | .idea/**/shelf 18 | 19 | # AWS User-specific 20 | .idea/**/aws.xml 21 | 22 | # Generated files 23 | .idea/**/contentModel.xml 24 | 25 | # Sensitive or high-churn files 26 | .idea/**/dataSources/ 27 | .idea/**/dataSources.ids 28 | .idea/**/dataSources.local.xml 29 | .idea/**/sqlDataSources.xml 30 | .idea/**/dynamic.xml 31 | .idea/**/uiDesigner.xml 32 | .idea/**/dbnavigator.xml 33 | 34 | # Gradle 35 | .idea/**/gradle.xml 36 | .idea/**/libraries 37 | 38 | # Gradle and Maven with auto-import 39 | # When using Gradle or Maven with auto-import, you should exclude module files, 40 | # since they will be recreated, and may cause churn. Uncomment if using 41 | # auto-import. 42 | .idea/artifacts 43 | .idea/compiler.xml 44 | .idea/jarRepositories.xml 45 | .idea/modules.xml 46 | .idea/*.iml 47 | .idea/modules 48 | *.iml 49 | *.ipr 50 | 51 | # CMake 52 | cmake-build-*/ 53 | 54 | # Mongo Explorer plugin 55 | .idea/**/mongoSettings.xml 56 | 57 | # File-based project format 58 | *.iws 59 | 60 | # IntelliJ 61 | out/ 62 | 63 | # mpeltonen/sbt-idea plugin 64 | .idea_modules/ 65 | 66 | # JIRA plugin 67 | atlassian-ide-plugin.xml 68 | 69 | # Cursive Clojure plugin 70 | .idea/replstate.xml 71 | 72 | # SonarLint plugin 73 | .idea/sonarlint/ 74 | 75 | # Crashlytics plugin (for Android Studio and IntelliJ) 76 | com_crashlytics_export_strings.xml 77 | crashlytics.properties 78 | crashlytics-build.properties 79 | fabric.properties 80 | 81 | # Editor-based Rest Client 82 | .idea/httpRequests 83 | 84 | # Android studio 3.1+ serialized cache file 85 | .idea/caches/build_file_checksums.ser 86 | 87 | ### PhpStorm Patch ### 88 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 89 | 90 | # *.iml 91 | # modules.xml 92 | # .idea/misc.xml 93 | # *.ipr 94 | 95 | # Sonarlint plugin 96 | # https://plugins.jetbrains.com/plugin/7973-sonarlint 97 | .idea/**/sonarlint/ 98 | 99 | # SonarQube Plugin 100 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin 101 | .idea/**/sonarIssues.xml 102 | 103 | # Markdown Navigator plugin 104 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced 105 | .idea/**/markdown-navigator.xml 106 | .idea/**/markdown-navigator-enh.xml 107 | .idea/**/markdown-navigator/ 108 | 109 | # Cache file creation bug 110 | # See https://youtrack.jetbrains.com/issue/JBR-2257 111 | .idea/$CACHE_FILE$ 112 | 113 | # CodeStream plugin 114 | # https://plugins.jetbrains.com/plugin/12206-codestream 115 | .idea/codestream.xml 116 | 117 | # End of https://www.toptal.com/developers/gitignore/api/phpstorm -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2019 - now, Sebastian Bittrich 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /motifs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/motifs.png -------------------------------------------------------------------------------- /strucmotif-search-benchmark/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | strucmotif-search 5 | org.rcsb 6 | 0.22.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | strucmotif-search-benchmark 11 | 12 | 13 | 14 | org.rcsb 15 | strucmotif-search-core 16 | 0.22.1-SNAPSHOT 17 | 18 | 19 | 20 | org.openjdk.jmh 21 | jmh-core 22 | ${jmh.version} 23 | 24 | 25 | org.openjdk.jmh 26 | jmh-generator-annprocess 27 | ${jmh.version} 28 | 29 | 30 | -------------------------------------------------------------------------------- /strucmotif-search-benchmark/src/main/java/org/rcsb/strucmotif/benchmark/integration/MyState.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.benchmark.integration; 2 | 3 | import org.openjdk.jmh.annotations.Scope; 4 | import org.openjdk.jmh.annotations.State; 5 | import org.rcsb.strucmotif.Strucmotif; 6 | import org.rcsb.strucmotif.config.StrucmotifConfig; 7 | import org.rcsb.strucmotif.domain.Pair; 8 | import org.rcsb.strucmotif.domain.motif.MotifDefinition; 9 | import org.rcsb.strucmotif.domain.query.StructureContextBuilder; 10 | import org.rcsb.strucmotif.domain.structure.LabelSelection; 11 | import org.rcsb.strucmotif.domain.structure.Structure; 12 | import org.rcsb.strucmotif.io.DefaultResidueTypeResolver; 13 | import org.rcsb.strucmotif.io.StructureReader; 14 | import org.rcsb.strucmotif.io.DefaultStructureReader; 15 | 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.io.UncheckedIOException; 19 | import java.net.URL; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.function.Function; 23 | import java.util.stream.Collectors; 24 | 25 | /** 26 | * Setup needed to benchmark. 27 | */ 28 | @State(Scope.Benchmark) 29 | public class MyState { 30 | private final StrucmotifConfig strucmotifConfig = new StrucmotifConfig(); 31 | private final StructureReader structureReader = new DefaultStructureReader(new DefaultResidueTypeResolver(strucmotifConfig)); 32 | final StructureContextBuilder queryBuilder = Strucmotif.searchForStructures(); 33 | final Map>> structureMap; 34 | 35 | /** 36 | * Create state. 37 | */ 38 | public MyState() { 39 | List motifs = List.of(MotifDefinition.CHH, 40 | MotifDefinition.CHCH, 41 | MotifDefinition.GGGG, 42 | MotifDefinition.HDS, 43 | MotifDefinition.KDDDE, 44 | MotifDefinition.KDEEH, 45 | MotifDefinition.KDEEH_EXCHANGES); 46 | this.structureMap = motifs.stream() 47 | .collect(Collectors.toMap(Function.identity(), this::createStructure)); 48 | } 49 | 50 | private Pair> createStructure(MotifDefinition motif) { 51 | try { 52 | URL url = new URL(prepareUri(strucmotifConfig.getCifFetchUrl(), motif.getStructureIdentifier())); 53 | InputStream inputStream = url.openStream(); 54 | return new Pair<>(structureReader.readFromInputStream(inputStream), motif.getLabelSelections()); 55 | } catch (IOException e) { 56 | throw new UncheckedIOException(e); 57 | } 58 | } 59 | 60 | @SuppressWarnings("Duplicates") 61 | private String prepareUri(String raw, String structureIdentifier) { 62 | String pdbId = structureIdentifier.toLowerCase(); 63 | String pdbIdUc = pdbId.toUpperCase(); 64 | String middle = pdbId.substring(1, 3); 65 | String middleUc = middle.toUpperCase(); 66 | return raw.replace("{middle}", middle) 67 | .replace("{MIDDLE}", middleUc) 68 | .replace("{id}", pdbId) 69 | .replace("{ID}", pdbIdUc); 70 | } 71 | } -------------------------------------------------------------------------------- /strucmotif-search-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | strucmotif-search 5 | org.rcsb 6 | 0.22.1-SNAPSHOT 7 | 8 | 4.0.0 9 | 10 | strucmotif-search-core 11 | 12 | 13 | 14 | 15 | org.rcsb 16 | ciftools-java 17 | ${ciftools.version} 18 | 19 | 20 | 21 | org.rcsb 22 | ffindex-java-core 23 | ${ffindex.version} 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter 30 | ${spring.version} 31 | 32 | 33 | 34 | 35 | com.google.code.gson 36 | gson 37 | ${gson.version} 38 | compile 39 | 40 | 41 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/NoSuchFileFailureAnalyzer.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import org.springframework.beans.factory.UnsatisfiedDependencyException; 4 | import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; 5 | import org.springframework.boot.diagnostics.FailureAnalysis; 6 | 7 | import java.nio.file.NoSuchFileException; 8 | 9 | /** 10 | * Provides better error messages when data files are missing. 11 | */ 12 | public class NoSuchFileFailureAnalyzer extends AbstractFailureAnalyzer { 13 | /** 14 | * Default constructor. 15 | */ 16 | public NoSuchFileFailureAnalyzer() { 17 | } 18 | 19 | @Override 20 | protected FailureAnalysis analyze(Throwable rootFailure, UnsatisfiedDependencyException cause) { 21 | Throwable mostSpecific = cause.getMostSpecificCause(); 22 | if (mostSpecific instanceof NoSuchFileException) { 23 | return new FailureAnalysis(getDescription(cause), getAction((NoSuchFileException) mostSpecific), cause); 24 | } 25 | 26 | // this causes the standard, super-verbose stack trace to kick in 27 | return null; 28 | } 29 | 30 | private String getDescription(UnsatisfiedDependencyException ex) { 31 | return String.format("The bean '%s' could not be created, the root cause is '%s'.", 32 | ex.getBeanName(), ex.getMostSpecificCause()); 33 | } 34 | 35 | private String getAction(NoSuchFileException ex) { 36 | return String.format("Make sure that the directory containing '%s' exists and this process has the necessary read/write permissions.", 37 | ex.getFile()); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/Strucmotif.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import org.rcsb.strucmotif.core.MotifDefinitionRegistry; 4 | import org.rcsb.strucmotif.domain.query.StructureContextBuilder; 5 | import org.rcsb.strucmotif.domain.query.MotifContextBuilder; 6 | 7 | /** 8 | * The entry point to perform strucmotif searches. 9 | */ 10 | public class Strucmotif { 11 | private final StructureContextBuilder structureContextBuilder; 12 | private final MotifContextBuilder motifContextBuilder; 13 | private final MotifDefinitionRegistry motifDefinitionRegistry; 14 | private static final Strucmotif INSTANCE = new Strucmotif(); 15 | 16 | private Strucmotif() { 17 | StrucmotifApplication.main(new String[0]); 18 | this.structureContextBuilder = StrucmotifApplication.structureContextBuilder; 19 | this.motifContextBuilder = StrucmotifApplication.motifContextBuilder; 20 | this.motifDefinitionRegistry = StrucmotifApplication.motifDefinitionRegistry; 21 | } 22 | 23 | /** 24 | * Use a single motif to search for all structures that contain this motif. 25 | * @return a context builder that allows searching for similar structures 26 | */ 27 | public static StructureContextBuilder searchForStructures() { 28 | return INSTANCE.structureContextBuilder; 29 | } 30 | 31 | /** 32 | * Use a single structure to detect all known motifs that occur within this structure. 33 | * @return a context builder that allows detecting motifs 34 | */ 35 | public static MotifContextBuilder detectMotifs() { 36 | return INSTANCE.motifContextBuilder; 37 | } 38 | 39 | /** 40 | * Instance of the registry that keeps track of all supported motifs. 41 | * @return the registry of known motifs 42 | */ 43 | public static MotifDefinitionRegistry getMotifDefinitionRegistry() { 44 | return INSTANCE.motifDefinitionRegistry; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/StrucmotifApplication.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import org.rcsb.strucmotif.core.MotifDefinitionRegistry; 4 | import org.rcsb.strucmotif.domain.query.StructureContextBuilder; 5 | import org.rcsb.strucmotif.domain.query.MotifContextBuilder; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; 10 | import org.springframework.boot.autoconfigure.domain.EntityScan; 11 | import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; 12 | 13 | /** 14 | * The entry point of the strucmotif-search application. 15 | */ 16 | @SpringBootApplication(exclude = { MongoAutoConfiguration.class, MongoDataAutoConfiguration.class }) 17 | @EntityScan("org.rcsb.strucmotif") 18 | public class StrucmotifApplication { 19 | static StructureContextBuilder structureContextBuilder; 20 | static MotifContextBuilder motifContextBuilder; 21 | static MotifDefinitionRegistry motifDefinitionRegistry; 22 | 23 | /** 24 | * Default entry point. 25 | * @param args arguments 26 | */ 27 | public static void main(String[] args) { 28 | SpringApplication.run(StrucmotifApplication.class, args); 29 | } 30 | 31 | /** 32 | * Constructor. 33 | * @param structureContextBuilder injectable context builder (1 motif -> n structures) 34 | * @param motifContextBuilder injectable context builder (1 structure -> n motifs) 35 | * @param motifDefinitionRegistry injectable motif definition registry (tracks all known motifs) 36 | */ 37 | @Autowired 38 | public StrucmotifApplication(StructureContextBuilder structureContextBuilder, MotifContextBuilder motifContextBuilder, MotifDefinitionRegistry motifDefinitionRegistry) { 39 | StrucmotifApplication.structureContextBuilder = structureContextBuilder; 40 | StrucmotifApplication.motifContextBuilder = motifContextBuilder; 41 | StrucmotifApplication.motifDefinitionRegistry = motifDefinitionRegistry; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/align/AlignmentService.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.align; 2 | 3 | import org.rcsb.strucmotif.domain.align.AlignmentResult; 4 | import org.rcsb.strucmotif.domain.align.AtomPairingScheme; 5 | import org.rcsb.strucmotif.domain.structure.LabelAtomId; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | /** 11 | * Superimpose sets of residues. 12 | */ 13 | public interface AlignmentService { 14 | /** 15 | * Aligns 2 sets of residues to one another. 16 | * @param reference the reference set of residues 17 | * @param candidate the candidate set of residues to evaluate 18 | * @param atomPairingScheme the atom names to consider for each residue during alignment 19 | * @return an Alignment instance which provides the aligned instances, transformation operations and scores 20 | */ 21 | AlignmentResult align(List> reference, List> candidate, AtomPairingScheme atomPairingScheme); 22 | } 23 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/AmbiguousMonomerStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * Controls how ambiguous amino acids such as GLX and ASX are handled. 5 | */ 6 | public enum AmbiguousMonomerStrategy { 7 | /** 8 | * Ignore and treat as unknown component, effectively disabling search. 9 | */ 10 | UNKNOWN_COMPONENT, 11 | /** 12 | * Treat as unknown type (maps GLX and ASX to the unknown amino acid). 13 | */ 14 | TYPE, 15 | /** 16 | * Treat as their amide equivalent (GLX -> GLN, ASX -> ASN). 17 | */ 18 | AMIDE, 19 | /** 20 | * Treat as their acid equivalent (GLX -> GLU, ASX -> ASP). 21 | */ 22 | ACID 23 | } 24 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/InMemoryStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * Keep structure data in memory? Requires ~30 GB of memory for 180k structures. 5 | */ 6 | public enum InMemoryStrategy { 7 | /** 8 | * Access file-system any time structure data is requested. 9 | */ 10 | OFF, 11 | /** 12 | * Load all data into heap during initialization. 13 | */ 14 | HEAP 15 | } 16 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/InvertedIndexBackend.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | import org.rcsb.strucmotif.io.codec.BucketCodec; 4 | import org.rcsb.strucmotif.io.codec.ColferCodec; 5 | import org.rcsb.strucmotif.io.codec.JsonCodec; 6 | 7 | /** 8 | * How to persist inverted index data? 9 | */ 10 | public enum InvertedIndexBackend { 11 | /** 12 | * Smaller files that are faster to read/write in a less standard format. 13 | */ 14 | COLFER(new ColferCodec(), ".colf"), 15 | /** 16 | * Useful for debugging. 17 | */ 18 | JSON(new JsonCodec(), ".json"); 19 | 20 | private final BucketCodec bucketCodec; 21 | private final String extension; 22 | 23 | InvertedIndexBackend(BucketCodec bucketCodec, String extension) { 24 | this.bucketCodec = bucketCodec; 25 | this.extension = extension; 26 | } 27 | 28 | /** 29 | * The implementation used by this backend. 30 | * @return a {@link BucketCodec} instance 31 | */ 32 | public BucketCodec getBucketCodec() { 33 | return bucketCodec; 34 | } 35 | 36 | /** 37 | * Reports the extension the index files have. 38 | * @return the extension associated with this backend 39 | */ 40 | public String getExtension() { 41 | return extension; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/MissingCategoryStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * How to handle missing categories in the source CIF file. 5 | */ 6 | public enum MissingCategoryStrategy { 7 | /** 8 | * Do nothing, use defaults (version will be 1.0, assembly will be "1"). 9 | */ 10 | IGNORE, 11 | /** 12 | * Warn with a console statement and use defaults (version will be 1.0, assembly will be "1"). 13 | */ 14 | WARN, 15 | /** 16 | * Fail the update if the category is absent. 17 | */ 18 | FAIL 19 | } 20 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/ModifiedResidueStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * How are modified residues indexed? 5 | */ 6 | public enum ModifiedResidueStrategy { 7 | /** 8 | * Ignore all non-standard polymeric components. 9 | */ 10 | NONE, 11 | /** 12 | * Map non-standard polymeric components to their parent component, according to the residue-type-mappings.json 13 | * file. This is a static, yet overridable variant of CCD_PARENT. 14 | */ 15 | INTERNAL, 16 | /** 17 | * Map non-standard polymeric components to their parent component, according to the chemical component dictionary. 18 | * This will read the CCD at initialization time. 19 | */ 20 | CCD_PARENT 21 | } 22 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/MotifPruningStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * How to simplify/prune motifs? 5 | */ 6 | public enum MotifPruningStrategy { 7 | /** 8 | * Minimal spanning tree, determined by Kruskal's algorithm. 9 | */ 10 | KRUSKAL, 11 | /** 12 | * Merely extract {@link org.rcsb.strucmotif.domain.motif.ResiduePairOccurrence}. 13 | */ 14 | NONE 15 | } 16 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/ReadErrorStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * Configures how read errors to the file bundles are handled. These seem to be caused by heavy load on the service. 5 | * Though the lack of exceptions leading up to the error might indicate that the root cause is bad concurrency. 6 | */ 7 | public enum ReadErrorStrategy { 8 | THROW, // throw exception at query level, ignore at service level 9 | EXIT, // terminate compromised service 10 | } 11 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/ResidueGraphStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | /** 4 | * Controls what residue pairs get detected. 5 | */ 6 | public enum ResidueGraphStrategy { 7 | /** 8 | * Only report contacts of deposited coordinates. 9 | */ 10 | DEPOSITED, 11 | /** 12 | * Reports contacts between deposited coordinates as well as all residues that are in contact with the deposited 13 | * chain(s). This is a superset of `DEPOSITED`. 14 | */ 15 | RESIDUES_IN_CONTACT, 16 | /** 17 | * Report contacts between deposited coordinates as well as all chains that are in contact with the deposited 18 | * chain(s). This is a superset of `RESIDUES_IN_CONTACT`. 19 | */ 20 | CHAINS_IN_CONTACT, 21 | /** 22 | * Index absolutely everything. 23 | */ 24 | ALL 25 | } 26 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/config/ResidueQualityStrategy.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.config; 2 | 3 | import java.util.function.BiPredicate; 4 | 5 | /** 6 | * Specify which residues to index and which to ignore. 7 | */ 8 | public enum ResidueQualityStrategy implements BiPredicate { 9 | /** 10 | * Index all residues. 11 | */ 12 | NONE((v, c) -> true), 13 | /** 14 | * Index only residues with a B-factor above the specified threshold. 15 | */ 16 | BFACTOR_ABOVE_CUTOFF((v, c) -> v > c), 17 | /** 18 | * Index only residues with a B-factor below the specified threshold. 19 | */ 20 | BFACTOR_BELOW_CUTOFF((v, c) -> v < c), 21 | /** 22 | * Index only residues with a B-factor above the specified threshold. 23 | */ 24 | QA_METRIC_LOCAL_ABOVE_CUTOFF((v, c) -> v > c), 25 | /** 26 | * Index only residues with a B-factor below the specified threshold. 27 | */ 28 | QA_METRIC_LOCAL_BELOW_CUTOFF((v, c) -> v < c); 29 | 30 | private final BiPredicate predicate; 31 | 32 | ResidueQualityStrategy(BiPredicate predicate) { 33 | this.predicate = predicate; 34 | } 35 | 36 | @Override 37 | public boolean test(Double value, Double cutoff) { 38 | return predicate.test(value, cutoff); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/HitScorer.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.align.AlignmentService; 4 | import org.rcsb.strucmotif.domain.align.AlignmentResult; 5 | import org.rcsb.strucmotif.domain.align.AtomPairingScheme; 6 | import org.rcsb.strucmotif.domain.structure.LabelAtomId; 7 | 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * Scores hits by computing the RMSD with respect to the reference motif. 13 | */ 14 | public class HitScorer { 15 | private final List> queryResidues; 16 | private final AtomPairingScheme atomPairingScheme; 17 | private final AlignmentService alignmentService; 18 | 19 | /** 20 | * Construct a query-specific hit scorer. 21 | * @param queryResidues the reference structure 22 | * @param atomPairingScheme how to pair atoms? 23 | * @param alignmentService alignment service 24 | */ 25 | public HitScorer(List> queryResidues, AtomPairingScheme atomPairingScheme, AlignmentService alignmentService) { 26 | this.queryResidues = queryResidues; 27 | this.atomPairingScheme = atomPairingScheme; 28 | this.alignmentService = alignmentService; 29 | } 30 | 31 | /** 32 | * Returns the used atom pairing scheme (e.g., all-atoms, side-chain, ...) 33 | * @return an {@link AtomPairingScheme} value 34 | */ 35 | public AtomPairingScheme getAtomPairingScheme() { 36 | return atomPairingScheme; 37 | } 38 | 39 | /** 40 | * The collection of residues that potential hits are aligned to. 41 | * @return all manifested residues of the query motif 42 | */ 43 | public List> getQueryResidues() { 44 | return queryResidues; 45 | } 46 | 47 | /** 48 | * Align a set of residues to the reference. 49 | * @param targetResidues collection of residues 50 | * @return an {@link AlignmentResult} 51 | */ 52 | public AlignmentResult alignToReference(List> targetResidues) { 53 | return alignmentService.align(queryResidues, targetResidues, atomPairingScheme); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/IllegalQueryDefinitionException.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.config.StrucmotifConfig; 4 | 5 | /** 6 | * Indicates invalid query definitions. May be caused by residue pairs exceeding the distance cutoff 7 | * ({@link StrucmotifConfig#getDistanceCutoff()}) or erroneous selections (like a mix-up of label_seq_id and 8 | * auth_seq_id). 9 | */ 10 | public class IllegalQueryDefinitionException extends IllegalArgumentException { 11 | /** 12 | * Default constructor. 13 | */ 14 | public IllegalQueryDefinitionException() { 15 | } 16 | 17 | /** 18 | * Construct with message. 19 | * @param s message 20 | */ 21 | public IllegalQueryDefinitionException(String s) { 22 | super(s); 23 | } 24 | 25 | /** 26 | * Construct with message and cause. 27 | * @param message message 28 | * @param cause the cause 29 | */ 30 | public IllegalQueryDefinitionException(String message, Throwable cause) { 31 | super(message, cause); 32 | } 33 | 34 | /** 35 | * Construct with cause. 36 | * @param cause the cause 37 | */ 38 | public IllegalQueryDefinitionException(Throwable cause) { 39 | super(cause); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/KruskalMotifPruner.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.motif.ResiduePairOccurrence; 4 | import org.rcsb.strucmotif.domain.structure.ResidueGraph; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.util.*; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * A motif may be best described by the minimal spanning tree which connects all vertices in the most compact fashion. 12 | * Uses Kruskal's algorithm to determine tree. 13 | */ 14 | @Service 15 | public class KruskalMotifPruner implements MotifPruner { 16 | /** 17 | * Default constructor. 18 | */ 19 | public KruskalMotifPruner() { 20 | } 21 | 22 | @Override 23 | public List prune(ResidueGraph residueGraph) { 24 | List original = residueGraph.residuePairOccurrencesSequential().collect(Collectors.toList()); 25 | List sorted = ResiduePairOccurrence.sort(original); 26 | 27 | // ignore motifs with <4 identifiers 28 | if (residueGraph.getResidueCount() < 4) { 29 | return sorted; 30 | } 31 | 32 | return kruskal(sorted); 33 | } 34 | 35 | private List kruskal(List residuePairOccurrences) { 36 | List> coveredSelectors = new ArrayList<>(); 37 | List result = new ArrayList<>(); 38 | 39 | while (!residuePairOccurrences.isEmpty()) { 40 | ResiduePairOccurrence best = residuePairOccurrences.remove(0); 41 | int id1 = best.getResidueIndex1(); 42 | int id2 = best.getResidueIndex2(); 43 | 44 | // prevent formation of circles 45 | Set set1 = find(coveredSelectors, id1); 46 | Set set2 = find(coveredSelectors, id2); 47 | if (set1 == null || !set1.equals(set2)) { 48 | result.add(best); 49 | 50 | Set updated = new LinkedHashSet<>(); 51 | if (set1 != null) { 52 | coveredSelectors.remove(set1); 53 | updated.addAll(set1); 54 | } 55 | if (set2 != null) { 56 | coveredSelectors.remove(set2); 57 | updated.addAll(set2); 58 | } 59 | updated.add(id1); 60 | updated.add(id2); 61 | coveredSelectors.add(updated); 62 | } 63 | } 64 | 65 | return result; 66 | } 67 | 68 | private Set find(List> selectors, Integer selector) { 69 | return selectors.stream() 70 | .filter(list -> list.contains(selector)) 71 | .findFirst() 72 | .orElse(null); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/MotifDefinitionRegistry.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.motif.EnrichedMotifDefinition; 4 | import org.rcsb.strucmotif.domain.motif.MotifDefinition; 5 | 6 | import java.io.InputStream; 7 | import java.util.Collection; 8 | import java.util.Set; 9 | import java.util.function.Function; 10 | import java.util.function.Predicate; 11 | 12 | /** 13 | * Global store of known motifs. This loads a hard-coded collection of motifs as well as will screen for a file called 14 | * 'motifs.json' located on the classpath. Additionally, you can manually register, or deregister, motifs. The service 15 | * keeps track of the global state of registered motifs. It also has the ability to enrich motifs with structure data. 16 | */ 17 | public interface MotifDefinitionRegistry { 18 | /** 19 | * Parse motif definitions from a file/string/URL. 20 | * @param inputStream stream of a JSON file 21 | * @return if content changed 22 | */ 23 | boolean parseAndAddMotifDefinitions(InputStream inputStream); 24 | 25 | /** 26 | * Register a motif. 27 | * @param motifDefinition what to add 28 | * @return true if content changed 29 | */ 30 | boolean addMotifDefinition(MotifDefinition motifDefinition); 31 | 32 | /** 33 | * Register multiple motifs. 34 | * @param motifDefinitions what to add 35 | * @return true if content changed 36 | */ 37 | boolean addMotifDefinitions(Collection motifDefinitions); 38 | 39 | /** 40 | * Remove a motif. 41 | * @param motifDefinition what to remove 42 | * @return true if content changed 43 | */ 44 | boolean removeMotifDefinition(MotifDefinition motifDefinition); 45 | 46 | /** 47 | * Remove multiple motifs. 48 | * @param motifDefinitions what to remove 49 | * @return true if content changed 50 | */ 51 | boolean removeMotifDefinitions(Collection motifDefinitions); 52 | 53 | /** 54 | * Conditionally remove. 55 | * @param predicate condition for removal 56 | * @return true if content changed 57 | */ 58 | boolean removeMotifDefinitions(Predicate predicate); 59 | 60 | /** 61 | * All registered motif definitions. 62 | * @return a collection of motif definitions 63 | */ 64 | Set getMotifDefinitions(); 65 | 66 | /** 67 | * Number of registered motifs. 68 | * @return an int 69 | */ 70 | int size(); 71 | 72 | /** 73 | * Access to all 'enriched' representation (i.e. with all necessary structure data) of all known motifs. Defaults to 74 | * loading data from local or public resources. Use {@link #enrichMotifDefinitions(Function mapper)} for motifs 75 | * from non-archived structures. 76 | * @return collection of motifs with resolved structure data 77 | */ 78 | Set getEnrichedMotifDefinitions(); 79 | 80 | /** 81 | * Specify how 'enriched' representation (i.e. with all necessary structure data) are created. 82 | * @param mapper the function to obtain structure data 83 | * @return collection motif motifs with resolved structure data 84 | */ 85 | Set enrichMotifDefinitions(Function mapper); 86 | 87 | /** 88 | * The default enricher that attaches structure data to motif definitions. This is done by loading local or remote 89 | * structure data. For structure without structure data in the usual places use 90 | * {@link #enrichMotifDefinitions(Function) enrichMotifDefinitions} and provide an appropriate implementation. 91 | * @return the default enricher 92 | */ 93 | Function getDefaultEnricher(); 94 | } 95 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/MotifPruner.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.motif.ResiduePairOccurrence; 4 | import org.rcsb.strucmotif.domain.structure.ResidueGraph; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Pruning motifs is advantageous as it saves time (fewer lookups) and avoids too rigid criteria enforced during search. 10 | */ 11 | public interface MotifPruner { 12 | /** 13 | * Perform pruning operation (e.g. extract all {@link ResiduePairOccurrence} instances from a structure and prune 14 | * the resulting graph). 15 | * @param residueGraph the graph to operate on 16 | * @return the list of occurrences which describe this structure 17 | */ 18 | List prune(ResidueGraph residueGraph); 19 | } 20 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/NoOperationMotifPruner.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.motif.ResiduePairOccurrence; 4 | import org.rcsb.strucmotif.domain.structure.ResidueGraph; 5 | import org.springframework.stereotype.Service; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * Don't prune query motif. Merely extract all {@link ResiduePairOccurrence} instances. 12 | */ 13 | @Service 14 | public class NoOperationMotifPruner implements MotifPruner { 15 | /** 16 | * Default constructor. 17 | */ 18 | public NoOperationMotifPruner() { 19 | } 20 | 21 | @Override 22 | public List prune(ResidueGraph residueGraph) { 23 | List original = residueGraph.residuePairOccurrencesSequential().collect(Collectors.toList()); 24 | return ResiduePairOccurrence.sort(original); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/QueryExecutionException.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | /** 4 | * Akin to "internal server error". 5 | */ 6 | public class QueryExecutionException extends RuntimeException { 7 | /** 8 | * Default constructor. 9 | */ 10 | public QueryExecutionException() { 11 | } 12 | 13 | /** 14 | * Construct with message. 15 | * @param message msg 16 | */ 17 | public QueryExecutionException(String message) { 18 | super(message); 19 | } 20 | 21 | /** 22 | * Construct with message and cause. 23 | * @param message msg 24 | * @param cause root cause 25 | */ 26 | public QueryExecutionException(String message, Throwable cause) { 27 | super(message, cause); 28 | } 29 | 30 | /** 31 | * Construct with cause. 32 | * @param cause root cause 33 | */ 34 | public QueryExecutionException(Throwable cause) { 35 | super(cause); 36 | } 37 | 38 | /** 39 | * Construct with a bunch of info. 40 | * @param message msg 41 | * @param cause root cause 42 | * @param enableSuppression whether suppression is enabled or disabled 43 | * @param writableStackTrace whether the stack trace should be writable 44 | */ 45 | public QueryExecutionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 46 | super(message, cause, enableSuppression, writableStackTrace); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/QueryTimeoutException.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | /** 4 | * Reports that a query was terminated because it timed out. 5 | */ 6 | public class QueryTimeoutException extends RuntimeException { 7 | /** 8 | * Default constructor. 9 | */ 10 | public QueryTimeoutException() { 11 | } 12 | 13 | /** 14 | * Construct with a detailed message. 15 | * @param message msg 16 | */ 17 | public QueryTimeoutException(String message) { 18 | super(message); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/StrucmotifRuntime.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.StructureSearchContext; 4 | import org.rcsb.strucmotif.domain.MotifSearchContext; 5 | import org.rcsb.strucmotif.domain.result.StructureHit; 6 | import org.rcsb.strucmotif.domain.result.MotifHit; 7 | 8 | import java.util.function.Consumer; 9 | 10 | /** 11 | * Performs motif search queries and returns the corresponding result object. 12 | */ 13 | public interface StrucmotifRuntime { 14 | /** 15 | * Perform a structure search. 16 | * @param context a structure context 17 | */ 18 | void performSearch(StructureSearchContext context); 19 | 20 | /** 21 | * Perform a structure search and consume results 'inline'. 22 | * @param context a structure context 23 | * @param consumer consumer of structure hits 24 | */ 25 | void performSearch(StructureSearchContext context, Consumer consumer); 26 | 27 | /** 28 | * Perform a structure search. 29 | * @param context a motif context 30 | */ 31 | void performSearch(MotifSearchContext context); 32 | 33 | /** 34 | * Perform a motif search and consume results 'inline'. 35 | * @param context a motif context 36 | * @param consumer consumer of motif hits 37 | */ 38 | void performSearch(MotifSearchContext context, Consumer consumer); 39 | } 40 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/core/TargetAssembler.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.rcsb.strucmotif.domain.StructureSearchContext; 4 | 5 | /** 6 | * Where the magic happens. Lookup all word occurrences which need to be fulfilled and combine them in the most 7 | * efficient way. 8 | *

Assembles the set of target structures to evaluate by focusing on the paths through targets. Basically, this is 9 | * subgraph isomorphism: the query is a graph, and we want to find all target structures which contain this query as a 10 | * subgraph. 11 | */ 12 | public interface TargetAssembler { 13 | /** 14 | * Search: i.e. find all paths through all target structures which reasonably resemble the structure of the query 15 | * motif. 16 | * @param context the container to work on 17 | */ 18 | void assemble(StructureSearchContext context); 19 | } 20 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/Pair.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain; 2 | 3 | /** 4 | * Defines a relation between 2 objects. 5 | * @param first 1st element 6 | * @param second 2nd element 7 | * @param the first type 8 | * @param the second type 9 | */ 10 | public record Pair(F first, S second) { 11 | @Override 12 | public String toString() { 13 | return first + " - " + second; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/align/AlignmentResult.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.align; 2 | 3 | /** 4 | * The result of an alignment. 5 | * @param transformation the transformation determined by the alignment 6 | * @param rmsd the alignment score 7 | */ 8 | public record AlignmentResult(float[] transformation, float rmsd) {} 9 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/align/AtomPairingScheme.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.align; 2 | 3 | import org.rcsb.strucmotif.domain.structure.LabelAtomId; 4 | 5 | import java.util.function.Predicate; 6 | 7 | /** 8 | * Schemes on which atoms (by name) to use to align residues. Each entry is actually a {@link Predicate} which tests 9 | * atom names and returns true if fall into that particular scheme. 10 | */ 11 | public enum AtomPairingScheme implements Predicate { 12 | /** 13 | * Use everything. 14 | */ 15 | ALL(s -> true), 16 | /** 17 | * Use alpha carbons only. 18 | */ 19 | ALPHA_CARBON(s -> s.equals(LabelAtomId.CA) || 20 | s.equals(LabelAtomId.C4_PRIME)), 21 | /** 22 | * Use beta carbons only. 23 | */ 24 | BETA_CARBON(s -> s.equals(LabelAtomId.CB) || 25 | s.equals(LabelAtomId.C1_PRIME)), 26 | /** 27 | * Use backbone atoms only. 28 | */ 29 | BACKBONE(s -> s.equals(LabelAtomId.N) || s.equals(LabelAtomId.CA) || s.equals(LabelAtomId.C) || 30 | s.equals(LabelAtomId.O) || s.equals(LabelAtomId.P) || s.equals(LabelAtomId.OP1) || 31 | s.equals(LabelAtomId.OP2) || s.equals(LabelAtomId.C2_PRIME) || s.equals(LabelAtomId.C3_PRIME) || 32 | s.equals(LabelAtomId.O3_PRIME) || s.equals(LabelAtomId.C4_PRIME) || s.equals(LabelAtomId.O4_PRIME) || 33 | s.equals(LabelAtomId.C5_PRIME) || s.equals(LabelAtomId.O5_PRIME)), 34 | /** 35 | * Use side-chain atoms only. 36 | */ 37 | SIDE_CHAIN(BACKBONE.predicate.negate()), 38 | /** 39 | * Use pseudo-atoms defined by {@link org.rcsb.strucmotif.domain.motif.ResiduePairDescriptor}. 40 | */ 41 | PSEUDO_ATOMS(s -> s.equals(LabelAtomId.CA) || s.equals(LabelAtomId.CB) || 42 | s.equals(LabelAtomId.C4_PRIME) || s.equals(LabelAtomId.C1_PRIME)); 43 | 44 | private final Predicate predicate; 45 | 46 | AtomPairingScheme(Predicate predicate) { 47 | this.predicate = predicate; 48 | } 49 | 50 | @Override 51 | public boolean test(LabelAtomId s) { 52 | return predicate.test(s); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/bucket/Bucket.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.bucket; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * Represents a single file of the inverted index (e.g., AL-4-5-4). This file keeps track of all structures that contain 7 | * occurrences of the corresponding descriptor. 8 | */ 9 | public interface Bucket { 10 | /** 11 | * All structures that contain occurrences of this descriptor. 12 | * @return a collection of structure indices 13 | */ 14 | Set getStructureIndices(); 15 | 16 | /** 17 | * True if there is another structure after the current one. 18 | * @return a boolean 19 | */ 20 | boolean hasNextStructure(); 21 | 22 | /** 23 | * True if there is another occurrence after the current one. 24 | * @return a boolean 25 | */ 26 | boolean hasNextOccurrence(); 27 | 28 | /** 29 | * Advance to the next structure, only safe if {@link #hasNextStructure()} is true. 30 | */ 31 | void moveStructure(); 32 | 33 | /** 34 | * Advance to the next structure, only safe if {@link #hasNextOccurrence()} is true. 35 | */ 36 | void moveOccurrence(); 37 | 38 | /** 39 | * The number of structures that contain this descriptor. 40 | * @return an int 41 | */ 42 | int getStructureCount(); 43 | 44 | /** 45 | * The total number of residue pairs registered in this bucket. 46 | * @return an int 47 | */ 48 | int getResiduePairCount(); 49 | 50 | /** 51 | * The current structure index. 52 | * @return a structure index 53 | */ 54 | int getStructureIndex(); 55 | 56 | /** 57 | * Convenience method that gives access to the current identifier represented by 2 ints. 58 | * @return the current residue indices 59 | */ 60 | long getResiduePairIdentifier(); 61 | 62 | /** 63 | * Move iterators back to start positions. 64 | */ 65 | void reset(); 66 | 67 | /** 68 | * Get the current occurrence start position associated with the current position pointer. 69 | * @return an int 70 | */ 71 | int getStartPosition(); 72 | 73 | /** 74 | * Get the current occurrence end position associated with the current position pointer. 75 | * @return an int 76 | */ 77 | int getEndPosition(); 78 | } 79 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/motif/AngleType.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | import org.rcsb.strucmotif.math.Algebra; 4 | 5 | /** 6 | * Binned representation of the angle between residues. 7 | */ 8 | public enum AngleType { 9 | /** 10 | * [0, 10) deg. 11 | */ 12 | A0, 13 | /** 14 | * [10, 30) deg. 15 | */ 16 | A20, 17 | /** 18 | * [30, 50) deg. 19 | */ 20 | A40, 21 | /** 22 | * [50, 70) deg. 23 | */ 24 | A60, 25 | /** 26 | * [70, 90) deg. 27 | */ 28 | A80, 29 | /** 30 | * [90, 110) deg. 31 | */ 32 | A100, 33 | /** 34 | * [110, 130) deg. 35 | */ 36 | A120, 37 | /** 38 | * [130, 150) deg. 39 | */ 40 | A140, 41 | /** 42 | * [150, 170) deg. 43 | */ 44 | A160, 45 | /** 46 | * [170, 180] 47 | */ 48 | A180; 49 | 50 | /** 51 | * Cached values of this enum. Don't manipulate this array or things will burn. 52 | */ 53 | public static final AngleType[] values = values(); 54 | 55 | /** 56 | * Width of an angle bin. 57 | */ 58 | public static final int BIN_SIZE = 20; 59 | 60 | /** 61 | * Convert enum to angle value in degree (basically the lower bound of the interval). 62 | * @return lower bound of angles landing in this bin 63 | */ 64 | public int getIntRepresentation() { 65 | return ordinal() * BIN_SIZE; 66 | } 67 | 68 | /** 69 | * Convert angle in degrees to enum value. Will cap results into interval of possible values. 70 | * @param angle raw value 71 | * @return the corresponding bin 72 | */ 73 | public static AngleType ofAngle(float angle) { 74 | int i = Math.round(angle / BIN_SIZE); 75 | if (i < 0) { 76 | return AngleType.A0; 77 | } else if (i >= values.length) { 78 | return AngleType.A180; 79 | } else { 80 | return values[i]; 81 | } 82 | } 83 | 84 | /** 85 | * Convert the ordinal to enum value. Somewhat trivial. Will cap results into interval of possible values. 86 | * @param ordinal the ordinal to get 87 | * @return the corresponding bin 88 | */ 89 | public static AngleType ofIntRepresentation(int ordinal) { 90 | return values[Algebra.capToInterval(0, ordinal, values.length)]; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/motif/DistanceType.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | import org.rcsb.strucmotif.math.Algebra; 4 | 5 | /** 6 | * Binned representation of the distance between residues. 7 | */ 8 | public enum DistanceType { 9 | /** 10 | * [0, 0.5) A. 11 | */ 12 | D0, 13 | /** 14 | * [0.5, 1.5) A. 15 | */ 16 | D1, 17 | /** 18 | * [1.5, 2.5) A. 19 | */ 20 | D2, 21 | /** 22 | * [2.5, 3.5) A. 23 | */ 24 | D3, 25 | /** 26 | * [3.5, 4.5) A. 27 | */ 28 | D4, 29 | /** 30 | * [4.5, 5.5) A. 31 | */ 32 | D5, 33 | /** 34 | * [5.5, 6.5) A. 35 | */ 36 | D6, 37 | /** 38 | * [6.5, 7.5) A. 39 | */ 40 | D7, 41 | /** 42 | * [7.5, 8.5) A. 43 | */ 44 | D8, 45 | /** 46 | * [8.5, 9.5) A. 47 | */ 48 | D9, 49 | /** 50 | * [9.5, 10.5) A. 51 | */ 52 | D10, 53 | /** 54 | * [10.5, 11.5) A. 55 | */ 56 | D11, 57 | /** 58 | * [11.5, 12.5) A. 59 | */ 60 | D12, 61 | /** 62 | * [12.5, 13.5) A. 63 | */ 64 | D13, 65 | /** 66 | * [13.5, 14.5) A. 67 | */ 68 | D14, 69 | /** 70 | * [14.5, 15.5) A. 71 | */ 72 | D15, 73 | /** 74 | * [15.5, 16.5) A. 75 | */ 76 | D16, 77 | /** 78 | * [16.5, 17.5) A. 79 | */ 80 | D17, 81 | /** 82 | * [17.5, 18.5) A. 83 | */ 84 | D18, 85 | /** 86 | * [18.5, 19.5) A. 87 | */ 88 | D19, 89 | /** 90 | * [19.5, 20.5) A. 91 | */ 92 | D20, 93 | /** 94 | * [20.5, 21.5) A. 95 | */ 96 | D21, 97 | /** 98 | * [21.5, 22.5) A. 99 | */ 100 | D22, 101 | /** 102 | * [22.5, 23.5) A. 103 | */ 104 | D23, 105 | /** 106 | * [23.5, 24.5) A. 107 | */ 108 | D24, 109 | /** 110 | * [24.5, 25.5) A. 111 | */ 112 | D25, 113 | /** 114 | * [25.5, 26.5) A. 115 | */ 116 | D26, 117 | /** 118 | * [26.5, 27.5) A. 119 | */ 120 | D27, 121 | /** 122 | * [27.5, 28.5) A. 123 | */ 124 | D28, 125 | /** 126 | * [28.5, 29.5) A. 127 | */ 128 | D29, 129 | /** 130 | * [29.5, 30.5) A. 131 | */ 132 | D30, 133 | /** 134 | * [30.5, 31.5) A. 135 | */ 136 | D31; // this is the hard-limit for the distance between pairs 137 | 138 | /** 139 | * Cached values of this enum. Don't manipulate this array or things will burn. 140 | */ 141 | public static final DistanceType[] values = values(); 142 | 143 | /** 144 | * Width of a distance bin. 145 | */ 146 | public static final int BIN_SIZE = 1; 147 | 148 | /** 149 | * Convert enum to distance value in Angstrom (basically the lower bound of the interval). 150 | * @return lower bound of distances landing in this bin 151 | */ 152 | public int getIntRepresentation() { 153 | return ordinal() * BIN_SIZE; 154 | } 155 | 156 | /** 157 | * Convert distance in Angstrom to enum value. Will cap results into interval of possible values. 158 | * @param distance raw distance 159 | * @return the corresponding bin 160 | */ 161 | public static DistanceType ofDistance(float distance) { 162 | int i = Math.round(distance / BIN_SIZE); 163 | if (i < 0) { 164 | return DistanceType.D0; 165 | } else if (i >= values.length) { 166 | return DistanceType.D31; 167 | } else { 168 | return values[i]; 169 | } 170 | } 171 | 172 | /** 173 | * Convert the ordinal to enum value. Somewhat trivial. Will cap results into interval of possible values. 174 | * @param ordinal the ordinal to get 175 | * @return the corresponding bin 176 | */ 177 | public static DistanceType ofIntRepresentation(int ordinal) { 178 | return values[Algebra.capToInterval(0, ordinal, values.length)]; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/motif/EnrichedMotifDefinition.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | import org.rcsb.strucmotif.domain.structure.LabelAtomId; 4 | import org.rcsb.strucmotif.domain.structure.Structure; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Objects; 9 | 10 | /** 11 | * Enriched motif definitions wrap a {@link MotifDefinition} and provide additionally access to the underlying 12 | * {@link Structure} as well as referenced residues. 13 | */ 14 | public class EnrichedMotifDefinition extends MotifDefinition { 15 | private final Structure structure; 16 | private final List> residues; 17 | 18 | /** 19 | * Construct a enriched motif. 20 | * @param motifDefinition original definition 21 | * @param structure underlying structure 22 | * @param residues all relevant residues 23 | */ 24 | public EnrichedMotifDefinition(MotifDefinition motifDefinition, Structure structure, List> residues) { 25 | super(motifDefinition.getMotifIdentifier(), motifDefinition.getStructureIdentifier(), motifDefinition.getTitle(), motifDefinition.getDescription(), motifDefinition.getLabelSelections(), motifDefinition.getPositionSpecificExchanges()); 26 | this.structure = structure; 27 | this.residues = residues; 28 | } 29 | 30 | /** 31 | * Access to the structure object. 32 | * @return a {@link Structure} 33 | */ 34 | public Structure getStructure() { 35 | return structure; 36 | } 37 | 38 | /** 39 | * All relevant residues. 40 | * @return a collection of maps from atom names to 3D vectors 41 | */ 42 | public List> getResidues() { 43 | return residues; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object o) { 48 | if (this == o) return true; 49 | if (o == null || getClass() != o.getClass()) return false; 50 | if (!super.equals(o)) return false; 51 | EnrichedMotifDefinition that = (EnrichedMotifDefinition) o; 52 | return Objects.equals(structure, that.structure) && Objects.equals(residues, that.residues); 53 | } 54 | 55 | @Override 56 | public int hashCode() { 57 | return Objects.hash(super.hashCode(), structure, residues); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/motif/Overlap.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | /** 4 | * Can be no overlap or both overlapping. Interesting case is when 1 pair overlaps. Can be LEFT_LEFT (left/first 5 | * identifier of first word paired to left/first of second word) and so on. 6 | */ 7 | public enum Overlap { 8 | /** 9 | * No overlap. 10 | */ 11 | NONE, 12 | /** 13 | * Left identifier of first word corresponds to left identifier of second word. 14 | */ 15 | LEFT_LEFT, 16 | /** 17 | * Left identifier of first word corresponds to right identifier of second word. 18 | */ 19 | LEFT_RIGHT, 20 | /** 21 | * Right identifier of first word corresponds to left identifier of second word. 22 | */ 23 | RIGHT_LEFT, 24 | /** 25 | * Right identifier of first word corresponds to right identifier of second word. 26 | */ 27 | RIGHT_RIGHT, 28 | /** 29 | * The degenerate case where both sides are referencing the same residues. 30 | */ 31 | BOTH; 32 | 33 | /** 34 | * Determines the overlap between 2 residue pair identifiers. 35 | * @param r11 1st index of 1st identifier 36 | * @param r12 2nd index of 1st identifier 37 | * @param r21 1st index of 2nd identifier 38 | * @param r22 2nd index of 2nd identifier 39 | * @return a description of the observed overlap 40 | */ 41 | public static Overlap ofResiduePairIdentifiers(int r11, int r12, int r21, int r22) { 42 | boolean equal1112 = r11 == r21; 43 | boolean equal1122 = r11 == r22; 44 | boolean equal1221 = r12 == r21; 45 | boolean equal1222 = r12 == r22; 46 | return of(equal1112, equal1122, equal1221, equal1222); 47 | } 48 | 49 | /** 50 | * Determines the overlap between 2 residue pair identifiers. 51 | * @param r1 1st identifier 52 | * @param r2 2nd identifier 53 | * @return a description of the observed overlap 54 | */ 55 | public static Overlap ofResiduePairIdentifiers(long r1, long r2) { 56 | int r11 = ResiduePairIdentifier.getResidueIndex1(r1); 57 | int r12 = ResiduePairIdentifier.getResidueIndex2(r1); 58 | int r21 = ResiduePairIdentifier.getResidueIndex1(r2); 59 | int r22 = ResiduePairIdentifier.getResidueIndex2(r2); 60 | boolean equal1112 = r11 == r21; 61 | boolean equal1122 = r11 == r22; 62 | boolean equal1221 = r12 == r21; 63 | boolean equal1222 = r12 == r22; 64 | return of(equal1112, equal1122, equal1221, equal1222); 65 | } 66 | 67 | private static Overlap of(boolean equal1112, boolean equal1122, boolean equal1221, boolean equal1222) { 68 | if (!equal1112 && !equal1122 && !equal1221 && !equal1222) { 69 | return NONE; 70 | } else if ((equal1112 && equal1222) || (equal1122 && equal1221)) { 71 | return BOTH; 72 | } else if (equal1112) { 73 | return LEFT_LEFT; 74 | } else if (equal1222) { 75 | return RIGHT_RIGHT; 76 | } else if (equal1122) { 77 | return LEFT_RIGHT; 78 | } else { 79 | return RIGHT_LEFT; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/motif/ResiduePairIdentifier.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | /** 4 | * A residue pair descriptor is a long that combines 2 residue indices. The upper 32 bit (A) are the 1st value, the 5 | * lower 32 bit (B) contain the 2nd value. 6 | * 7 | *

AAAAAAAA AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB BBBBBBBB BBBBBBBB BBBBBBBB
8 | */ 9 | public class ResiduePairIdentifier { 10 | private ResiduePairIdentifier() { 11 | // deny 12 | } 13 | 14 | /** 15 | * Encode (residueIndex1, residueIndex2) as long. 16 | * @param residueIndex1 1st index 17 | * @param residueIndex2 2nd index 18 | * @return both represented as a single long 19 | */ 20 | public static long encodeIdentifier(int residueIndex1, int residueIndex2) { 21 | return (long) residueIndex1 << 32 | residueIndex2; 22 | } 23 | 24 | /** 25 | * Extract the 1st index from a long identifier. 26 | * @param residuePairIdentifier long 27 | * @return 1st index as int 28 | */ 29 | public static int getResidueIndex1(long residuePairIdentifier) { 30 | return (int) (residuePairIdentifier >>> 32); 31 | } 32 | 33 | /** 34 | * Extract the 2nd index from a long identifier. 35 | * @param residuePairIdentifier long 36 | * @return 2nd index as int 37 | */ 38 | public static int getResidueIndex2(long residuePairIdentifier) { 39 | return (int) residuePairIdentifier; 40 | } 41 | 42 | /** 43 | * Pretty-print a long identifier. 44 | * @param residuePairIdentifier long 45 | * @return human-readable String 46 | */ 47 | public static String toString(long residuePairIdentifier) { 48 | return getResidueIndex1(residuePairIdentifier) + "-" + getResidueIndex2(residuePairIdentifier); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/ContextBuilder.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.config.MotifPruningStrategy; 4 | import org.rcsb.strucmotif.core.MotifPruner; 5 | import org.rcsb.strucmotif.domain.SearchContext; 6 | import org.rcsb.strucmotif.domain.align.AtomPairingScheme; 7 | 8 | /** 9 | * Step-wise builder of the search context. 10 | */ 11 | public interface ContextBuilder { 12 | /** 13 | * Parameters are considered mandatory arguments (in the sense that some value has to be given - nonetheless, 14 | * default values will be used). But internally these values are strictly required. No input validation is performed 15 | * whatsoever. 16 | * @param type of the context to create 17 | */ 18 | interface MandatoryBuilder> { 19 | /** 20 | * Specify the backbone distance tolerance (default: 1). 21 | * @param backboneDistanceTolerance an int 22 | * @return this builder 23 | */ 24 | MandatoryBuilder backboneDistanceTolerance(int backboneDistanceTolerance); 25 | 26 | /** 27 | * Specify the side-chain distance tolerance (default: 1). 28 | * @param sideChainDistanceTolerance an int 29 | * @return this builder 30 | */ 31 | MandatoryBuilder sideChainDistanceTolerance(int sideChainDistanceTolerance); 32 | 33 | /** 34 | * Specify the angle tolerance (default: 1). 35 | * @param angleTolerance an int 36 | * @return this builder 37 | */ 38 | MandatoryBuilder angleTolerance(int angleTolerance); 39 | 40 | /** 41 | * Filter hits based on RMSD. 42 | * @param rmsdCutoff the RMSD cutoff above which hits are filtered 43 | * @return this builder 44 | */ 45 | MandatoryBuilder rmsdCutoff(double rmsdCutoff); 46 | 47 | /** 48 | * Controls which atoms will be considered for alignment. Only relevant when scoring scheme is alignment-based. 49 | * @param atomPairingScheme how to pair atoms for alignment routine 50 | * @return this builder 51 | */ 52 | MandatoryBuilder atomPairingScheme(AtomPairingScheme atomPairingScheme); 53 | 54 | /** 55 | * Specify the motif pruning strategy. 56 | * @param motifPruner the implementation to prune motifs 57 | * @return this builder 58 | */ 59 | MandatoryBuilder motifPruningStrategy(MotifPruner motifPruner); 60 | 61 | /** 62 | * Specify the motif pruning strategy. 63 | * @param motifPruningStrategy the strategy to prune motifs 64 | * @return this builder 65 | */ 66 | MandatoryBuilder motifPruningStrategy(MotifPruningStrategy motifPruningStrategy); 67 | 68 | /** 69 | * Timeout after this many milliseconds by throwing a {@link java.util.concurrent.TimeoutException}. Set to 70 | * Integer.MAX_VALUE to not enforce any timeout. 71 | * @param ms the timeout in ms 72 | * @return this builder 73 | */ 74 | MandatoryBuilder timeout(int ms); 75 | 76 | /** 77 | * Create the parameter object and move on to the optional step. 78 | * @return the optional builder instance 79 | */ 80 | OptionalBuilder buildParameters(); 81 | } 82 | 83 | /** 84 | * Optional values. 85 | * @param type of the context to create 86 | */ 87 | interface OptionalBuilder> { 88 | /** 89 | * Create the context. 90 | * @return a context 91 | */ 92 | C buildContext(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/MotifParameters.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.core.MotifPruner; 4 | import org.rcsb.strucmotif.domain.align.AtomPairingScheme; 5 | 6 | /** 7 | * Parameters of a 'detect-motifs' run. 8 | */ 9 | public class MotifParameters implements Parameters { 10 | private final int backboneDistanceTolerance; 11 | private final int sideChainDistanceTolerance; 12 | private final int angleTolerance; 13 | private final float rmsdCutoff; 14 | private final AtomPairingScheme atomPairingScheme; 15 | private final MotifPruner motifPruner; 16 | private final int timeout; 17 | 18 | /** 19 | * Construct motif parameters. 20 | * @param backboneDistanceTolerance backbone tolerance 21 | * @param sideChainDistanceTolerance side-chain tolerance 22 | * @param angleTolerance angle tolerance 23 | * @param rmsdCutoff maximum RMSD 24 | * @param atomPairingScheme how to pair atoms 25 | * @param motifPruner how to prune motifs 26 | * @param timeout timeout in ms 27 | */ 28 | public MotifParameters(int backboneDistanceTolerance, int sideChainDistanceTolerance, int angleTolerance, float rmsdCutoff, AtomPairingScheme atomPairingScheme, MotifPruner motifPruner, int timeout) { 29 | this.backboneDistanceTolerance = backboneDistanceTolerance; 30 | this.sideChainDistanceTolerance = sideChainDistanceTolerance; 31 | this.angleTolerance = angleTolerance; 32 | this.rmsdCutoff = rmsdCutoff; 33 | this.atomPairingScheme = atomPairingScheme; 34 | this.motifPruner = motifPruner; 35 | this.timeout = timeout; 36 | } 37 | 38 | /** 39 | * Employed backbone distance tolerance. 40 | * @return an int 41 | */ 42 | public int getBackboneDistanceTolerance() { 43 | return backboneDistanceTolerance; 44 | } 45 | 46 | /** 47 | * Employed side-chain distance tolerance. 48 | * @return an int 49 | */ 50 | public int getSideChainDistanceTolerance() { 51 | return sideChainDistanceTolerance; 52 | } 53 | 54 | /** 55 | * Employed angle tolerance. 56 | * @return an int 57 | */ 58 | public int getAngleTolerance() { 59 | return angleTolerance; 60 | } 61 | 62 | /** 63 | * Maximum RMSD up to which hits will be accepted, can be 'infinite'. 64 | * @return a float 65 | */ 66 | public float getRmsdCutoff() { 67 | return rmsdCutoff; 68 | } 69 | 70 | /** 71 | * If filtering by RMSD will happen. 72 | * @return true if there's a cutoff 73 | */ 74 | public boolean hasRmsdCutoff() { 75 | return rmsdCutoff != Float.MAX_VALUE; 76 | } 77 | 78 | /** 79 | * Which atoms will get aligned. 80 | * @return an {@link AtomPairingScheme} 81 | */ 82 | public AtomPairingScheme getAtomPairingScheme() { 83 | return atomPairingScheme; 84 | } 85 | 86 | /** 87 | * The associated motif pruning strategy. 88 | * @return a {@link MotifPruner} 89 | */ 90 | public MotifPruner getMotifPruner() { 91 | return motifPruner; 92 | } 93 | 94 | @Override 95 | public int getTimeout() { 96 | return timeout; 97 | } 98 | 99 | @Override 100 | public boolean hasTimeout() { 101 | return timeout != Integer.MAX_VALUE; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/MotifQuery.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.domain.motif.EnrichedMotifDefinition; 4 | import org.rcsb.strucmotif.domain.structure.Structure; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * The immutable container for a structural motif query. 10 | */ 11 | public class MotifQuery implements SearchQuery { 12 | private final MotifQueryStructure queryStructure; 13 | private final Set motifDefinitions; 14 | private final MotifParameters parameters; 15 | 16 | /** 17 | * Construct a motif search query. 18 | * @param structureIdentifier the referenced structure 19 | * @param structure structure data 20 | * @param motifDefinitions the motifs to consider 21 | * @param parameters query parameters 22 | */ 23 | public MotifQuery(String structureIdentifier, 24 | Structure structure, 25 | Set motifDefinitions, 26 | MotifParameters parameters) { 27 | this.queryStructure = new MotifQueryStructure(structureIdentifier, structure); 28 | this.motifDefinitions = motifDefinitions; 29 | this.parameters = parameters; 30 | } 31 | 32 | /** 33 | * The structure used to define this query/motif. 34 | * @return a dedicated implementation wrapping a structure instance 35 | */ 36 | @Override 37 | public MotifQueryStructure getQueryStructure() { 38 | return queryStructure; 39 | } 40 | 41 | /** 42 | * All associated motif definitions. 43 | * @return a collection of motifs 44 | */ 45 | public Set getMotifDefinitions() { 46 | return motifDefinitions; 47 | } 48 | 49 | /** 50 | * All parameters defined for this search task. 51 | * @return a parameter instance 52 | */ 53 | @Override 54 | public MotifParameters getParameters() { 55 | return parameters; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/MotifQueryStructure.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.domain.structure.Structure; 4 | 5 | /** 6 | * A query structure when searching for motifs. 7 | */ 8 | public class MotifQueryStructure implements QueryStructure { 9 | private final String structureIdentifier; 10 | private final Structure structure; 11 | 12 | /** 13 | * Construct a motif query structure. 14 | * @param structureIdentifier the identifier 15 | * @param structure the structure 16 | */ 17 | public MotifQueryStructure(String structureIdentifier, Structure structure) { 18 | this.structureIdentifier = structureIdentifier; 19 | this.structure = structure; 20 | } 21 | 22 | /** 23 | * Get the identifier of this query structure. 24 | * 25 | * @return a String 26 | */ 27 | @Override 28 | public String getStructureIdentifier() { 29 | return structureIdentifier; 30 | } 31 | 32 | /** 33 | * Delegate to wrapped structure. 34 | * 35 | * @return the structure instance 36 | */ 37 | @Override 38 | public Structure getStructure() { 39 | return structure; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/Parameters.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | /** 4 | * Parameters of a search run. 5 | */ 6 | public interface Parameters { 7 | /** 8 | * Default tolerance value for backbone distances. 9 | */ 10 | int DEFAULT_BACKBONE_DISTANCE_TOLERANCE = 1; 11 | /** 12 | * Default tolerance value for side-chain distances. 13 | */ 14 | int DEFAULT_SIDE_CHAIN_DISTANCE_TOLERANCE = 1; 15 | /** 16 | * Default tolerance value for angles. 17 | */ 18 | int DEFAULT_ANGLE_TOLERANCE = 1; 19 | 20 | /** 21 | * Timeout after this many milliseconds by throwing a {@link java.util.concurrent.TimeoutException}. No timeout is 22 | * enforced if set to Integer.MAX_VALUE. 23 | * @return the timeout specified for this query 24 | */ 25 | int getTimeout(); 26 | 27 | /** 28 | * Reports whether this query is configured to timeout. 29 | * @return true if this query will get interrupted after some time 30 | */ 31 | boolean hasTimeout(); 32 | } 33 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/PositionSpecificExchange.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.domain.structure.LabelSelection; 4 | import org.rcsb.strucmotif.domain.structure.ResidueType; 5 | 6 | import java.util.LinkedHashSet; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * Defines a position-specific exchange for a particular position in the query structure. 13 | */ 14 | public class PositionSpecificExchange { 15 | private final LabelSelection labelSelection; 16 | private final Set residueTypes; 17 | 18 | /** 19 | * Constructs a new position-specific exchange. 20 | * @see PositionSpecificExchange (LabelSelection, Set) 21 | * @param labelSelection selector of the referenced position 22 | * @param residueTypes all allowed types (must include original type if still allowed) 23 | */ 24 | public PositionSpecificExchange(LabelSelection labelSelection, ResidueType... residueTypes) { 25 | this(labelSelection, Stream.of(residueTypes).collect(Collectors.toCollection(LinkedHashSet::new))); 26 | } 27 | 28 | /** 29 | * Constructs a new position-specific exchange. 30 | * @param labelSelection selector of the referenced position 31 | * @param residueTypes all allowed types (must include original type if still allowed) 32 | */ 33 | public PositionSpecificExchange(LabelSelection labelSelection, Set residueTypes) { 34 | this.labelSelection = labelSelection; 35 | this.residueTypes = residueTypes; 36 | } 37 | 38 | /** 39 | * The position this exchange references. 40 | * @return the {@link LabelSelection} of a residue 41 | */ 42 | public LabelSelection getLabelSelection() { 43 | return labelSelection; 44 | } 45 | 46 | /** 47 | * The set of allowed component types at that position. Must explicitly include the original residue type if that 48 | * should still be allowed. 49 | * @return all types that can occur at this position 50 | */ 51 | public Set getResidueTypes() { 52 | return residueTypes; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/QueryStructure.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.rcsb.strucmotif.domain.structure.Structure; 4 | 5 | /** 6 | * References the structure that is the basis of a query. 7 | */ 8 | public interface QueryStructure { 9 | /** 10 | * The identifier of this structure. 11 | * @return a String 12 | */ 13 | String getStructureIdentifier(); 14 | 15 | /** 16 | * The structure data. 17 | * @return {@link Structure} instance 18 | */ 19 | Structure getStructure(); 20 | } 21 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/ResultsContentType.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import java.util.function.Predicate; 4 | 5 | /** 6 | * Controls the set of allowed targets, effectively providing high-level control to find exclusively PDB structures, or 7 | * exclusively computed structure models. 8 | */ 9 | public enum ResultsContentType implements Predicate { 10 | /** 11 | * Return only PDB-entries. 12 | */ 13 | EXPERIMENTAL(s -> s.matches(Constants.PDB_REGEX)), 14 | /** 15 | * Return only computed structure models. 16 | */ 17 | COMPUTATIONAL(s -> !s.matches(Constants.PDB_REGEX)); 18 | 19 | private static class Constants { 20 | private static final String PDB_REGEX = "^[0-9][a-zA-Z0-9]{3}$"; 21 | } 22 | 23 | private final Predicate condition; 24 | 25 | ResultsContentType(Predicate condition) { 26 | this.condition = condition; 27 | } 28 | 29 | @Override 30 | public boolean test(String s) { 31 | return condition.test(s); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/query/SearchQuery.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | /** 4 | * Summarizes a query. 5 | * @param

parameter type 6 | * @param query structure type 7 | */ 8 | public interface SearchQuery

{ 9 | /** 10 | * Access to the parameters used. 11 | * @return a {@link Parameters} instance 12 | */ 13 | P getParameters(); 14 | 15 | /** 16 | * Access to the underlying query structure. 17 | * @return a {@link QueryStructure} instance 18 | */ 19 | S getQueryStructure(); 20 | } 21 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/Hit.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | /** 4 | * One accepted hit. 5 | */ 6 | public interface Hit { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/MotifHit.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import org.rcsb.strucmotif.domain.structure.LabelSelection; 4 | import org.rcsb.strucmotif.domain.structure.ResidueType; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * The result of a structural motif search. 11 | * @param motifIdentifier the motif ID 12 | * @param labelSelections selections for each matched residue 13 | * @param residueTypes mapped residue types 14 | * @param rmsd the alignment score 15 | * @param transformation the transformation determined by the alignment 16 | */ 17 | public record MotifHit(String motifIdentifier, List labelSelections, List residueTypes, float rmsd, float[] transformation) implements Hit { 18 | @Override 19 | public String toString() { 20 | return "MotifHit{" + 21 | "motifIdentifier='" + motifIdentifier + '\'' + 22 | ", labelSelections=" + labelSelections + 23 | ", residueTypes=" + residueTypes + 24 | ", rmsd=" + rmsd + 25 | ", transformation=" + Arrays.toString(transformation) + 26 | '}'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/MotifSearchResult.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * The results of a motif search run. 8 | */ 9 | public class MotifSearchResult implements SearchResult { 10 | private final MotifTimings timings; 11 | private List hits; 12 | 13 | /** 14 | * Construct a result container. 15 | */ 16 | public MotifSearchResult() { 17 | this.timings = new MotifTimings(); 18 | this.hits = new ArrayList<>(); 19 | } 20 | 21 | @Override 22 | public MotifTimings getTimings() { 23 | return timings; 24 | } 25 | 26 | /** 27 | * Update the collection of accepted hits. 28 | * @param hits a collection of hits 29 | */ 30 | public void setHits(List hits) { 31 | this.hits = hits; 32 | } 33 | 34 | @Override 35 | public List getHits() { 36 | return hits; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/MotifTimings.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | /** 4 | * Timings in the context of motif queries. 5 | */ 6 | public class MotifTimings implements Timings { 7 | private final Timer query; 8 | 9 | /** 10 | * Constructs a new timer instance. Immediately starts the query timer. 11 | */ 12 | public MotifTimings() { 13 | this.query = new Timer(); 14 | queryStart(); 15 | } 16 | 17 | @Override 18 | public void queryStart() { 19 | query.start(); 20 | } 21 | 22 | @Override 23 | public void queryStop() { 24 | query.stop(); 25 | } 26 | 27 | @Override 28 | public long getQueryTime() { 29 | return query.getMillisecondTime(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/SearchResult.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * The results of a search run. 7 | * @param hit type 8 | */ 9 | public interface SearchResult { 10 | /** 11 | * Associated timings. 12 | * @return captured timings 13 | */ 14 | Timings getTimings(); 15 | 16 | /** 17 | * All accepted hits. 18 | * @return a collection of hits 19 | */ 20 | List getHits(); 21 | } 22 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/StructureHit.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import org.rcsb.strucmotif.domain.structure.LabelSelection; 4 | import org.rcsb.strucmotif.domain.structure.ResidueType; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * The result of a structural motif search. 11 | * @param structureIdentifier the entry ID 12 | * @param assemblyIdentifier the assembly ID 13 | * @param labelSelections selections for each matched residue 14 | * @param residueTypes mapped residue types 15 | * @param rmsd the alignment score 16 | * @param transformation the transformation determined by the alignment 17 | */ 18 | public record StructureHit(String structureIdentifier, String assemblyIdentifier, List labelSelections, List residueTypes, float rmsd, float[] transformation) implements Hit { 19 | @Override 20 | public String toString() { 21 | return "StructureHit{" + 22 | "structureIdentifier='" + structureIdentifier + '\'' + 23 | ", assemblyIdentifier='" + assemblyIdentifier + '\'' + 24 | ", labelSelections=" + labelSelections + 25 | ", residueTypes=" + residueTypes + 26 | ", rmsd=" + rmsd + 27 | ", transformation=" + Arrays.toString(transformation) + 28 | '}'; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/StructureSearchResult.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | /** 8 | * The results of a structure search run. 9 | */ 10 | public class StructureSearchResult implements SearchResult { 11 | private final StructureTimings timings; 12 | 13 | /** 14 | * Keep track of the generation we are currently in, i.e. how many words of the query have been consumed. 15 | */ 16 | private int pathGeneration; 17 | private Map targetStructures; 18 | 19 | private List hits; 20 | private int numberOfPaths; 21 | private int numberOfTargetStructures; 22 | 23 | /** 24 | * Construct a result container. 25 | */ 26 | public StructureSearchResult() { 27 | this.timings = new StructureTimings(); 28 | this.pathGeneration = 0; 29 | this.hits = new ArrayList<>(); 30 | } 31 | 32 | /** 33 | * Associated timings. 34 | * @return timings object 35 | */ 36 | @Override 37 | public StructureTimings getTimings() { 38 | return timings; 39 | } 40 | 41 | /** 42 | * Access to all currently referenced target structures. 43 | * @return a map with structure identifiers as keys and target structure instances as values 44 | */ 45 | public Map getTargetStructures() { 46 | return targetStructures; 47 | } 48 | 49 | /** 50 | * Update the currently referenced target structures. 51 | * @param targetStructures a map with structure indices as keys and target structure instances as values 52 | */ 53 | public void setTargetStructures(Map targetStructures) { 54 | this.targetStructures = targetStructures; 55 | } 56 | 57 | /** 58 | * Update the collection of currently valid hits. 59 | * @param hits a collection of hits 60 | */ 61 | public void setHits(List hits) { 62 | this.hits = hits; 63 | } 64 | 65 | /** 66 | * Access all (currently) valid hits. 67 | * @return a collection of hits 68 | */ 69 | @Override 70 | public List getHits() { 71 | return hits; 72 | } 73 | 74 | /** 75 | * Update the number of valid paths. 76 | * @param numberOfPaths an int 77 | */ 78 | public void setNumberOfPaths(int numberOfPaths) { 79 | this.numberOfPaths = numberOfPaths; 80 | } 81 | 82 | /** 83 | * The number of valid paths in all target structures. 84 | * @return an int 85 | */ 86 | public int getNumberOfPaths() { 87 | return numberOfPaths; 88 | } 89 | 90 | /** 91 | * Update the number of referenced target structures. 92 | * @param numberOfTargetStructures an int 93 | */ 94 | public void setNumberOfTargetStructures(int numberOfTargetStructures) { 95 | this.numberOfTargetStructures = numberOfTargetStructures; 96 | } 97 | 98 | /** 99 | * The number of referenced target structures. 100 | * @return an int 101 | */ 102 | public int getNumberOfTargetStructures() { 103 | return numberOfTargetStructures; 104 | } 105 | 106 | /** 107 | * Called internally after a descriptor has been processed. 108 | * @return the new path generation 109 | */ 110 | public int incrementAndGetPathGeneration() { 111 | pathGeneration++; 112 | return pathGeneration; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/StructureTimings.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | /** 4 | * Timings in the context of structure queries. 5 | */ 6 | public class StructureTimings implements Timings { 7 | private final Timer query; 8 | private final Timer paths; 9 | private final Timer scoreHits; 10 | 11 | /** 12 | * Constructs a new timer instance. Immediately starts the query timer. 13 | */ 14 | public StructureTimings() { 15 | this.query = new Timer(); 16 | this.paths = new Timer(); 17 | this.scoreHits = new Timer(); 18 | queryStart(); 19 | } 20 | 21 | /** 22 | * Start the path assembly timer. 23 | */ 24 | public void pathsStart() { 25 | paths.start(); 26 | } 27 | 28 | /** 29 | * Stop the path assembly timer. 30 | */ 31 | public void pathsStop() { 32 | paths.stop(); 33 | } 34 | 35 | /** 36 | * Get the path assembly time in ms. 37 | * @return a long 38 | */ 39 | public long getPathsTime() { 40 | return paths.getMillisecondTime(); 41 | } 42 | 43 | /** 44 | * Start the hit scoring timer. 45 | */ 46 | public void scoreHitsStart() { 47 | scoreHits.start(); 48 | } 49 | 50 | /** 51 | * Stop the hit scoring timer. 52 | */ 53 | public void scoreHitsStop() { 54 | this.scoreHits.stop(); 55 | } 56 | 57 | /** 58 | * Get the hit scoring time in ms. 59 | * @return a long 60 | */ 61 | public long getScoreHitsTime() { 62 | return scoreHits.getMillisecondTime(); 63 | } 64 | 65 | @Override 66 | public void queryStart() { 67 | query.start(); 68 | } 69 | 70 | @Override 71 | public void queryStop() { 72 | query.stop(); 73 | } 74 | 75 | @Override 76 | public long getQueryTime() { 77 | return query.getMillisecondTime(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/Timer.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * Tracks timings. 7 | */ 8 | public class Timer { 9 | private long start; 10 | private long time; 11 | private boolean stopped; 12 | 13 | /** 14 | * Default constructor. 15 | */ 16 | public Timer() { 17 | } 18 | 19 | /** 20 | * Start the time. 21 | */ 22 | public void start() { 23 | if (start != 0) { 24 | throw new IllegalStateException("timer has been started before"); 25 | } 26 | if (time != 0) { 27 | throw new IllegalStateException("timer has been stopped before"); 28 | } 29 | 30 | this.start = System.nanoTime(); 31 | } 32 | 33 | /** 34 | * Stop the time and 'freeze' the measurement for later retrieval/output. 35 | */ 36 | public void stop() { 37 | if (start == 0) { 38 | throw new IllegalStateException("timer was never started"); 39 | } 40 | if (time != 0) { 41 | throw new IllegalStateException("timer has been stopped before"); 42 | } 43 | 44 | this.time = System.nanoTime() - start; 45 | this.stopped = true; 46 | } 47 | 48 | /** 49 | * Retrieve the measured time in milliseconds. 50 | * @return a long in ms 51 | */ 52 | public long getMillisecondTime() { 53 | return getMeasuredTime(TimeUnit.MILLISECONDS); 54 | } 55 | 56 | /** 57 | * Retrieve the measured time. 58 | * @param timeUnit the {@link TimeUnit} in which to output 59 | * @return a long of the desired granularity 60 | */ 61 | public long getMeasuredTime(TimeUnit timeUnit) { 62 | if (!stopped) throw new IllegalStateException("timer was never stopped"); 63 | return timeUnit.convert(time, TimeUnit.NANOSECONDS); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/result/Timings.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.result; 2 | 3 | /** 4 | * A helper class keeping track of internal timings. Useful for development and diagnosis. All but the query timer need 5 | * to be started at an appropriate time during the query. 'Overall' query timer is started upon creation of this class. 6 | * All timers need to be explicitly stopped. Timers return times in ms. 7 | */ 8 | public interface Timings { 9 | /** 10 | * Start the query timer. 11 | */ 12 | void queryStart(); 13 | 14 | /** 15 | * Stop the query timer. 16 | */ 17 | void queryStop(); 18 | 19 | /** 20 | * Get the overall query timer in ms. 21 | * @return a long 22 | */ 23 | long getQueryTime(); 24 | } 25 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/structure/LabelSelection.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.structure; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * Identifies a residue unambiguously by label_asym_id, struct_oper_id, and label_seq_id. Basically, the 'natural' way 7 | * to reference residues. 8 | * @param labelAsymId the chain of interest 9 | * @param structOperId the operation of interest 10 | * @param labelSeqId the sequence position of interest 11 | */ 12 | public record LabelSelection(String labelAsymId, String structOperId, int labelSeqId) { 13 | @Override 14 | public boolean equals(Object o) { 15 | if (this == o) return true; 16 | if (o == null || getClass() != o.getClass()) return false; 17 | LabelSelection that = (LabelSelection) o; 18 | return labelSeqId == that.labelSeqId && 19 | Objects.equals(labelAsymId, that.labelAsymId) && 20 | Objects.equals(structOperId, that.structOperId); 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | return Objects.hash(labelAsymId, structOperId, labelSeqId); 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return labelAsymId + "_" + structOperId + "-" + labelSeqId; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/structure/PolymerType.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.structure; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.Map; 6 | import java.util.Optional; 7 | import java.util.Set; 8 | import java.util.stream.Collectors; 9 | 10 | /** 11 | * Reports the polymer type for a component. Used to determine the correct constructor during model creation. 12 | */ 13 | public enum PolymerType { 14 | /** 15 | * Amino acid chain. 16 | */ 17 | AMINO_ACID(Set.of("d-peptide linking", 18 | "d-peptide nh3 amino terminus", 19 | "d-peptide cooh carboxy terminus", 20 | "d-gamma-peptide, c-delta linking", 21 | "d-beta-peptide, c-gamma linking", 22 | "l-peptide linking", 23 | "l-peptide nh3 amino terminus", 24 | "l-peptide cooh carboxy terminus", 25 | "l-gamma-peptide, c-delta linking", 26 | "l-beta-peptide, c-gamma linking", 27 | "peptide linking", 28 | "peptide-like")), 29 | /** 30 | * Nucleotide chain. 31 | */ 32 | NUCLEOTIDE(Set.of("dna linking", 33 | "l-dna linking", 34 | "dna oh 5 prime terminus", 35 | "dna oh 3 prime terminus", 36 | "rna linking", "l-rna linking", 37 | "rna oh 5 prime terminus", 38 | "rna oh 3 prime terminus")), 39 | /** 40 | * Unknown but polymeric. 41 | */ 42 | UNKNOWN_POLYMER(Collections.emptySet()); 43 | 44 | /** 45 | * Cached values of this enum. Don't manipulate this array or things will burn. 46 | */ 47 | public static final PolymerType[] values = values(); 48 | 49 | private final Set typeNames; 50 | 51 | PolymerType(Set typeNames) { 52 | this.typeNames = typeNames; 53 | } 54 | 55 | /** 56 | * Access to CCD types that correspond to this polymer type. 57 | * @return all associated chem_comp.type values 58 | */ 59 | public Set getTypeNames() { 60 | return typeNames; 61 | } 62 | 63 | private static final Map MAPPING = Arrays.stream(PolymerType.values) 64 | .flatMap(t -> t.getTypeNames().stream().map(n -> Map.entry(n, t))) 65 | .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 66 | 67 | /** 68 | * Map the type of polymeric component to the enum. 69 | * @param type value to resolve 70 | * @return the corresponding polymer type 71 | */ 72 | public static Optional ofChemCompType(String type) { 73 | return Optional.ofNullable(MAPPING.get(type.toLowerCase())); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/domain/structure/StructureInformation.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.structure; 2 | 3 | /** 4 | * Reports global properties of a structure. 5 | * @param structureIdentifier entry id 6 | * @param structureIndex globally unique identifier of this entry 7 | * @param majorRevision version info 8 | * @param minorRevision version info 9 | */ 10 | public record StructureInformation(String structureIdentifier, int structureIndex, int majorRevision, int minorRevision) {} 11 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/Committable.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | /** 4 | * Allows writing data to FFindex-managed files without compromising production data. Call the providing function to 5 | * commit all data to the production files. This is rather slow and should only happen from time to time. 6 | */ 7 | public interface Committable { 8 | /** 9 | * Process all temporary files and make them available in queries. 10 | */ 11 | void commit(); 12 | } 13 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/InvertedIndex.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.bucket.ArrayBucket; 4 | 5 | import java.util.Collection; 6 | import java.util.Set; 7 | import java.util.stream.Stream; 8 | 9 | /** 10 | * The specification on how to insert and select residue pair occurrences. Update operate is not directly supported 11 | * (rather invalid/obsolete identifiers have to be removed manually and subsequently the new data can be inserted). 12 | * Insert operations are implemented by the update routine. It will place temporary files next to the index files and by 13 | * calling {@link #commit()}, these can be added to the index. 14 | */ 15 | public interface InvertedIndex extends Committable { 16 | /** 17 | * Perform lookup for a particular bin. 18 | * @param residuePairDescriptor the bin for which occurrences should the lookup be performed 19 | * @return a {@link Stream} of all occurrences, grouped by their structure identifier 20 | */ 21 | ArrayBucket select(int residuePairDescriptor); 22 | 23 | /** 24 | * Removes all information on a set of structures from the index. 25 | * @param structureIdentifiers what to remove 26 | */ 27 | void delete(Collection structureIdentifiers); 28 | 29 | /** 30 | * Scans the entire index and returns all referenced descriptors. 31 | * @return a collection of all descriptors 32 | */ 33 | Set reportKnownDescriptors(); 34 | 35 | /** 36 | * Scans the entire index and returns all referenced structure indices. 37 | * @return a collection of all structure indices 38 | */ 39 | Set reportKnownKeys(); 40 | } 41 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/ResidueTypeResolver.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.structure.ResidueType; 4 | 5 | /** 6 | * Maps from generic three-letter-codes to the {@link ResidueType} enum. Depending on the selected strategy, this will 7 | * completely ignore non-canonical components or map them to something known via their parent. 8 | */ 9 | public interface ResidueTypeResolver { 10 | /** 11 | * Map a three-letter-code to a ResidueType. 12 | * @param threeLetterCode the input 13 | * @return a ResidueType, might be the unknown component 14 | */ 15 | ResidueType selectResidueType(String threeLetterCode); 16 | } 17 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/SingleStructureDataProvider.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.cif.schema.mm.MmCifFile; 4 | import org.rcsb.strucmotif.domain.structure.Structure; 5 | 6 | import java.io.InputStream; 7 | import java.util.Collection; 8 | import java.util.Set; 9 | 10 | /** 11 | * An implementation of a {@link StructureDataProvider} that only deals with a single structure. Used in the 12 | * 'detect-motif' mode (see {@link org.rcsb.strucmotif.domain.query.MotifContextBuilder}). 13 | */ 14 | public class SingleStructureDataProvider implements StructureDataProvider { 15 | private final Structure structure; 16 | 17 | /** 18 | * Create a data provider for this structure. 19 | * @param structure the content 20 | */ 21 | public SingleStructureDataProvider(Structure structure) { 22 | this.structure = structure; 23 | } 24 | 25 | @Override 26 | public void initializeRenumberedStructureCache() { 27 | // no need to do anything 28 | } 29 | 30 | @Override 31 | public Structure readFromInputStream(InputStream inputStream) { 32 | return structure; 33 | } 34 | 35 | @Override 36 | public Structure readRenumbered(String structureIdentifier) { 37 | return structure; 38 | } 39 | 40 | @Override 41 | public Structure readOriginal(String structureIdentifier) { 42 | return structure; 43 | } 44 | 45 | @Override 46 | public Structure readSome(String structureIdentifier) { 47 | return structure; 48 | } 49 | 50 | @Override 51 | public void enterWriteMode() { 52 | immutable(); 53 | } 54 | 55 | @Override 56 | public void writeRenumbered(String structureIdentifier, MmCifFile mmCifFile, int modelIdentifier) { 57 | immutable(); 58 | } 59 | 60 | @Override 61 | public void deleteRenumbered(Collection structureIdentifiers) { 62 | immutable(); 63 | } 64 | 65 | @Override 66 | public InputStream getOriginalInputStream(String structureIdentifier) { 67 | return null; 68 | } 69 | 70 | @Override 71 | public void commit() { 72 | immutable(); 73 | } 74 | 75 | private void immutable() { 76 | throw new UnsupportedOperationException("This data provider is read-only"); 77 | } 78 | 79 | @Override 80 | public Set reportKnownFiles() { 81 | throw new UnsupportedOperationException("This data provider contains a single not registered structure"); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/SingleStructureIndexProvider.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.query.ResultsContentType; 4 | import org.rcsb.strucmotif.domain.structure.Structure; 5 | 6 | import java.util.Collection; 7 | import java.util.Set; 8 | 9 | /** 10 | * An implementation of a {@link StructureIndexProvider} that only deals with a single structure. Used in the 11 | * 'detect-motif' mode (see {@link org.rcsb.strucmotif.domain.query.MotifContextBuilder}). 12 | */ 13 | public class SingleStructureIndexProvider implements StructureIndexProvider { 14 | private final int structureIndex; 15 | private final String structureIdentifier; 16 | 17 | /** 18 | * Create an index provider for this structure. 19 | * @param structure the content 20 | */ 21 | public SingleStructureIndexProvider(Structure structure) { 22 | this.structureIndex = -1; 23 | this.structureIdentifier = structure.getStructureIdentifier(); 24 | } 25 | 26 | @Override 27 | public String selectStructureIdentifier(int structureIndex) { 28 | return structureIdentifier; 29 | } 30 | 31 | @Override 32 | public int selectStructureIndex(String structureIdentifier) { 33 | return structureIndex; 34 | } 35 | 36 | @Override 37 | public int selectOrMintStructureIndex(String structureIdentifier) { 38 | throw new UnsupportedOperationException("This index provider is read-only"); 39 | } 40 | 41 | @Override 42 | public int nextStructureIndex() { 43 | throw new UnsupportedOperationException("This index provider is read-only"); 44 | } 45 | 46 | @Override 47 | public boolean containsKey(String structureIdentifier) { 48 | return this.structureIdentifier.equals(structureIdentifier); 49 | } 50 | 51 | @Override 52 | public boolean containsKey(int structureIndex) { 53 | return this.structureIndex == structureIndex; 54 | } 55 | 56 | @Override 57 | public Set selectByResultsContentType(Collection resultsContentType) { 58 | return Set.of(structureIndex); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/SingleStructureInvertedIndex.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.bucket.ArrayBucket; 4 | import org.rcsb.strucmotif.domain.motif.ResiduePairOccurrence; 5 | import org.rcsb.strucmotif.domain.structure.ResidueGraph; 6 | 7 | import java.util.Collection; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.stream.Collectors; 12 | 13 | /** 14 | * An implementation of a {@link InvertedIndex} that only deals with a single structure. Used in the 15 | * 'detect-motif' mode (see {@link org.rcsb.strucmotif.domain.query.MotifContextBuilder}). 16 | */ 17 | public class SingleStructureInvertedIndex implements InvertedIndex { 18 | private final Map index; 19 | 20 | /** 21 | * Create an inverted index based on this graph. 22 | * @param residueGraph the content 23 | */ 24 | public SingleStructureInvertedIndex(ResidueGraph residueGraph) { 25 | index = residueGraph.residuePairOccurrencesParallel() 26 | .collect(Collectors.groupingBy(ResiduePairOccurrence::getResiduePairDescriptor, Collectors.collectingAndThen(Collectors.toList(), this::toInvertedIndexBucket))); 27 | } 28 | 29 | private ArrayBucket toInvertedIndexBucket(List residuePairOccurrences) { 30 | int[] structureIndices = new int[] { 0 }; 31 | int[] positionOffsets = new int[] { 0 }; 32 | int[] positionData = new int[residuePairOccurrences.size() * 2]; 33 | 34 | for (int i = 0; i < residuePairOccurrences.size(); i++) { 35 | ResiduePairOccurrence occurrence = residuePairOccurrences.get(i); 36 | positionData[2 * i] = occurrence.getResidueIndex1(); 37 | positionData[2 * i + 1] = occurrence.getResidueIndex2(); 38 | } 39 | 40 | return new ArrayBucket(structureIndices, positionOffsets, positionData); 41 | } 42 | 43 | @Override 44 | public void commit() { 45 | immutable(); 46 | } 47 | 48 | @Override 49 | public ArrayBucket select(int residuePairDescriptor) { 50 | return index.getOrDefault(residuePairDescriptor, ArrayBucket.EMPTY_BUCKET); 51 | } 52 | 53 | @Override 54 | public void delete(Collection structureIdentifiers) { 55 | immutable(); 56 | } 57 | 58 | @Override 59 | public Set reportKnownDescriptors() { 60 | return index.keySet(); 61 | } 62 | 63 | @Override 64 | public Set reportKnownKeys() { 65 | throw new UnsupportedOperationException("This bin contains a single not registered structure"); 66 | } 67 | 68 | private void immutable() { 69 | throw new UnsupportedOperationException("This index is read-only"); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/StateRepository.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.structure.StructureInformation; 4 | 5 | import java.util.Set; 6 | import java.util.stream.Collectors; 7 | 8 | /** 9 | * The state of the application consists of two lists of structure identifiers: 10 | *

    11 | *
  • known: entries that have been processed (might become invalid if e.g. alpha carbon trace)
  • 12 | *
  • dirty: all identifiers that could cause a corrupted state (if update fails during inverted index writing) - useful to recover
  • 13 | *
14 | */ 15 | public interface StateRepository { 16 | /** 17 | * Returns all registered revisions. 18 | * @return a collection of ids and their corresponding revision 19 | */ 20 | Set selectKnown(); 21 | 22 | /** 23 | * Returns all referenced structure indices. 24 | * @return a collection of all structure indices 25 | */ 26 | default Set reportKnownKeys() { 27 | return selectKnown() 28 | .stream() 29 | .map(StructureInformation::structureIndex) 30 | .collect(Collectors.toSet()); 31 | } 32 | 33 | /** 34 | * The set of currently 'dirty' ids. Will be populated when update starts and emptied upon successful completion. 35 | * Problematic if not the empty set after an update. 36 | * @return a collection of ids 37 | */ 38 | Set selectDirty(); 39 | 40 | /** 41 | * Insert into 'known' collection. 42 | * @param additions a collection of ids 43 | */ 44 | void insertKnown(Set additions); 45 | 46 | /** 47 | * Insert into 'dirty' collection. 48 | * @param additions a collection of ids 49 | */ 50 | void insertDirty(Set additions); 51 | 52 | /** 53 | * Remove from 'known' collection. 54 | * @param removals a collection of ids 55 | */ 56 | void deleteKnown(Set removals); 57 | 58 | /** 59 | * Remove from 'dirty' collection. 60 | * @param removals a collection of ids 61 | */ 62 | void deleteDirty(Set removals); 63 | } 64 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/StructureDataProvider.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.cif.schema.mm.MmCifFile; 4 | import org.rcsb.strucmotif.domain.structure.Structure; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.util.Collection; 9 | import java.util.Set; 10 | 11 | /** 12 | * Access structure data. 13 | */ 14 | public interface StructureDataProvider extends Committable { 15 | int DEFAULT_MODEL_IDENTIFIER = 1; 16 | 17 | /** 18 | * If `strucmotif.in-memory-strategy` is active: Initialize caching by reading all structures and keeping them in 19 | * memory for fast access. 20 | */ 21 | void initializeRenumberedStructureCache(); 22 | 23 | /** 24 | * Read everything from an input stream. 25 | * @param inputStream the source of data, assumed to be following the mmCIF schema 26 | * @return the corresponding {@link Structure} 27 | */ 28 | Structure readFromInputStream(InputStream inputStream); 29 | 30 | /** 31 | * Read a renumbered structure entirely. 32 | * @param structureIdentifier the structure to read 33 | * @return the corresponding {@link Structure} 34 | */ 35 | Structure readRenumbered(String structureIdentifier); 36 | 37 | /** 38 | * Read a selected range from an original structure. 39 | * @param structureIdentifier the structure to read 40 | * @return the corresponding {@link Structure} 41 | */ 42 | Structure readOriginal(String structureIdentifier); 43 | 44 | /** 45 | * Read some structure entirely. 46 | * @param structureIdentifier the structure to read 47 | * @return the corresponding {@link Structure} 48 | */ 49 | Structure readSome(String structureIdentifier); 50 | 51 | /** 52 | * Must be called before invoking {@link #writeRenumbered(String, MmCifFile, int)}. 53 | * @throws IOException if files can't be created 54 | */ 55 | void enterWriteMode() throws IOException; 56 | 57 | /** 58 | * Write a renumbered structure. Make sure to call {@link #enterWriteMode()} if you need to write structure data. 59 | * @param structureIdentifier the structure identifier to write 60 | * @param mmCifFile the data source 61 | */ 62 | default void writeRenumbered(String structureIdentifier, MmCifFile mmCifFile) { 63 | writeRenumbered(structureIdentifier, mmCifFile, DEFAULT_MODEL_IDENTIFIER); 64 | } 65 | 66 | /** 67 | * Write a renumbered structure. Make sure to call {@link #enterWriteMode()} if you need to write structure data. 68 | * @param structureIdentifier the structure identifier to write 69 | * @param mmCifFile the data source 70 | * @param modelIdentifier specific model to extract 71 | */ 72 | void writeRenumbered(String structureIdentifier, MmCifFile mmCifFile, int modelIdentifier); 73 | 74 | /** 75 | * Drop information on a renumbered structure. 76 | * @param structureIdentifiers the collection of structure identifier to remove 77 | */ 78 | void deleteRenumbered(Collection structureIdentifiers); 79 | 80 | /** 81 | * Acquire the input stream of an original structure. 82 | * @param structureIdentifier the structure identifier to read 83 | * @return the corresponding input stream 84 | */ 85 | InputStream getOriginalInputStream(String structureIdentifier); 86 | 87 | /** 88 | * Report all known structure files. 89 | * @return a collection of filenames 90 | */ 91 | Set reportKnownFiles(); 92 | } 93 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/StructureIndexProvider.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.query.ResultsContentType; 4 | 5 | import java.util.Collection; 6 | import java.util.Set; 7 | 8 | /** 9 | * Maps between structure indices (a compact int representation that is e.g. stored in the inverted index) and readable 10 | * Strings (that can be PDB-IDs or longer, namespaced identifiers used by computed structure models). 11 | */ 12 | public interface StructureIndexProvider { 13 | /** 14 | * Maps between structure index and identifier. 15 | * @param structureIndex the int 16 | * @return the String 17 | */ 18 | String selectStructureIdentifier(int structureIndex); 19 | 20 | /** 21 | * Maps between structure identifier and index. 22 | * @param structureIdentifier the String 23 | * @return the int 24 | */ 25 | int selectStructureIndex(String structureIdentifier); 26 | 27 | /** 28 | * Get the structure index associated to this identifier. If none exists a new one will be created. 29 | * @param structureIdentifier the structure identifier 30 | * @return a unique int that maps to this identifier 31 | */ 32 | int selectOrMintStructureIndex(String structureIdentifier); 33 | 34 | /** 35 | * Get the next available structureIndex. This may reuse a previously assigned index that is no longer referenced. 36 | * @return an int that is guaranteed to uniquely identify a structure in the inverted index 37 | */ 38 | int nextStructureIndex(); 39 | 40 | /** 41 | * Check if this structure identifier is known. 42 | * @param structureIdentifier the String 43 | * @return true if this key has a mapping 44 | */ 45 | boolean containsKey(String structureIdentifier); 46 | 47 | /** 48 | * Check if this structure index is known. 49 | * @param structureIndex the int 50 | * @return true if this key has a mapping 51 | */ 52 | boolean containsKey(int structureIndex); 53 | 54 | /** 55 | * Get all registered indices of a particular type. 56 | * @param resultsContentType search space identifier (PDB entries, computed structure models, everything) 57 | * @return a collection of all relevant structure indices 58 | */ 59 | Set selectByResultsContentType(Collection resultsContentType); 60 | } 61 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/StructureReader.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.strucmotif.domain.structure.Structure; 4 | 5 | import java.io.InputStream; 6 | 7 | /** 8 | * Read structures from CIF files. 9 | */ 10 | public interface StructureReader { 11 | /** 12 | * Neutral transform. 13 | */ 14 | float[] IDENTITY_TRANSFORM = new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }; 15 | 16 | /** 17 | * Read from a InputStream and parse the corresponding Structure. 18 | * @param inputStream the source 19 | * @return the parsed Structure instance 20 | */ 21 | Structure readFromInputStream(InputStream inputStream); 22 | } 23 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/StructureWriter.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.rcsb.cif.schema.mm.MmCifFile; 4 | 5 | /** 6 | * The contract to write optimized structure data that don't contain non-polymers, hydrogen, non-selected models etc. 7 | */ 8 | public interface StructureWriter { 9 | /** 10 | * Converts a structure data to its binary representation. 11 | * @param source a MmCifFile to process 12 | * @return a byte[] with the file content or null if the structure would be empty 13 | */ 14 | default byte[] write(MmCifFile source) { 15 | return write(source, StructureDataProvider.DEFAULT_MODEL_IDENTIFIER); 16 | } 17 | 18 | /** 19 | * Converts a structure data to its binary representation. 20 | * @param source a MmCifFile to process 21 | * @param modelIdentifier identifier of the model to extract 22 | * @return a byte[] with the file content or null if the structure would be empty 23 | */ 24 | byte[] write(MmCifFile source, int modelIdentifier); 25 | } 26 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/codec/BucketCodec.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io.codec; 2 | 3 | import org.rcsb.strucmotif.domain.bucket.ArrayBucket; 4 | 5 | import java.io.IOException; 6 | import java.nio.ByteBuffer; 7 | 8 | /** 9 | * Persistence of inverted index buckets. 10 | */ 11 | public interface BucketCodec { 12 | /** 13 | * Deserialize a bucket from an InputStream. 14 | * @param byteBuffer data source 15 | * @return the decoded bucket 16 | */ 17 | ArrayBucket decode(ByteBuffer byteBuffer); 18 | 19 | /** 20 | * Serialize a bucket as binary stream. 21 | * @param bucket data source 22 | * @return the encoded data 23 | * @throws IOException writing failed 24 | */ 25 | ByteBuffer encode(ArrayBucket bucket) throws IOException; 26 | } 27 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/io/codec/JsonCodec.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io.codec; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.reflect.TypeToken; 6 | import org.rcsb.strucmotif.domain.bucket.ArrayBucket; 7 | 8 | import java.io.ByteArrayInputStream; 9 | import java.io.InputStreamReader; 10 | import java.lang.reflect.Type; 11 | import java.nio.ByteBuffer; 12 | import java.nio.charset.StandardCharsets; 13 | import java.util.Map; 14 | 15 | /** 16 | * Text-based implementation of a codec serializer. Useful for debugging. 17 | */ 18 | public class JsonCodec implements BucketCodec { 19 | /** 20 | * Tag of the structure index array. 21 | */ 22 | public static final String STRUCTURE_INDICES = "structure_indices"; 23 | /** 24 | * Tag of the position offset array. 25 | */ 26 | public static final String POSITION_OFFSETS = "position_offsets"; 27 | /** 28 | * Tag of the identifier data array. 29 | */ 30 | public static final String IDENTIFIER_DATA = "identifier_data"; 31 | private final Type mapType; 32 | private final Gson gson; 33 | 34 | /** 35 | * Default constructor. 36 | */ 37 | public JsonCodec() { 38 | this.gson = new GsonBuilder().setPrettyPrinting().create(); 39 | this.mapType = new TypeToken>() {}.getType(); 40 | } 41 | 42 | @Override 43 | public ArrayBucket decode(ByteBuffer byteBuffer) { 44 | Map map = gson.fromJson(new InputStreamReader(new ByteArrayInputStream(toByteArray(byteBuffer))), mapType); 45 | return new ArrayBucket(map.get(STRUCTURE_INDICES), map.get(POSITION_OFFSETS), map.get(IDENTIFIER_DATA)); 46 | } 47 | 48 | private byte[] toByteArray(ByteBuffer byteBuffer) { 49 | byteBuffer.rewind(); 50 | byte[] out = new byte[byteBuffer.remaining()]; 51 | byteBuffer.get(out); 52 | return out; 53 | } 54 | 55 | @Override 56 | public ByteBuffer encode(ArrayBucket arrayBucket) { 57 | Map map = Map.of(STRUCTURE_INDICES, arrayBucket.getStructureIndexArray(), POSITION_OFFSETS, arrayBucket.getPositionOffsetArray(), IDENTIFIER_DATA, arrayBucket.getIdentifierDataArray()); 58 | byte[] bytes = gson.toJson(map).getBytes(StandardCharsets.UTF_8); 59 | return ByteBuffer.wrap(bytes); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/java/org/rcsb/strucmotif/math/Partition.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.math; 2 | 3 | import java.util.AbstractList; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | import java.util.List; 8 | import java.util.Objects; 9 | 10 | /** 11 | * Partitions a collection into (roughly) equal-sized chunks. Will shuffle the original collection. 12 | *

13 | * code from: https://e.printstacktrace.blog/divide-a-list-to-lists-of-n-size-in-Java-8/ 14 | * @param type of the original collection 15 | */ 16 | public class Partition extends AbstractList> { 17 | private final List list; 18 | private final int chunkSize; 19 | 20 | /** 21 | * Split a collection into partitions up to a defined size. 22 | * @param list collection to partition 23 | * @param chunkSize how many elements in one batch 24 | */ 25 | public Partition(Collection list, int chunkSize) { 26 | this.list = new ArrayList<>(list); 27 | // shuffle to prevent troublemakers such as ribosome and virus capsids occurring in the same chunk 28 | Collections.shuffle(this.list); 29 | this.chunkSize = chunkSize; 30 | } 31 | 32 | @Override 33 | public List get(int index) { 34 | int start = index * chunkSize; 35 | int end = Math.min(start + chunkSize, list.size()); 36 | 37 | if (start > end) { 38 | throw new IndexOutOfBoundsException("Index " + index + " is out of the list range <0," + (size() - 1) + ">"); 39 | } 40 | 41 | return new ArrayList<>(list.subList(start, end)); 42 | } 43 | 44 | @Override 45 | public int size() { 46 | return (int) Math.ceil((double) list.size() / (double) chunkSize); 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | if (!super.equals(o)) return false; 54 | Partition partition = (Partition) o; 55 | return chunkSize == partition.chunkSize && Objects.equals(list, partition.list); 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return Objects.hash(super.hashCode(), list, chunkSize); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.diagnostics.FailureAnalyzer=\ 2 | org.rcsb.strucmotif.NoSuchFileFailureAnalyzer -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.main.banner-mode=off 2 | spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration -------------------------------------------------------------------------------- /strucmotif-search-core/src/main/resources/motifs.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "motifIdentifier": "CK", 4 | "structureIdentifier": "6zwf", 5 | "title": "NOS bridge", 6 | "description": "A covalent crosslink between a cysteine and a lysine residue with a NOS bridge that serves as an allosteric redox switch in the transaldolase enzyme of Neisseria gonorrhoeae, the pathogen that causes gonorrhoea.", 7 | "labelSelections": [{ 8 | "labelAsymId": "A", 9 | "structOperId": "1", 10 | "labelSeqId": 9 11 | }, { 12 | "labelAsymId": "A", 13 | "structOperId": "1", 14 | "labelSeqId": 39 15 | }], 16 | "positionSpecificExchanges": [] 17 | } 18 | ] -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/Demo.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import org.rcsb.strucmotif.domain.motif.EnrichedMotifDefinition; 4 | import org.rcsb.strucmotif.domain.structure.LabelSelection; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public class Demo { 10 | public static void main(String[] args) { 11 | // use a single motif definition to search for all structure that contain this motif 12 | Strucmotif.searchForStructures() 13 | // several ways can be used to define the query motif - e.g., specify a PDB entry id 14 | .defineByPdbIdAndSelection("4cha", 15 | // and a collection of sequence positions to extract residues to use as motif 16 | List.of(new LabelSelection("B", "1", 42), // HIS 17 | new LabelSelection("B", "1", 87), // ASP 18 | new LabelSelection("C", "1", 47))) // SER 19 | .rmsdCutoff(1.0) 20 | .buildParameters() 21 | .buildContext() 22 | .run() 23 | .getHits() 24 | .stream() 25 | .map(hit -> hit.structureIdentifier() + "_" + 26 | hit.assemblyIdentifier() + " @ " + 27 | hit.labelSelections() + " - RMSD: " + 28 | hit.rmsd()) 29 | .forEach(System.out::println); 30 | 31 | // use a single structure to detect all motifs that occur therein 32 | Set motifs = Strucmotif.getMotifDefinitionRegistry().getEnrichedMotifDefinitions(); 33 | Strucmotif.detectMotifs() 34 | .defineByPdbIdAndAssemblyId("2mnr", "1") 35 | .withMotifs(motifs) 36 | .rmsdCutoff(1.0) 37 | .buildParameters() 38 | .buildContext() 39 | .run() 40 | .getHits() 41 | .stream() 42 | .map(hit -> hit.motifIdentifier() + " @ " + 43 | hit.labelSelections() + " - RMSD: " + 44 | hit.rmsd()) 45 | .forEach(System.out::println); 46 | } 47 | } -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/Helpers.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import java.io.File; 4 | import java.io.InputStream; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.util.Objects; 8 | 9 | public class Helpers { 10 | public static final float DELTA = 0.001f; 11 | public static final float RELAXED_DELTA = 0.1f; 12 | 13 | public static short[] convertCoordsToShort(double[] array) { 14 | short[] out = new short[array.length]; 15 | for (int i = 0; i < out.length; i++) { 16 | out[i] = (short) Math.round(array[i] * 10); 17 | } 18 | return out; 19 | } 20 | 21 | public static InputStream getOriginalBcif(String pdbId) { 22 | return getResource("orig/" + pdbId.toLowerCase() + ".bcif"); 23 | } 24 | 25 | public static InputStream getRenumberedBcif(String pdbId) { 26 | return getResource("renum/" + pdbId + ".bcif"); 27 | } 28 | 29 | public static InputStream getResource(String location) { 30 | InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(location); 31 | return Objects.requireNonNull(resourceAsStream, "failed to locate test resource: " + location); 32 | } 33 | 34 | public static byte[] convertEnumToByte(Enum... array) { 35 | byte[] out = new byte[array.length]; 36 | for (int i = 0; i < out.length; i++) { 37 | out[i] = (byte) array[i].ordinal(); 38 | } 39 | return out; 40 | } 41 | 42 | public static Path getResourceAsPath(String path) { 43 | return Paths.get(new File("src/test/resources/").getAbsolutePath()).resolve(path); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/UpdateTestData.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif; 2 | 3 | import org.rcsb.cif.CifIO; 4 | import org.rcsb.cif.schema.StandardSchemata; 5 | import org.rcsb.cif.schema.mm.MmCifFile; 6 | import org.rcsb.strucmotif.config.StrucmotifConfig; 7 | import org.rcsb.strucmotif.io.DefaultResidueTypeResolver; 8 | import org.rcsb.strucmotif.io.DefaultStructureWriter; 9 | import org.rcsb.strucmotif.io.StructureWriter; 10 | 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.UncheckedIOException; 14 | import java.net.URL; 15 | import java.nio.channels.Channels; 16 | import java.nio.channels.FileChannel; 17 | import java.nio.channels.ReadableByteChannel; 18 | import java.nio.file.Files; 19 | import java.nio.file.Path; 20 | import java.nio.file.Paths; 21 | import java.util.stream.Stream; 22 | 23 | public class UpdateTestData { 24 | private static final Path updateRoot; 25 | private static final StrucmotifConfig strucmotifConfig; 26 | private static final StructureWriter structureWriter; 27 | 28 | static { 29 | Path root = Paths.get(".").toAbsolutePath(); 30 | System.out.println("Project path: " + root); 31 | updateRoot = root.resolve("strucmotif-search-core/src/test/resources/"); 32 | System.out.println("Update root: " + updateRoot); 33 | strucmotifConfig = new StrucmotifConfig(); 34 | strucmotifConfig.setRootPath(updateRoot.toString()); 35 | structureWriter = new DefaultStructureWriter(new DefaultResidueTypeResolver(strucmotifConfig), strucmotifConfig); 36 | } 37 | 38 | public static void main(String[] args) throws IOException { 39 | updateOriginalBcif(updateRoot.resolve("orig")); 40 | updateRenumberedBcif(updateRoot.resolve("renum")); 41 | } 42 | 43 | private static void updateOriginalBcif(Path path) throws IOException { 44 | try (Stream paths = Files.list(path)) { 45 | paths.forEach(p -> { 46 | String fileName = p.getFileName().toString(); 47 | System.out.println("Updating original: " + fileName); 48 | download("https://models.rcsb.org/" + fileName, p); 49 | }); 50 | } 51 | } 52 | 53 | private static void updateRenumberedBcif(Path path) throws IOException { 54 | try (Stream paths = Files.list(path)) { 55 | paths.forEach(p -> { 56 | String fileName = p.getFileName().toString(); 57 | System.out.println("Updating renumbered: " + fileName); 58 | 59 | try { 60 | MmCifFile cif = CifIO.readFromURL(new URL("https://models.rcsb.org/" + fileName)).as(StandardSchemata.MMCIF); 61 | byte[] bytes = structureWriter.write(cif, 1); 62 | Files.write(p, bytes); 63 | } catch (IOException e) { 64 | throw new UncheckedIOException(e); 65 | } 66 | }); 67 | } 68 | } 69 | 70 | private static void download(String sourceUrl, Path dest) { 71 | try (ReadableByteChannel readableByteChannel = Channels.newChannel(new URL(sourceUrl).openStream()); 72 | FileOutputStream outputStream = new FileOutputStream(dest.toFile()); 73 | FileChannel outputChannel = outputStream.getChannel()) { 74 | outputChannel.transferFrom(readableByteChannel, 0, Long.MAX_VALUE); 75 | } catch (IOException e) { 76 | throw new UncheckedIOException(e); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/core/MotifDefinitionRegistryTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.core; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import org.rcsb.strucmotif.domain.motif.MotifDefinition; 6 | 7 | import java.util.Collection; 8 | import java.util.Set; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | class MotifDefinitionRegistryTest { 13 | private DefaultMotifDefinitionRegistry registry; 14 | 15 | @BeforeEach 16 | public void init() { 17 | this.registry = new DefaultMotifDefinitionRegistry(null); 18 | } 19 | 20 | @Test 21 | void afterRegistryInitialized_thenHardCodedAndDynamicMotifsAvailable() { 22 | Set motifDefinitions = registry.getMotifDefinitions(); 23 | assertTrue(motifDefinitions.contains(MotifDefinition.CHCH)); 24 | assertTrue(motifDefinitions.contains(MotifDefinition.CHH)); 25 | assertTrue(motifDefinitions.contains(MotifDefinition.GGGG)); 26 | assertTrue(motifDefinitions.contains(MotifDefinition.HDS)); 27 | assertTrue(motifDefinitions.contains(MotifDefinition.KDDDE)); 28 | assertTrue(motifDefinitions.contains(MotifDefinition.KDEEH)); 29 | assertTrue(motifDefinitions.contains(MotifDefinition.KDEEH_EXCHANGES)); 30 | assertTrue(motifDefinitions.stream().anyMatch(m -> m.getTitle().startsWith("NOS")), "NOS parsed from JSON missing"); 31 | assertTrue(motifDefinitions.size() > 7); 32 | 33 | assertTrue(motifDefinitions.stream() 34 | .map(MotifDefinition::getLabelSelections) 35 | .flatMap(Collection::stream) 36 | .allMatch(l -> l.labelAsymId() != null && l.structOperId() != null && l.labelSeqId() != 0), "Not all label-selections were parsed properly"); 37 | } 38 | 39 | @Test 40 | void whenRegistryCleared_thenIsEmpty() { 41 | registry.getMotifDefinitions().clear(); 42 | assertTrue(registry.getMotifDefinitions().isEmpty()); 43 | } 44 | } -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/domain/motif/ResiduePairOccurrenceTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.motif; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.rcsb.strucmotif.domain.structure.ResidueType; 5 | 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import static org.junit.jupiter.api.Assertions.*; 11 | 12 | class ResiduePairOccurrenceTest { 13 | @Test 14 | void whenStreamingDescriptorsWithExchanges_thenAllPresent() { 15 | // DD-5-4-4 -> 10-55 16 | ResiduePairOccurrence occurrence = new ResiduePairOccurrence(42949673015L, 8522308); 17 | Map> exchanges = Map.of(10, Set.of(ResidueType.GLUTAMIC_ACID, ResidueType.ASPARTIC_ACID)); 18 | 19 | List out = occurrence.residuePairDescriptorsByTolerance(1, 1, 1, exchanges) 20 | .boxed() 21 | .toList(); 22 | 23 | assertEquals(out.stream().distinct().count(), out.size(), "There are duplicates"); 24 | assertEquals(2, out.stream().map(ResiduePairDescriptor::getResidueType2).distinct().count(), "Didn't observe exchange"); 25 | } 26 | } -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/domain/query/ResultsContentTypeTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.query; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import java.util.Set; 6 | 7 | import static org.junit.jupiter.api.Assertions.*; 8 | 9 | class ResultsContentTypeTest { 10 | private static final Set TEST_CASES = Set.of("1acj", "1MUW", "1eXr", "AF-Q8W3K0-F1", "ma-bak-cepc-0001"); 11 | 12 | @Test 13 | void whenHandlingPdbIds_thenArchiveEntriesRetained() { 14 | assertEquals(3, TEST_CASES.stream() 15 | .filter(ResultsContentType.EXPERIMENTAL) 16 | .count()); 17 | } 18 | 19 | @Test 20 | void whenHandlingModelIds_thenArchiveEntriesIgnored() { 21 | assertEquals(2, TEST_CASES.stream() 22 | .filter(ResultsContentType.COMPUTATIONAL) 23 | .count()); 24 | } 25 | 26 | @Test 27 | void whenAllSearchSpace_thenNoOperation() { 28 | assertEquals(TEST_CASES.size(), TEST_CASES.stream() 29 | .filter(ResultsContentType.EXPERIMENTAL.or(ResultsContentType.COMPUTATIONAL)) 30 | .count()); 31 | } 32 | } -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/domain/structure/OffsetArrayIndexOfTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.domain.structure; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class OffsetArrayIndexOfTest { 8 | private static final int[] TEST_DATA = new int[] { 0, 25, 50, 60, 70, 80, 90, 100, 200, 250, 400 }; 9 | 10 | @Test 11 | void whenElementAtStart_thenFirstIndexReturned() { 12 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 0); 13 | assertEquals(0, i); 14 | } 15 | 16 | @Test 17 | void whenElementPastStart_thenFirstIndexReturned() { 18 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 1); 19 | assertEquals(0, i); 20 | } 21 | 22 | @Test 23 | void whenElementBeforeOffset_thenFirstIndexReturned() { 24 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 24); 25 | assertEquals(0, i); 26 | } 27 | 28 | @Test 29 | void whenElementAtOffset_thenSecondIndexReturned() { 30 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 25); 31 | assertEquals(1, i); 32 | } 33 | 34 | @Test 35 | void whenElementBeforePenultimateOffset_thenAntepenultimateIndexReturned() { 36 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 249); 37 | assertEquals(8, i); 38 | } 39 | 40 | @Test 41 | void whenElementAtPenultimateOffset_thenPenultimateIndexReturned() { 42 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 250); 43 | assertEquals(9, i); 44 | } 45 | 46 | @Test 47 | void whenElementBeforeLastOffset_thenPenultimateIndexReturned() { 48 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 399); 49 | assertEquals(9, i); 50 | } 51 | 52 | @Test 53 | void whenElementAtLastOffset_thenLastIndexReturned() { 54 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 400); 55 | assertEquals(10, i); 56 | } 57 | 58 | @Test 59 | void whenElementAfterLastOffset_thenLastIndexReturned() { 60 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, 401); 61 | assertEquals(10, i); 62 | } 63 | 64 | @Test 65 | void whenNegativeInput_thenMinus1Returned() { 66 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, -1); 67 | assertEquals(-1, i); 68 | } 69 | 70 | @Test 71 | void whenAboveHighestValue_thenLastIndexReturned() { 72 | int i = DefaultStructure.offsetArrayIndexOf(TEST_DATA, Integer.MAX_VALUE); 73 | assertEquals(TEST_DATA.length - 1, i); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/java/org/rcsb/strucmotif/io/DefaultInvertedIndexTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.io; 2 | 3 | import org.junit.jupiter.api.BeforeEach; 4 | import org.junit.jupiter.api.Test; 5 | import org.rcsb.ffindex.FileBundleIO; 6 | import org.rcsb.ffindex.ReadableFileBundle; 7 | import org.rcsb.strucmotif.Helpers; 8 | import org.rcsb.strucmotif.config.StrucmotifConfig; 9 | import org.rcsb.strucmotif.domain.bucket.ArrayBucket; 10 | import org.rcsb.strucmotif.domain.motif.AngleType; 11 | import org.rcsb.strucmotif.domain.motif.DistanceType; 12 | import org.rcsb.strucmotif.domain.motif.ResiduePairDescriptor; 13 | import org.rcsb.strucmotif.domain.structure.ResidueType; 14 | import org.rcsb.strucmotif.io.codec.ColferCodec; 15 | 16 | import java.io.IOException; 17 | import java.io.UncheckedIOException; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 20 | import static org.junit.jupiter.api.Assertions.assertEquals; 21 | 22 | class DefaultInvertedIndexTest { 23 | private InvertedIndex invertedIndex; 24 | 25 | @BeforeEach 26 | public void init() throws IOException { 27 | StrucmotifConfig strucmotifConfig = new StrucmotifConfig(); 28 | ReadableFileBundle fileBundle = FileBundleIO.openBundle(Helpers.getResourceAsPath("index.data"), Helpers.getResourceAsPath("index.ffindex")).inReadOnlyMode(); 29 | ColferCodec bucketCodec = new ColferCodec(); 30 | invertedIndex = new DefaultInvertedIndex(strucmotifConfig) { 31 | @Override 32 | public ArrayBucket select(int residuePairDescriptor) { 33 | String filename = residuePairDescriptor + ".colf"; 34 | if (!fileBundle.containsFile(filename)) { 35 | return ArrayBucket.EMPTY_BUCKET; 36 | } 37 | 38 | try { 39 | return bucketCodec.decode(fileBundle.readFile(filename)); 40 | } catch (IOException e) { 41 | throw new UncheckedIOException(e); 42 | } 43 | } 44 | }; 45 | } 46 | 47 | private static final int BIN_WITH_ASSEMBLY = ResiduePairDescriptor.encodeDescriptor(ResidueType.ASPARTIC_ACID, 48 | ResidueType.LYSINE, 49 | DistanceType.D6, 50 | DistanceType.D7, 51 | AngleType.A80); 52 | @Test 53 | void whenAccessingSpecificBin_thenObserveAssemblies() { 54 | ArrayBucket bucket = invertedIndex.select(BIN_WITH_ASSEMBLY); 55 | int structures = 0; 56 | int occurrences = 0; 57 | while (bucket.hasNextStructure()) { 58 | bucket.moveStructure(); 59 | structures++; 60 | while (bucket.hasNextOccurrence()) { 61 | bucket.moveOccurrence(); 62 | occurrences++; 63 | } 64 | } 65 | assertEquals(13, structures); 66 | assertEquals(241, occurrences); 67 | } 68 | 69 | @Test 70 | void whenSelectingByFlippedDescriptor_thenContentMatchesOriginal() { 71 | ArrayBucket original = invertedIndex.select(BIN_WITH_ASSEMBLY); 72 | ArrayBucket flipped = invertedIndex.select(BIN_WITH_ASSEMBLY & ~(1 << 28)); 73 | assertArrayEquals(original.getStructureIndexArray(), flipped.getStructureIndexArray()); 74 | assertArrayEquals(original.getPositionOffsetArray(), flipped.getPositionOffsetArray()); 75 | assertArrayEquals(original.getIdentifierDataArray(), flipped.getIdentifierDataArray()); 76 | } 77 | } -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/index.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/index.data -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/known.list: -------------------------------------------------------------------------------- 1 | 3CXO,21,1,1 2 | 4X2P,53,1,4 3 | 4H19,73,1,0 4 | 3FXG,10,1,3 5 | 3EKG,70,1,3 6 | 2QGY,84,1,5 7 | 4M6U,23,1,3 8 | 4KEM,39,1,0 9 | 2PP0,19,1,1 10 | 3UXK,31,1,1 11 | 5OLC,59,1,0 12 | 2OO6,41,1,5 13 | 3SN0,54,1,3 14 | 3VCC,27,1,0 15 | 4H83,32,1,1 16 | 3CYJ,36,1,4 17 | 1ZDM,9,1,2 18 | 6VIM,72,1,2 19 | 3N4F,30,1,4 20 | 1MDR,35,1,3 21 | 4JN7,11,1,0 22 | 4FP1,1,1,4 23 | 2OG9,89,1,3 24 | 4IP5,76,1,0 25 | 2DW7,61,1,2 26 | 2PP3,22,1,2 27 | 3T8Q,58,1,1 28 | 3P3B,8,1,3 29 | 4HPN,13,1,1 30 | 2HZG,24,1,5 31 | 2P3Z,34,1,6 32 | 2NQL,15,1,4 33 | 3NO1,86,1,2 34 | 2GGE,3,1,5 35 | 4GGB,14,1,2 36 | 3CK5,56,1,2 37 | 2MNR,87,1,6 38 | 4H1Z,40,1,0 39 | 1DTN,17,1,3 40 | 2OVL,48,1,3 41 | 3TJ4,69,1,2 42 | 2HXU,92,2,1 43 | 3OZY,51,1,0 44 | 2HXT,29,1,2 45 | 4HNC,16,1,4 46 | 1MRA,65,1,3 47 | 2HNE,75,1,4 48 | 3TTE,2,1,1 49 | 2QQ6,63,1,2 50 | 3MSY,55,1,2 51 | 3V5F,68,1,0 52 | 3T9P,20,1,0 53 | 3H12,62,1,5 54 | 4IP4,88,1,0 55 | 1YEY,6,1,3 56 | 3SN4,47,1,2 57 | 2GSH,95,1,5 58 | 2P0I,64,1,5 59 | 3OP2,33,1,3 60 | 2PPG,91,1,5 61 | 2I5Q,37,1,5 62 | 6TNE,83,2,0 63 | 3TCS,77,1,0 64 | 3TOY,82,1,1 65 | 3SN1,18,1,2 66 | 3V5C,43,1,0 67 | 5XD8,52,1,0 68 | 3SJN,71,1,3 69 | 3D46,0,1,3 70 | 3CB3,94,1,2 71 | 2OZ3,25,1,5 72 | 4DN1,45,1,1 73 | 3OPS,42,1,3 74 | 5XD7,81,1,0 75 | 4A35,60,1,2 76 | 1MNS,50,1,2 77 | 4DWD,5,1,3 78 | 4JN8,80,1,0 79 | 3UGV,12,1,1 80 | 3UXL,28,1,1 81 | 3BOX,90,1,3 82 | 2PP1,93,1,1 83 | 3BJS,38,1,4 84 | 3U4F,4,1,0 85 | 3N4E,7,1,4 86 | 3RRA,79,1,1 87 | 3D47,66,1,3 88 | 2DW6,26,1,3 89 | 1MDL,74,1,4 90 | 3RR1,85,1,1 91 | 2GDQ,46,1,5 92 | 1TZZ,49,1,3 93 | 3OZM,44,1,0 94 | 3QPE,57,2,0 95 | 3GO2,67,1,4 96 | 2POZ,78,1,3 97 | -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1acj.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1acj.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1c3c.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1c3c.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1ec6.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1ec6.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1eta.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1eta.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1exr.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1exr.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1ezc.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1ezc.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1g2f.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1g2f.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1kp0.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1kp0.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1lap.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1lap.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1m4x.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1m4x.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1nmr.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1nmr.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1qd6.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1qd6.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1w27.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1w27.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/1zdm.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/1zdm.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/200l.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/200l.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/2bfu.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/2bfu.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/2bwx.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/2bwx.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/2mnr.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/2mnr.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/3djy.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/3djy.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/3ibk.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/3ibk.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/3pei.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/3pei.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/3uud.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/3uud.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/4cha.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/4cha.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/4oog.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/4oog.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/6lxk.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/6lxk.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/6tne.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/6tne.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/6zwf.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/6zwf.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/7a3x.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/7a3x.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/7els.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/7els.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/orig/AF_AFA0A0R0FWM3F1.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/orig/AF_AFA0A0R0FWM3F1.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1DTN.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1DTN.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1MDL.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1MDL.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1MDR.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1MDR.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1MNS.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1MNS.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1MRA.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1MRA.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1TZZ.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1TZZ.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1YEY.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1YEY.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1ZDM.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1ZDM.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1acj.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1acj.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1dsd.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1dsd.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1eta.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1eta.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1exr.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1exr.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/1m4x.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/1m4x.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/200l.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/200l.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2DW6.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2DW6.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2DW7.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2DW7.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2GDQ.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2GDQ.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2GGE.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2GGE.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2GSH.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2GSH.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2HNE.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2HNE.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2HXT.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2HXT.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2HXU.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2HXU.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2HZG.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2HZG.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2I5Q.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2I5Q.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2MNR.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2MNR.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2NQL.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2NQL.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2OG9.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2OG9.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2OO6.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2OO6.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2OVL.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2OVL.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2OZ3.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2OZ3.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2P0I.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2P0I.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2P3Z.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2P3Z.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2POZ.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2POZ.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2PP0.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2PP0.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2PP1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2PP1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2PP3.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2PP3.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2PPG.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2PPG.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2QGY.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2QGY.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2QQ6.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2QQ6.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2bfu.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2bfu.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/2bwx.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/2bwx.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3BJS.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3BJS.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3BOX.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3BOX.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3CB3.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3CB3.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3CK5.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3CK5.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3CXO.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3CXO.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3CYJ.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3CYJ.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3D46.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3D46.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3D47.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3D47.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3EKG.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3EKG.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3FXG.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3FXG.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3GO2.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3GO2.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3H12.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3H12.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3MSY.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3MSY.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3N4E.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3N4E.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3N4F.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3N4F.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3NO1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3NO1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3OP2.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3OP2.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3OPS.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3OPS.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3OZM.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3OZM.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3OZY.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3OZY.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3P3B.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3P3B.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3QPE.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3QPE.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3RR1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3RR1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3RRA.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3RRA.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3SJN.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3SJN.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3SN0.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3SN0.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3SN1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3SN1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3SN4.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3SN4.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3T8Q.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3T8Q.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3T9P.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3T9P.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3TCS.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3TCS.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3TJ4.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3TJ4.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3TOY.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3TOY.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3TTE.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3TTE.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3U4F.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3U4F.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3UGV.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3UGV.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3UXK.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3UXK.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3UXL.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3UXL.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3V5C.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3V5C.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3V5F.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3V5F.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3VCC.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3VCC.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3uud.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3uud.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3vk6.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3vk6.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/3vvk.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/3vvk.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4A35.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4A35.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4DN1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4DN1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4DWD.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4DWD.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4FP1.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4FP1.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4GGB.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4GGB.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4H19.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4H19.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4H1Z.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4H1Z.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4H83.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4H83.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4HNC.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4HNC.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4HPN.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4HPN.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4IP4.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4IP4.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4IP5.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4IP5.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4JN7.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4JN7.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4JN8.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4JN8.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4KEM.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4KEM.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4M6U.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4M6U.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4X2P.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4X2P.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4cha.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4cha.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/4ob8.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/4ob8.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/5OLC.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/5OLC.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/5XD7.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/5XD7.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/5XD8.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/5XD8.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/5ire.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/5ire.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/6TNE.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/6TNE.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/6VIM.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/6VIM.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renum/6j6q.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renum/6j6q.bcif -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renumbered.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-core/src/test/resources/renumbered.data -------------------------------------------------------------------------------- /strucmotif-search-core/src/test/resources/renumbered.ffindex: -------------------------------------------------------------------------------- 1 | 1ZDM.bcif.gz 0 6097 2 | 4JN7.bcif.gz 6097 10102 3 | 3N4E.bcif.gz 16199 15029 4 | 3P3B.bcif.gz 31228 15498 5 | 4FP1.bcif.gz 46726 14823 6 | 4DWD.bcif.gz 61549 15153 7 | 3TTE.bcif.gz 76702 14670 8 | 3U4F.bcif.gz 91372 27400 9 | 1YEY.bcif.gz 118772 31499 10 | 4HPN.bcif.gz 150271 9589 11 | 2GGE.bcif.gz 159860 53335 12 | 4GGB.bcif.gz 213195 8993 13 | 3D46.bcif.gz 222188 56334 14 | 3UGV.bcif.gz 278522 50431 15 | 3FXG.bcif.gz 328953 55748 16 | 2NQL.bcif.gz 384701 16232 17 | 1DTN.bcif.gz 400933 9029 18 | 4HNC.bcif.gz 409962 14842 19 | 3SN1.bcif.gz 424804 10062 20 | 2PP0.bcif.gz 434866 23148 21 | 3T9P.bcif.gz 458014 15058 22 | 3CXO.bcif.gz 473072 16613 23 | 2HXT.bcif.gz 489685 10565 24 | 4M6U.bcif.gz 500250 14878 25 | 2HZG.bcif.gz 515128 15555 26 | 3VCC.bcif.gz 530683 16069 27 | 2PP3.bcif.gz 546752 23155 28 | 2DW6.bcif.gz 569907 28238 29 | 3UXL.bcif.gz 598145 26337 30 | 3N4F.bcif.gz 624482 28323 31 | 3UXK.bcif.gz 652805 25680 32 | 1MDR.bcif.gz 678485 9037 33 | 3OP2.bcif.gz 687522 15343 34 | 2P3Z.bcif.gz 702865 16822 35 | 4H83.bcif.gz 719687 38778 36 | 2I5Q.bcif.gz 758465 16101 37 | 2OZ3.bcif.gz 774566 54879 38 | 3CYJ.bcif.gz 829445 25714 39 | 3BJS.bcif.gz 855159 15389 40 | 4KEM.bcif.gz 870548 15840 41 | 2OO6.bcif.gz 886388 10017 42 | 4DN1.bcif.gz 896405 15937 43 | 2GDQ.bcif.gz 912342 15925 44 | 3SN4.bcif.gz 928267 10036 45 | 3OPS.bcif.gz 938303 28508 46 | 3V5C.bcif.gz 966811 28128 47 | 1TZZ.bcif.gz 994939 15381 48 | 1MNS.bcif.gz 1010320 9036 49 | 2OVL.bcif.gz 1019356 26092 50 | 4X2P.bcif.gz 1045448 9068 51 | 4H1Z.bcif.gz 1054516 52171 52 | 3SN0.bcif.gz 1106687 10172 53 | 5XD8.bcif.gz 1116859 15078 54 | 3OZY.bcif.gz 1131937 15893 55 | 3OZM.bcif.gz 1147830 53157 56 | 4A35.bcif.gz 1200987 10985 57 | 3T8Q.bcif.gz 1211972 15299 58 | 3CK5.bcif.gz 1227271 26097 59 | 3QPE.bcif.gz 1253368 28106 60 | 3H12.bcif.gz 1281474 16294 61 | 3MSY.bcif.gz 1297768 37637 62 | 2QQ6.bcif.gz 1335405 16058 63 | 1MRA.bcif.gz 1351463 9031 64 | 5OLC.bcif.gz 1360494 49238 65 | 3GO2.bcif.gz 1409732 9884 66 | 3V5F.bcif.gz 1419616 9523 67 | 3TJ4.bcif.gz 1429139 15301 68 | 3SJN.bcif.gz 1444440 15653 69 | 3EKG.bcif.gz 1460093 16443 70 | 1MDL.bcif.gz 1476536 8992 71 | 2P0I.bcif.gz 1485528 54422 72 | 4IP5.bcif.gz 1539950 17284 73 | 3D47.bcif.gz 1557234 56385 74 | 3TCS.bcif.gz 1613619 15455 75 | 2HNE.bcif.gz 1629074 31442 76 | 5XD7.bcif.gz 1660516 9087 77 | 6TNE.bcif.gz 1669603 3444 78 | 3RRA.bcif.gz 1673047 15698 79 | 4JN8.bcif.gz 1688745 9979 80 | 6VIM.bcif.gz 1698724 118853 81 | 2QGY.bcif.gz 1817577 15888 82 | 2MNR.bcif.gz 1833465 9026 83 | 3RR1.bcif.gz 1842491 15633 84 | 2DW7.bcif.gz 1858124 102426 85 | 3TOY.bcif.gz 1960550 26189 86 | 4IP4.bcif.gz 1986739 17284 87 | 2OG9.bcif.gz 2004023 14692 88 | 2POZ.bcif.gz 2018715 51584 89 | 3BOX.bcif.gz 2070299 16626 90 | 2HXU.bcif.gz 2086925 10566 91 | 3NO1.bcif.gz 2097491 37798 92 | 2PPG.bcif.gz 2135289 27877 93 | 2PP1.bcif.gz 2163166 40061 94 | 4H19.bcif.gz 2203227 99555 95 | 3CB3.bcif.gz 2302782 26672 96 | 2GSH.bcif.gz 2329454 13929 97 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/Context.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update; 2 | 3 | import org.rcsb.strucmotif.config.StrucmotifConfig; 4 | import org.rcsb.strucmotif.domain.motif.ResiduePairDescriptor; 5 | import org.rcsb.strucmotif.domain.structure.StructureInformation; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.BufferedOutputStream; 10 | import java.io.Closeable; 11 | import java.io.FileOutputStream; 12 | import java.io.Flushable; 13 | import java.io.IOException; 14 | import java.io.OutputStream; 15 | import java.nio.file.Files; 16 | import java.nio.file.Path; 17 | import java.nio.file.Paths; 18 | import java.util.*; 19 | import java.util.concurrent.CopyOnWriteArrayList; 20 | import java.util.concurrent.atomic.AtomicInteger; 21 | 22 | /** 23 | * Captures global state of the update process. 24 | */ 25 | public class Context implements Closeable, Flushable { 26 | private static final Logger logger = LoggerFactory.getLogger(Context.class); 27 | private static final int BUFFER_SIZE = 65536; 28 | private final String rootPath; 29 | final List updateItems; 30 | final Set processed; 31 | int partitionSize; 32 | String partitionContext; 33 | private final Map outputStreams; 34 | private final List outputPaths; 35 | AtomicInteger structureCounter; 36 | 37 | /** 38 | * Construct a new update context. 39 | * @param strucmotifConfig global config 40 | * @param updateItems update list 41 | */ 42 | public Context(StrucmotifConfig strucmotifConfig, List updateItems) { 43 | this.rootPath = strucmotifConfig.getRootPath(); 44 | this.updateItems = updateItems; 45 | this.processed = Collections.synchronizedSet(new HashSet<>()); 46 | this.outputStreams = Collections.synchronizedMap(new HashMap<>()); 47 | this.outputPaths = new CopyOnWriteArrayList<>(); 48 | } 49 | 50 | private String getPrefix(int descriptor) { 51 | return ResiduePairDescriptor.getResidueType1(descriptor).getInternalCode() + ResiduePairDescriptor.getResidueType2(descriptor).getInternalCode(); 52 | } 53 | 54 | /** 55 | * Get an output stream that a thread can use to dump data. 56 | * @param descriptor the descriptor to write 57 | * @return a new or previously created output stream that is specific to this thread 58 | * @throws IOException IO operation failed 59 | */ 60 | public OutputStream getOutputStream(int descriptor) throws IOException { 61 | String key = Thread.currentThread().getId() + "-" + getPrefix(descriptor); 62 | OutputStream ref = outputStreams.get(key); 63 | if (ref != null) { 64 | return ref; 65 | } 66 | 67 | Path path = Paths.get(rootPath).resolve(StrucmotifConfig.INDEX + "." + key + StrucmotifConfig.TMP_EXT); 68 | logger.debug("Creating thread-specific index dump at {}", path); 69 | ref = new BufferedOutputStream(new FileOutputStream(path.toFile()), BUFFER_SIZE); 70 | outputStreams.put(key, ref); 71 | outputPaths.add(path); 72 | return ref; 73 | } 74 | 75 | @Override 76 | public void flush() throws IOException { 77 | for (OutputStream stream : outputStreams.values()) { 78 | stream.flush(); 79 | } 80 | } 81 | 82 | @Override 83 | public void close() throws IOException { 84 | logger.info("Closing thread-specific index dumps"); 85 | for (OutputStream stream : outputStreams.values()) { 86 | stream.close(); 87 | } 88 | outputStreams.clear(); 89 | for (Path path : outputPaths) { 90 | Files.deleteIfExists(path); 91 | } 92 | outputPaths.clear(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/Operation.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update; 2 | 3 | import java.util.Arrays; 4 | import java.util.NoSuchElementException; 5 | 6 | /** 7 | * The possible operations during a strucmotif update ('ADD' structures, 'REMOVE' structures, 'RECOVER'). 8 | */ 9 | public enum Operation { 10 | /** 11 | * Add structures. 12 | */ 13 | ADD, 14 | /** 15 | * Remove structures. 16 | */ 17 | REMOVE, 18 | /** 19 | * Try to recover - this is used when the JVM dies while manipulating the inverted index. 20 | */ 21 | RECOVER; 22 | 23 | /** 24 | * Map from string to Operation enum. 25 | * @param s the name 26 | * @return the corresponding enum entry 27 | */ 28 | public static Operation resolve(String s) { 29 | String uc = s.toUpperCase(); 30 | return Arrays.stream(Operation.values()) 31 | .filter(e -> e.name().equals(uc)) 32 | .findFirst() 33 | .orElseThrow(() -> new NoSuchElementException("Unrecognized Operation: " + s + " - options are: " + Arrays.toString(Operation.values()))); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/UpdateItem.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update; 2 | 3 | import org.rcsb.strucmotif.io.StructureDataProvider; 4 | 5 | import java.net.URL; 6 | 7 | /** 8 | * One piece of the update. Usually just references a PDB entry.

9 | * Can also point to external resources or local files via a URL. In that case, you must make sure to provide a unique 10 | * structureIdentifier. 11 | */ 12 | public class UpdateItem { 13 | private final String structureIdentifier; 14 | private final URL url; 15 | private final int modelIdentifier; 16 | 17 | /** 18 | * Update by PDB-ID. 19 | * @param structureIdentifier a PDB entry ID 20 | */ 21 | public UpdateItem(String structureIdentifier) { 22 | this(structureIdentifier, null, StructureDataProvider.DEFAULT_MODEL_IDENTIFIER); 23 | } 24 | 25 | /** 26 | * Update a specific model of a PDB-ID. 27 | * @param structureIdentifier a PDB entry ID 28 | */ 29 | public UpdateItem(String structureIdentifier, int modelIdentifier) { 30 | this(structureIdentifier, null, modelIdentifier); 31 | } 32 | 33 | /** 34 | * Update by identifier and external URL. 35 | * @param structureIdentifier the unique ID this item will have 36 | * @param url data source pointing to non-PDB structures, either by URL to some external resource or to a local file 37 | */ 38 | public UpdateItem(String structureIdentifier, URL url) { 39 | this(structureIdentifier, url, StructureDataProvider.DEFAULT_MODEL_IDENTIFIER); 40 | } 41 | 42 | /** 43 | * Update by identifier and external URL, while being model-aware. 44 | * @param structureIdentifier the unique ID this item will have 45 | * @param url data source pointing to non-PDB structures, either by URL to some external resource or to a local file 46 | * @param modelIdentifier int value of the model to index 47 | */ 48 | public UpdateItem(String structureIdentifier, URL url, int modelIdentifier) { 49 | this.structureIdentifier = structureIdentifier; 50 | this.url = url; 51 | this.modelIdentifier = modelIdentifier; 52 | } 53 | 54 | /** 55 | * Get the key with which this item will be registered. 56 | * @return a String, usually a PDB-ID or some compact identifier 57 | */ 58 | public String getStructureIdentifier() { 59 | return structureIdentifier; 60 | } 61 | 62 | /** 63 | * Get the resource URL to load. 64 | * @return the URL to load, or null if referencing a PDB entry 65 | */ 66 | public URL getUrl() { 67 | return url; 68 | } 69 | 70 | /** 71 | * Which model to index? 72 | * @return an int (usually, 1) 73 | */ 74 | public int getModelIdentifier() { 75 | return modelIdentifier; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/extractor/AlphaFoldKeyExtractor.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | /** 4 | * Handles files from the AlphaFoldDB. 5 | */ 6 | public class AlphaFoldKeyExtractor implements KeyExtractor { 7 | private static final String NAMESPACE = "AF-"; 8 | 9 | /** 10 | * Default constructor. 11 | */ 12 | public AlphaFoldKeyExtractor() { 13 | } 14 | 15 | @Override 16 | public String getNameSpace() { 17 | return NAMESPACE; 18 | } 19 | 20 | @Override 21 | public String getKey(String resource) { 22 | // https://alphafold.ebi.ac.uk/files/AF-Q76EI6-F1-model_v1.cif -> AF-Q76EI6-F1 23 | String name = resource.contains("/") ? resource.substring(resource.lastIndexOf("/") + 1) : resource; 24 | return name.replaceAll("(?i)-model_v\\d+\\.b?cif(?:\\.gz)?", "").toUpperCase(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/extractor/GenericKeyExtractor.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | /** 4 | * Fallback strategy of extracting keys: use file name. 5 | */ 6 | public class GenericKeyExtractor implements KeyExtractor { 7 | private static final String NAMESPACE = ""; 8 | 9 | /** 10 | * Default constructor. 11 | */ 12 | public GenericKeyExtractor() { 13 | } 14 | 15 | @Override 16 | public String getNameSpace() { 17 | return NAMESPACE; 18 | } 19 | 20 | @Override 21 | public String getKey(String resource) { 22 | // /path/to/1abc.cif -> 1ABC 23 | String name = resource.contains("/") ? resource.substring(resource.lastIndexOf("/") + 1) : resource; 24 | return name.replaceAll("(?i)\\.b?cif(?:\\.gz)?", "").toUpperCase(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/extractor/KeyExtractor.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | import java.nio.file.Path; 4 | 5 | /** 6 | * Converts {@link Path} instances to a (hopefully) unique key. 7 | */ 8 | public interface KeyExtractor { 9 | /** 10 | * The expected namespace prefix used by this data-source. 11 | * @return a String which can be empty 12 | */ 13 | String getNameSpace(); 14 | 15 | /** 16 | * Extract the key of this path or URL. The input will be processed in a case-insensitive manner, the output will be 17 | * upper-case. 18 | * @param resource the path/URL to process 19 | * @return a key 20 | */ 21 | String getKey(String resource); 22 | } 23 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/extractor/KeyExtractorFactory.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Finds an appropriate key extractor. 7 | */ 8 | public class KeyExtractorFactory { 9 | private final List nonGeneric; 10 | private final GenericKeyExtractor generic; 11 | private static final KeyExtractorFactory INSTANCE = new KeyExtractorFactory(); 12 | 13 | private KeyExtractorFactory() { 14 | nonGeneric = List.of(new AlphaFoldKeyExtractor(), new ModelArchiveKeyExtractor()); 15 | generic = new GenericKeyExtractor(); 16 | } 17 | 18 | /** 19 | * Determine the key extractor for this resource. 20 | * @param resource the resource 21 | * @return a {@link KeyExtractor} that supports this namespace, the generic implementation if none matches 22 | */ 23 | public static KeyExtractor getKeyExtractor(String resource) { 24 | String name = resource.contains("/") ? resource.substring(resource.lastIndexOf("/") + 1) : resource; 25 | String upperCase = name.toUpperCase(); 26 | for (KeyExtractor keyExtractor : INSTANCE.nonGeneric) { 27 | if (upperCase.startsWith(keyExtractor.getNameSpace())) { 28 | return keyExtractor; 29 | } 30 | } 31 | return INSTANCE.generic; 32 | } 33 | 34 | /** 35 | * Short-cut to extract keys. 36 | * @param resource the resource 37 | * @return the extracted key 38 | */ 39 | public static String getKey(String resource) { 40 | return getKeyExtractor(resource).getKey(resource); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/main/java/org/rcsb/strucmotif/update/extractor/ModelArchiveKeyExtractor.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | /** 4 | * Handles files from the ModelArchive. 5 | */ 6 | public class ModelArchiveKeyExtractor implements KeyExtractor { 7 | private static final String NAMESPACE = "MA-"; 8 | 9 | /** 10 | * Default constructor. 11 | */ 12 | public ModelArchiveKeyExtractor() { 13 | } 14 | 15 | @Override 16 | public String getNameSpace() { 17 | return NAMESPACE; 18 | } 19 | 20 | @Override 21 | public String getKey(String resource) { 22 | // /path/to/ma-9z55z.cif -> MA-9Z55Z 23 | String name = resource.contains("/") ? resource.substring(resource.lastIndexOf("/") + 1) : resource; 24 | return name.replaceAll("(?i)\\.b?cif(?:\\.gz)?", "").toUpperCase(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/java/org/rcsb/strucmotif/update/Demo.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update; 2 | 3 | class Demo { 4 | public static void main(String[] args) { 5 | // perform a full load of all structures in RCSB PDB with default configuration 6 | // use 'full_csm' to also fetch all computed structure models integrated into RCSB.org (~200k experimentally-determined structures, ~1M CSMs) 7 | StrucmotifUpdate.main(new String[] { "ADD", "full" }); 8 | 9 | // load some arbitrary (external) structure data like AlphaFold models 10 | StrucmotifUpdate.main(new String[] { 11 | "ADD", 12 | "AF-Q76EI6-F1,https://alphafold.ebi.ac.uk/files/AF-Q76EI6-F1-model_v4.cif", 13 | "ma-bak-cepc-0886,https://www.modelarchive.org/api/projects/ma-bak-cepc-0886?type=basic__model_file_name", 14 | }); 15 | } 16 | } -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/java/org/rcsb/strucmotif/update/TestCases.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update; 2 | 3 | import java.io.InputStream; 4 | import java.util.Arrays; 5 | import java.util.NoSuchElementException; 6 | 7 | /** 8 | * Some small structures and their expected properties when processed by the update routine. 9 | */ 10 | enum TestCases { 11 | PDB_2RLL("2RLL.cif.gz"), 12 | PDB_3ULN("3uln.cif.gz"), 13 | PDB_3UM4("3UM4.cif"), 14 | PDB_4TUT("4TUT.bcif.gz"), 15 | PDB_5XES("5xes.bcif"), 16 | PDB_6FCE("6fce.cif"), 17 | AF_A0A0R0FWM3("af_afa0a0r0fwm3f1.bcif"), // helix, fragmented 18 | AF_Q8SY76("af_afq8sy76f1.bcif"); // helix 19 | 20 | private final String filename; 21 | private final String key; 22 | 23 | TestCases(String name) { 24 | this.filename = name; 25 | this.key = filename.split("\\.")[0].replace("-model_v1", ""); 26 | } 27 | 28 | public String getFilename() { 29 | return filename; 30 | } 31 | 32 | public String getKey() { 33 | return key; 34 | } 35 | 36 | public InputStream getInputStream() { 37 | return Thread.currentThread().getContextClassLoader().getResourceAsStream(this.filename); 38 | } 39 | 40 | public static InputStream getInputStream(String key) { 41 | return Arrays.stream(TestCases.values()) 42 | .filter(t -> t.getKey().equalsIgnoreCase(key)) 43 | .findFirst() 44 | .map(TestCases::getInputStream) 45 | .orElseThrow(() -> new NoSuchElementException("Couldn't find resource for case '" + key + "'")); 46 | } 47 | 48 | public String getExpression() { 49 | if (filename.equalsIgnoreCase(key)) { 50 | return key; 51 | } else { 52 | return key + ",https://rcsb.org"; // any URL works here 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/java/org/rcsb/strucmotif/update/extractor/KeyExtractorFactoryTest.java: -------------------------------------------------------------------------------- 1 | package org.rcsb.strucmotif.update.extractor; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.*; 6 | 7 | class KeyExtractorFactoryTest { 8 | @Test 9 | public void whenRequestingExtractor_thenCorrectOnesReturned() { 10 | KeyExtractor extractor1 = KeyExtractorFactory.getKeyExtractor("AF-Q76EI6-F1-model_v1.cif"); 11 | assertInstanceOf(AlphaFoldKeyExtractor.class, extractor1); 12 | 13 | KeyExtractor extractor2 = KeyExtractorFactory.getKeyExtractor("/path/to/ma-9z55z.cif"); 14 | assertInstanceOf(ModelArchiveKeyExtractor.class, extractor2); 15 | 16 | KeyExtractor extractor3 = KeyExtractorFactory.getKeyExtractor("/1acj.cif"); 17 | assertInstanceOf(GenericKeyExtractor.class, extractor3); 18 | 19 | KeyExtractor extractor4 = KeyExtractorFactory.getKeyExtractor("/"); 20 | assertInstanceOf(GenericKeyExtractor.class, extractor4); 21 | 22 | KeyExtractor extractor5 = KeyExtractorFactory.getKeyExtractor(""); 23 | assertInstanceOf(GenericKeyExtractor.class, extractor5); 24 | } 25 | 26 | @Test 27 | public void whenExtractingKeys_thenCorrectOnesReturned() { 28 | String key1 = KeyExtractorFactory.getKey("AF-Q76EI6-F1-model_v1.cif"); 29 | assertEquals("AF-Q76EI6-F1", key1); 30 | 31 | String key2 = KeyExtractorFactory.getKey("/path/to/ma-9z55z.cif"); 32 | assertEquals("MA-9Z55Z", key2); 33 | 34 | String key3 = KeyExtractorFactory.getKey("/1acj.cif"); 35 | assertEquals("1ACJ", key3); 36 | } 37 | } -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/2RLL.cif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/2RLL.cif.gz -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/3uln.cif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/3uln.cif.gz -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/4TUT.bcif.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/4TUT.bcif.gz -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/5xes.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/5xes.bcif -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/af_afa0a0r0fwm3f1.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/af_afa0a0r0fwm3f1.bcif -------------------------------------------------------------------------------- /strucmotif-search-update/src/test/resources/af_afq8sy76f1.bcif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rcsb/strucmotif-search/7662e218d891706e03ce0cf02e4583df40b69766/strucmotif-search-update/src/test/resources/af_afq8sy76f1.bcif --------------------------------------------------------------------------------