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 */ 021package org.biojava.nbio.structure.io.mmtf; 022 023import java.util.List; 024import java.util.Map; 025import java.util.Map.Entry; 026 027import org.biojava.nbio.structure.Atom; 028import org.biojava.nbio.structure.Bond; 029import org.biojava.nbio.structure.Chain; 030import org.biojava.nbio.structure.ChainImpl; 031import org.biojava.nbio.structure.EntityInfo; 032import org.biojava.nbio.structure.Group; 033import org.biojava.nbio.structure.PDBCrystallographicInfo; 034import org.biojava.nbio.structure.PDBHeader; 035import org.biojava.nbio.structure.Structure; 036import org.biojava.nbio.structure.io.mmcif.model.ChemComp; 037import org.biojava.nbio.structure.quaternary.BioAssemblyInfo; 038import org.rcsb.mmtf.api.StructureAdapterInterface; 039import org.rcsb.mmtf.dataholders.MmtfStructure; 040 041/** 042 * Class to take Biojava structure data and covert to the DataApi for encoding. 043 * Must implement all the functions in {@link StructureAdapterInterface}. 044 * @author Anthony Bradley 045 * 046 */ 047public class MmtfStructureWriter { 048 049 050 private StructureAdapterInterface mmtfDecoderInterface; 051 052 /** 053 * Pass data from Biojava structure to another generic output type. Loops through the data 054 * structure and calls all the set functions. 055 * @param structure the input {@link Structure} to write 056 * @param dataTransferInterface the generic interface that 057 * implements all the set methods. 058 */ 059 public MmtfStructureWriter(Structure structure, StructureAdapterInterface dataTransferInterface) { 060 this.mmtfDecoderInterface = dataTransferInterface; 061 // Reset structure to consider altloc groups with the same residue number but different group names as seperate groups 062 MmtfUtils.fixMicroheterogenity(structure); 063 // Get the chain name to index map 064 MmtfSummaryDataBean mmtfSummaryDataBean = MmtfUtils.getStructureInfo(structure); 065 Map<String, Integer> chainIdToIndexMap = mmtfSummaryDataBean.getChainIdToIndexMap(); 066 List<Atom> allAtoms = mmtfSummaryDataBean.getAllAtoms(); 067 int numBonds = mmtfSummaryDataBean.getNumBonds(); 068 List<Chain> allChains = mmtfSummaryDataBean.getAllChains(); 069 mmtfDecoderInterface.initStructure(numBonds, allAtoms.size(), MmtfUtils.getNumGroups(structure), allChains.size(), structure.nrModels(), structure.getPDBCode()); 070 // Generate the secondary structure 071 MmtfUtils.calculateDsspSecondaryStructure(structure); 072 // Get the header and the xtal info. 073 PDBHeader pdbHeader = structure.getPDBHeader(); 074 PDBCrystallographicInfo xtalInfo = pdbHeader.getCrystallographicInfo(); 075 mmtfDecoderInterface.setHeaderInfo(pdbHeader.getRfree(), pdbHeader.getRwork(), pdbHeader.getResolution(), pdbHeader.getTitle(), MmtfUtils.dateToIsoString(pdbHeader.getDepDate()), 076 MmtfUtils.dateToIsoString(pdbHeader.getRelDate()), MmtfUtils.techniquesToStringArray(pdbHeader.getExperimentalTechniques())); 077 mmtfDecoderInterface.setXtalInfo(MmtfUtils.getSpaceGroupAsString(xtalInfo.getSpaceGroup()), MmtfUtils.getUnitCellAsArray(xtalInfo), MmtfUtils.getNcsAsArray(xtalInfo.getNcsOperators())); 078 // Store the bioassembly data 079 storeBioassemblyInformation(chainIdToIndexMap, pdbHeader.getBioAssemblies()); 080 // Store the entity data 081 storeEntityInformation(allChains, structure.getEntityInfos()); 082 // Now loop through the data structure 083 for (int modelIndex=0; modelIndex<structure.nrModels(); modelIndex++) { 084 List<Chain> modelChains = structure.getChains(modelIndex); 085 // Set this model 086 mmtfDecoderInterface.setModelInfo(modelIndex, modelChains.size()); 087 for(int chainInModelIndex=0; chainInModelIndex<modelChains.size(); chainInModelIndex++) { 088 Chain chain = modelChains.get(chainInModelIndex); 089 List<Group> groups = chain.getAtomGroups(); 090 List<Group> sequenceGroups = chain.getSeqResGroups(); 091 mmtfDecoderInterface.setChainInfo(chain.getId(), chain.getName(), groups.size()); 092 for(int groupInChainIndex=0; groupInChainIndex<groups.size(); groupInChainIndex++){ 093 Group group = groups.get(groupInChainIndex); 094 List<Atom> atomsInGroup = MmtfUtils.getAtomsForGroup(group); 095 ChemComp chemComp = group.getChemComp(); 096 Character insCode = group.getResidueNumber().getInsCode(); 097 if(insCode==null || insCode.equals(' ')){ 098 insCode=MmtfStructure.UNAVAILABLE_CHAR_VALUE; 099 } 100 char singleLetterCode = 'X'; 101 if (chemComp.getOne_letter_code().length()==1){ 102 singleLetterCode = chemComp.getOne_letter_code().charAt(0); 103 } 104 mmtfDecoderInterface.setGroupInfo(group.getPDBName(), group.getResidueNumber().getSeqNum(), insCode.charValue(), 105 chemComp.getType().toUpperCase(), atomsInGroup.size(), MmtfUtils.getNumBondsInGroup(atomsInGroup), singleLetterCode, 106 sequenceGroups.indexOf(group), MmtfUtils.getSecStructType(group)); 107 for (Atom atom : atomsInGroup){ 108 char altLoc = MmtfStructure.UNAVAILABLE_CHAR_VALUE; 109 if(atom.getAltLoc()!=null){ 110 if(atom.getAltLoc().charValue()!=' '){ 111 altLoc=atom.getAltLoc().charValue(); 112 } 113 } 114 mmtfDecoderInterface.setAtomInfo(atom.getName(), atom.getPDBserial(), altLoc, (float) atom.getX(), 115 (float) atom.getY(), (float) atom.getZ(), atom.getOccupancy(), 116 atom.getTempFactor(), atom.getElement().toString(), atom.getCharge()); 117 addBonds(atom, atomsInGroup, allAtoms); 118 } 119 } 120 } 121 } 122 mmtfDecoderInterface.finalizeStructure(); 123 124 } 125 126 /** 127 * Add the bonds for a given atom. 128 * @param atom the atom for which bonds are to be formed 129 * @param atomsInGroup the list of atoms in the group 130 * @param allAtoms the list of atoms in the whole structure 131 */ 132 private void addBonds(Atom atom, List<Atom> atomsInGroup, List<Atom> allAtoms) { 133 if(atom.getBonds()==null){ 134 return; 135 } 136 for(Bond bond : atom.getBonds()) { 137 // Now set the bonding information. 138 Atom other = bond.getOther(atom); 139 // If both atoms are in the group 140 if (atomsInGroup.indexOf(other)!=-1){ 141 Integer firstBondIndex = atomsInGroup.indexOf(atom); 142 Integer secondBondIndex = atomsInGroup.indexOf(other); 143 // Don't add the same bond twice 144 if(firstBondIndex>secondBondIndex){ 145 int bondOrder = bond.getBondOrder(); 146 mmtfDecoderInterface.setGroupBond(firstBondIndex, secondBondIndex, bondOrder); 147 } 148 } 149 // Otherwise it's an inter group bond - so add it here 150 else { 151 Integer firstBondIndex = allAtoms.indexOf(atom); 152 Integer secondBondIndex = allAtoms.indexOf(other); 153 if(firstBondIndex>secondBondIndex){ 154 // Don't add the same bond twice 155 int bondOrder = bond.getBondOrder(); 156 mmtfDecoderInterface.setInterGroupBond(firstBondIndex, secondBondIndex, bondOrder); 157 } 158 } 159 } 160 } 161 162 163 /** 164 * Store the entity information for a given structure. 165 * @param allChains a list of all the chains in a structure 166 * @param entityInfos a list of the entity information 167 */ 168 private void storeEntityInformation(List<Chain> allChains, List<EntityInfo> entityInfos) { 169 for (EntityInfo entityInfo : entityInfos) { 170 String description = entityInfo.getDescription(); 171 String type; 172 if (entityInfo.getType()==null){ 173 type = null; 174 } 175 else{ 176 type = entityInfo.getType().getEntityType(); 177 } 178 List<Chain> entityChains = entityInfo.getChains(); 179 if (entityChains.isEmpty()){ 180 // Error mapping chain to entity 181 System.err.println("ERROR MAPPING CHAIN TO ENTITY: "+description); 182 mmtfDecoderInterface.setEntityInfo(new int[0], "", description, type); 183 continue; 184 } 185 else{ 186 int[] chainIndices = new int[entityChains.size()]; 187 for (int i=0; i<entityChains.size(); i++) { 188 chainIndices[i] = allChains.indexOf(entityChains.get(i)); 189 } 190 Chain chain = entityChains.get(0); 191 ChainImpl chainImpl; 192 if (chain instanceof ChainImpl){ 193 chainImpl = (ChainImpl) entityChains.get(0); 194 } 195 else{ 196 throw new RuntimeException(); 197 } 198 String sequence = chainImpl.getSeqResOneLetterSeq(); 199 mmtfDecoderInterface.setEntityInfo(chainIndices, sequence, description, type); 200 } 201 } 202 } 203 204 205 /** 206 * Generate the bioassembly information on in the desired form. 207 * @param bioJavaStruct the Biojava structure 208 * @param header the header 209 */ 210 private void storeBioassemblyInformation(Map<String, Integer> chainIdToIndexMap, Map<Integer, BioAssemblyInfo> inputBioAss) { 211 int bioAssemblyIndex = 0; 212 for (Entry<Integer, BioAssemblyInfo> entry : inputBioAss.entrySet()) { 213 Map<double[], int[]> transformMap = MmtfUtils.getTransformMap(entry.getValue(), chainIdToIndexMap); 214 for(Entry<double[], int[]> transformEntry : transformMap.entrySet()) { 215 mmtfDecoderInterface.setBioAssemblyTrans(bioAssemblyIndex, transformEntry.getValue(), transformEntry.getKey(), entry.getKey().toString()); 216 } 217 bioAssemblyIndex++; 218 } 219 } 220 221}