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.secstruc;
022
023import java.io.BufferedReader;
024import java.io.File;
025import java.io.FileReader;
026import java.io.IOException;
027import java.io.InputStream;
028import java.io.InputStreamReader;
029import java.io.Reader;
030import java.io.StringReader;
031import java.net.URL;
032import java.util.ArrayList;
033import java.util.List;
034import java.util.zip.GZIPInputStream;
035
036import org.biojava.nbio.structure.Group;
037import org.biojava.nbio.structure.ResidueNumber;
038import org.biojava.nbio.structure.Structure;
039import org.biojava.nbio.structure.StructureException;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043/**
044 * Class to parse a DSSP file (output of the DSSP program),
045 * that contains the secondary structure assignment of a structure.
046 * <p>
047 * This class has been ported from the OWL Java library for
048 * Structural Bioinformatics (https://github.com/eppic-team/owl).
049 * <p>
050 * As of September 2015, the DSSP source code and executables can
051 * be downloaded from http://swift.cmbi.ru.nl/gv/dssp/.
052 *
053 * @author Aleix Lafita
054 * @since 4.1.1
055 *
056 */
057public class DSSPParser {
058
059        private static final Logger logger =
060                        LoggerFactory.getLogger(DSSPParser.class);
061
062        /**
063         * Parse a DSSP output file and return the secondary structure
064         * annotation as a List of {@link SecStrucState} objects.
065         *
066         * @param dsspPath path to the DSSP file to parse
067         * @param structure Structure object associated to the dssp
068         * @param assign assigns the SS to the structure if true
069         * @return a List of SS annotation objects
070         * @throws StructureException
071         * @throws IOException
072         */
073        public static List<SecStrucState> parseFile(String dsspPath,
074                        Structure structure, boolean assign)
075                                        throws IOException, StructureException {
076
077                File file = new File(dsspPath);
078                Reader read = new FileReader(file);
079                BufferedReader reader = new BufferedReader(read);
080                return generalParse(reader, structure, assign);
081        }
082
083        /**
084         * Fetch and parse the DSSP file of the specified pdb code
085         * from the PDB web server and return the secondary structure
086         * annotation as a List of {@link SecStrucState} objects.
087         *
088         * @param pdb path to the DSSP file to parse
089         * @param structure Structure object associated to the dssp
090         * @param assign assigns the SS to the structure if true
091         * @return a List of SS annotation objects
092         * @throws StructureException
093         * @throws IOException
094         */
095        public static List<SecStrucState> fetch(String pdb,
096                        Structure structure, boolean assign)
097                                        throws IOException, StructureException {
098
099                URL url = new URL("http://files.rcsb.org/dssp/" + 
100                                pdb.toLowerCase().substring(1, 3) + "/" + 
101                                pdb.toLowerCase() + "/" +
102                                pdb + ".dssp.gz");
103                InputStream in = new GZIPInputStream(url.openStream());
104                Reader read = new InputStreamReader(in);
105                BufferedReader reader = new BufferedReader(read);
106                return generalParse(reader, structure, assign);
107        }
108
109        /**
110         * Parse a DSSP format String and return the secondary structure
111         * annotation as a List of {@link SecStrucState} objects.
112         *
113         * @param dsspOut String with the DSSP output to parse
114         * @param structure Structure object associated to the dssp
115         * @param assign assigns the SS to the structure if true
116         * @return a List of SS annotation objects
117         * @throws StructureException
118         * @throws IOException
119         */
120        public static List<SecStrucState> parseString(String dsspOut,
121                        Structure structure, boolean assign)
122                                        throws IOException, StructureException {
123
124                Reader read = new StringReader(dsspOut);
125                BufferedReader reader = new BufferedReader(read);
126                return generalParse(reader, structure, assign);
127        }
128
129        private static List<SecStrucState> generalParse(BufferedReader reader,
130                        Structure structure, boolean assign)
131                                        throws IOException, StructureException {
132
133                String startLine = "  #  RESIDUE AA STRUCTURE BP1 BP2  ACC";
134                String line;
135
136                List<SecStrucState> secstruc = new ArrayList<SecStrucState>();
137
138                //Find the first line of the DSSP output
139                while((line = reader.readLine()) != null) {
140                        if(line.startsWith(startLine)) break;
141                }
142
143                while((line = reader.readLine()) != null) {
144
145                        String indexStr = line.substring(0,5).trim();
146                        String resNumStr = line.substring(5,10).trim();
147
148                        //Only happens if dssp inserts a line indicating a chain break
149                        if(!resNumStr.equals("")) {
150
151                                int index = Integer.valueOf(indexStr);
152                                //Get the group of the structure corresponding to the residue
153                                int resNum = Integer.valueOf(resNumStr);
154                                char insCode = line.charAt(10);
155                                String chainId = line.substring(11,13).trim();
156                                ResidueNumber r = new ResidueNumber(chainId, resNum, insCode);
157                                Group parent = structure.getChainByPDB(chainId)
158                                                .getGroupByPDB(r);
159                                SecStrucType ssType =
160                                                SecStrucType.fromCharacter(line.charAt(16));
161
162                                SecStrucState ss = new SecStrucState(parent,
163                                                SecStrucInfo.DSSP_ASSIGNMENT, ssType);
164
165                                //Parse the Bridge partners - TODO parallel or antiparallel?
166                                String bp = line.substring(25,29).trim();
167                                if (bp != "") {
168                                        BetaBridge bb = new BetaBridge(
169                                                        index, Integer.valueOf(bp), BridgeType.parallel);
170                                        ss.addBridge(bb);
171                                } else logger.warn("Unable to parse beta Bridge for resn "+index);
172
173                                bp = line.substring(29,33).trim();
174                                if (bp != "") {
175                                        BetaBridge bb = new BetaBridge(
176                                                        index, Integer.valueOf(bp), BridgeType.parallel);
177                                        ss.addBridge(bb);
178                                } else logger.warn("Unable to parse beta Bridge for resn "+index);
179
180                                //Parse the energy terms of donor and acceptor
181                                for (int i=0; i<4; i++){
182
183                                        int a = 42 + i*11;
184                                        int b = a + 8;
185
186                                        String val = line.substring(a,b).trim();
187                                        if (val == "") {
188                                                logger.warn("Unable to parse energy for resn "+index);
189                                                continue;
190                                        }
191
192                                        String[] p = val.split(",");
193
194                                        int partner = Integer.valueOf(p[0]);
195                                        if (partner != 0) partner += index;
196                                        double energy = Double.valueOf(p[1]) * 1000.0;
197
198                                        switch(i){
199                                        case 0:
200                                                ss.getAccept1().setPartner(partner);
201                                                ss.getAccept1().setEnergy(energy);
202                                                break;
203                                        case 1:
204                                                ss.getDonor1().setPartner(partner);
205                                                ss.getDonor1().setEnergy(energy);
206                                                break;
207                                        case 2:
208                                                ss.getAccept2().setPartner(partner);
209                                                ss.getAccept2().setEnergy(energy);
210                                                break;
211                                        case 3:
212                                                ss.getDonor2().setPartner(partner);
213                                                ss.getDonor1().setEnergy(energy);
214                                                break;
215                                        }
216                                }
217
218                                //Angle properties
219                                String val = line.substring(91,97).trim();
220                                if (val != "") ss.setKappa(Float.valueOf(val));
221                                else logger.warn("Unable to parse kappa for resn "+index);
222
223                                val = line.substring(103,109).trim();
224                                if (val != "") ss.setPhi(Float.valueOf(val));
225                                else logger.warn("Unable to parse phi for resn "+index);
226
227                                val = line.substring(109,116).trim();
228                                if (val != "") ss.setPsi(Float.valueOf(val));
229                                else logger.warn("Unable to parse psi for resn "+index);
230
231                                if (assign) parent.setProperty(Group.SEC_STRUC, ss);
232                                secstruc.add(ss);
233                        }
234                }
235
236                reader.close();
237                return secstruc;
238        }
239
240}