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