001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.nbio.structure.quaternary; 023 024import org.biojava.nbio.structure.Atom; 025import org.biojava.nbio.structure.Chain; 026import org.biojava.nbio.structure.Group; 027import org.biojava.nbio.structure.Structure; 028import org.biojava.nbio.structure.io.mmcif.model.PdbxStructAssembly; 029import org.biojava.nbio.structure.io.mmcif.model.PdbxStructAssemblyGen; 030import org.biojava.nbio.structure.io.mmcif.model.PdbxStructOperList; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import java.util.*; 035 036/** 037 * Reconstructs the quaternary structure of a protein from an asymmetric unit 038 * 039 * @author Peter Rose 040 * @author Andreas Prlic 041 * 042 */ 043public class BiologicalAssemblyBuilder { 044 045 private static final Logger logger = LoggerFactory.getLogger(BiologicalAssemblyBuilder.class); 046 047 private OperatorResolver operatorResolver; 048 private List<PdbxStructAssemblyGen> psags; 049 050 private List<BiologicalAssemblyTransformation> modelTransformations; 051 052 private List<String> modelIndex = new ArrayList<String>(); 053 054 public BiologicalAssemblyBuilder(){ 055 init(); 056 } 057 058 public Structure rebuildQuaternaryStructure(Structure asymUnit, List<BiologicalAssemblyTransformation> transformations){ 059 // ensure that new chains are build in the same order as they appear in the asymmetric unit 060 orderTransformationsByChainId(asymUnit, transformations); 061 062 Structure s = asymUnit.clone(); 063 // this resets all models (not only the first one): this is important for NMR (multi-model) 064 // structures, otherwise we could not add new models below 065 s.resetModels(); 066 067 for (BiologicalAssemblyTransformation transformation : transformations){ 068 069 // note: for NMR structures (or any multi-model) we use the first model only and throw away the rest 070 for (Chain c : asymUnit.getChains()){ 071 072 String intChainID = c.getInternalChainID(); 073 if (intChainID == null) { 074 logger.info("No internal chain ID found while building bioassembly, using chain ID instead: " + c.getChainID()); 075 intChainID = c.getChainID(); 076 } 077 078 if (transformation.getChainId().equals(intChainID)){ 079 Chain chain = (Chain)c.clone(); 080 081 for (Group g : chain.getAtomGroups()) { 082 083 for (Atom a: g.getAtoms()) { 084 085 transformation.transformPoint(a.getCoords()); 086 087 } 088 } 089 090 String transformId = transformation.getId(); 091 092 addChainAndModel(s, chain, transformId); 093 } 094 } 095 } 096 097 s.setBiologicalAssembly(true); 098 return s; 099 } 100 101 /** 102 * Orders model transformations by chain ids in the same order as in the asymmetric unit 103 * @param asymUnit 104 * @param transformations 105 */ 106 private void orderTransformationsByChainId(Structure asymUnit, List<BiologicalAssemblyTransformation> transformations) { 107 final List<String> chainIds = getChainIds(asymUnit); 108 Collections.sort(transformations, new Comparator<BiologicalAssemblyTransformation>() { 109 @Override 110 public int compare(BiologicalAssemblyTransformation t1, BiologicalAssemblyTransformation t2) { 111 // set sort order only if the two ids are identical 112 if (t1.getId().equals(t2.getId())) { 113 return chainIds.indexOf(t1.getChainId()) - chainIds.indexOf(t2.getChainId()); 114 } 115 return 0; 116 } 117 }); 118 } 119 120 /** 121 * Returns a list of chain ids in the order they are specified in the ATOM 122 * records in the asymmetric unit 123 * @param asymUnit 124 * @return 125 */ 126 private List<String> getChainIds(Structure asymUnit) { 127 List<String> chainIds = new ArrayList<String>(); 128 for ( Chain c : asymUnit.getChains()){ 129 String intChainID = c.getInternalChainID(); 130 if ( intChainID == null) { 131 //System.err.println("no internal chain ID found, using " + c.getChainID() + " ( while looking for " + max.ndbChainId+")"); 132 intChainID = c.getChainID(); 133 } 134 chainIds.add(intChainID); 135 } 136 return chainIds; 137 } 138 139 private void addChainAndModel(Structure s, Chain newChain, String modelId) { 140 141 if ( modelIndex.size() == 0) 142 modelIndex.add("PLACEHOLDER FOR ASYM UNIT"); 143 144 int modelCount = modelIndex.indexOf(modelId); 145 if ( modelCount == -1) { 146 modelIndex.add(modelId); 147 modelCount = modelIndex.indexOf(modelId); 148 } 149 150 if (modelCount == 0) { 151 s.addChain(newChain); 152 } else if (modelCount > s.nrModels()) { 153 List<Chain> newModel = new ArrayList<Chain>(); 154 newModel.add(newChain); 155 s.addModel(newModel); 156 } else { 157 s.addChain(newChain, modelCount-1); 158 } 159 } 160 161 /** 162 * Returns a list of transformation matrices for the generation of a macromolecular 163 * assembly for the specified assembly Id. 164 * 165 * @param assemblyId Id of the macromolecular assembly to be generated 166 * @return list of transformation matrices to generate macromolecular assembly 167 */ 168 public ArrayList<BiologicalAssemblyTransformation> getBioUnitTransformationList(PdbxStructAssembly psa, List<PdbxStructAssemblyGen> psags, List<PdbxStructOperList> operators) { 169 //System.out.println("Rebuilding " + psa.getDetails() + " | " + psa.getOligomeric_details() + " | " + psa.getOligomeric_count()); 170 //System.out.println(psag); 171 init(); 172 this.psags = psags; 173 174 //psa.getId(); 175 176 for (PdbxStructOperList oper: operators){ 177 BiologicalAssemblyTransformation transform = new BiologicalAssemblyTransformation(); 178 transform.setId(oper.getId()); 179 transform.setRotationMatrix(oper.getMatrix().getArray()); 180 transform.setTranslation(oper.getVector()); 181// transform.setTransformationMatrix(oper.getMatrix(), oper.getVector()); 182 modelTransformations.add(transform); 183 } 184 185 ArrayList<BiologicalAssemblyTransformation> transformations = getBioUnitTransformationsListUnaryOperators(psa.getId()); 186 transformations.addAll(getBioUnitTransformationsListBinaryOperators(psa.getId())); 187 transformations.trimToSize(); 188 return transformations; 189 } 190 191 192 private ArrayList<BiologicalAssemblyTransformation> getBioUnitTransformationsListBinaryOperators(String assemblyId) { 193 194 ArrayList<BiologicalAssemblyTransformation> transformations = new ArrayList<BiologicalAssemblyTransformation>(); 195 196 List<OrderedPair<String>> operators = operatorResolver.getBinaryOperators(); 197 198 199 for ( PdbxStructAssemblyGen psag : psags){ 200 if ( psag.getAssembly_id().equals(assemblyId)) { 201 202 List<String>asymIds= Arrays.asList(psag.getAsym_id_list().split(",")); 203 204 operatorResolver.parseOperatorExpressionString(psag.getOper_expression()); 205 206 // apply binary operators to the specified chains 207 // Example 1M4X: generates all products of transformation matrices (1-60)(61-88) 208 for (String chainId : asymIds) { 209 210 int modelNumber = 1; 211 for (OrderedPair<String> operator : operators) { 212 BiologicalAssemblyTransformation original1 = getModelTransformationMatrix(operator.getElement1()); 213 BiologicalAssemblyTransformation original2 = getModelTransformationMatrix(operator.getElement2()); 214 // ModelTransformationMatrix transform = ModelTransformationMatrix.multiply4square_x_4square2(original1, original2); 215 BiologicalAssemblyTransformation transform = BiologicalAssemblyTransformation.combine(original1, original2); 216 transform.setChainId(chainId); 217 // transform.setId(original1.getId() + "x" + original2.getId()); 218 transform.setId(String.valueOf(modelNumber)); 219 transformations.add(transform); 220 modelNumber++; 221 } 222 } 223 } 224 225 } 226 227 return transformations; 228 } 229 230 private BiologicalAssemblyTransformation getModelTransformationMatrix(String operator) { 231 for (BiologicalAssemblyTransformation transform: modelTransformations) { 232 if (transform.getId().equals(operator)) { 233 return transform; 234 } 235 } 236 logger.error("Could not find modelTransformationmatrix for " + operator); 237 return new BiologicalAssemblyTransformation(); 238 } 239 240 private ArrayList<BiologicalAssemblyTransformation> getBioUnitTransformationsListUnaryOperators(String assemblyId) { 241 ArrayList<BiologicalAssemblyTransformation> transformations = new ArrayList<BiologicalAssemblyTransformation>(); 242 243 244 for ( PdbxStructAssemblyGen psag : psags){ 245 if ( psag.getAssembly_id().equals(assemblyId)) { 246 247 operatorResolver.parseOperatorExpressionString(psag.getOper_expression()); 248 List<String> operators = operatorResolver.getUnaryOperators(); 249 250 List<String>asymIds= Arrays.asList(psag.getAsym_id_list().split(",")); 251 252 // apply unary operators to the specified chains 253 for (String chainId : asymIds) { 254 for (String operator : operators) { 255 256 BiologicalAssemblyTransformation original = getModelTransformationMatrix(operator); 257 BiologicalAssemblyTransformation transform = new BiologicalAssemblyTransformation(original); 258 transform.setChainId(chainId); 259 transform.setId(operator); 260 transformations.add(transform); 261 } 262 } 263 } 264 } 265 266 return transformations; 267 } 268 269 private void init(){ 270 operatorResolver= new OperatorResolver(); 271 modelTransformations = new ArrayList<BiologicalAssemblyTransformation>(1); 272 } 273}