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 dsspIs an InputStream to a DSSP file
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> parseInputStream(InputStream dsspIs,
074                        Structure structure, boolean assign)
075                                        throws IOException, StructureException {
076                        
077                BufferedReader reader = new BufferedReader(new InputStreamReader(dsspIs));
078                return generalParse(reader, structure, assign);
079        }
080
081        /**
082         * Parse a DSSP output file and return the secondary structure
083         * annotation as a List of {@link SecStrucState} objects.
084         *
085         * @param dsspPath path to the DSSP file to parse
086         * @param structure Structure object associated to the dssp
087         * @param assign assigns the SS to the structure if true
088         * @return a List of SS annotation objects
089         * @throws StructureException
090         * @throws IOException
091         */
092        public static List<SecStrucState> parseFile(String dsspPath,
093                        Structure structure, boolean assign)
094                                        throws IOException, StructureException {
095
096                File file = new File(dsspPath);
097                Reader read = new FileReader(file);
098                BufferedReader reader = new BufferedReader(read);
099                return generalParse(reader, structure, assign);
100        }
101
102        /**
103         * Fetch and parse the DSSP file of the specified pdb code
104         * from the PDB web server and return the secondary structure
105         * annotation as a List of {@link SecStrucState} objects.
106         *
107         * @param pdb path to the DSSP file to parse
108         * @param structure Structure object associated to the dssp
109         * @param assign assigns the SS to the structure if true
110         * @return a List of SS annotation objects
111         * @throws StructureException
112         * @throws IOException
113         */
114        public static List<SecStrucState> fetch(String pdb,
115                        Structure structure, boolean assign)
116                                        throws IOException, StructureException {
117
118                URL url = new URL("http://files.rcsb.org/dssp/" + 
119                                pdb.toLowerCase().substring(1, 3) + "/" + 
120                                pdb.toLowerCase() + "/" +
121                                pdb.toLowerCase() + ".dssp.gz");
122                InputStream in = new GZIPInputStream(url.openStream());
123                Reader read = new InputStreamReader(in);
124                BufferedReader reader = new BufferedReader(read);
125                return generalParse(reader, structure, assign);
126        }
127
128        /**
129         * Parse a DSSP format String and return the secondary structure
130         * annotation as a List of {@link SecStrucState} objects.
131         *
132         * @param dsspOut String with the DSSP output to parse
133         * @param structure Structure object associated to the dssp
134         * @param assign assigns the SS to the structure if true
135         * @return a List of SS annotation objects
136         * @throws StructureException
137         * @throws IOException
138         */
139        public static List<SecStrucState> parseString(String dsspOut,
140                        Structure structure, boolean assign)
141                                        throws IOException, StructureException {
142
143                Reader read = new StringReader(dsspOut);
144                BufferedReader reader = new BufferedReader(read);
145                return generalParse(reader, structure, assign);
146        }
147
148        private static List<SecStrucState> generalParse(BufferedReader reader,
149                        Structure structure, boolean assign)
150                                        throws IOException, StructureException {
151
152                String startLine = "  #  RESIDUE AA STRUCTURE BP1 BP2  ACC";
153                String line;
154
155                List<SecStrucState> secstruc = new ArrayList<SecStrucState>();
156
157                //Find the first line of the DSSP output
158                while((line = reader.readLine()) != null) {
159                        if(line.startsWith(startLine)) break;
160                }
161
162                while((line = reader.readLine()) != null) {
163
164                        String indexStr = line.substring(0,5).trim();
165                        String resNumStr = line.substring(5,10).trim();
166
167                        //Only happens if dssp inserts a line indicating a chain break
168                        if(!resNumStr.equals("")) {
169
170                                int index = Integer.parseInt(indexStr);
171                                //Get the group of the structure corresponding to the residue
172                                int resNum = Integer.parseInt(resNumStr);
173                                char insCode = line.charAt(10);
174                                String chainId = line.substring(11,13).trim();
175                                ResidueNumber r = new ResidueNumber(chainId, resNum, insCode);
176                                Group parent = structure.getPolyChainByPDB(chainId)
177                                                .getGroupByPDB(r);
178                                SecStrucType ssType =
179                                                SecStrucType.fromCharacter(line.charAt(16));
180
181                                SecStrucState ss = new SecStrucState(parent,
182                                                SecStrucInfo.DSSP_ASSIGNMENT, ssType);
183
184                                //Parse the Bridge partners - TODO parallel or antiparallel?
185                                String bp = line.substring(25,29).trim();
186                                if (bp != "") {
187                                        BetaBridge bb = new BetaBridge(
188                                                        index, Integer.valueOf(bp), BridgeType.parallel);
189                                        ss.addBridge(bb);
190                                } else logger.warn("Unable to parse beta Bridge for resn "+index);
191
192                                bp = line.substring(29,33).trim();
193                                if (bp != "") {
194                                        BetaBridge bb = new BetaBridge(
195                                                        index, Integer.valueOf(bp), BridgeType.parallel);
196                                        ss.addBridge(bb);
197                                } else logger.warn("Unable to parse beta Bridge for resn "+index);
198
199                                //Parse the energy terms of donor and acceptor
200                                for (int i=0; i<4; i++){
201
202                                        int a = 42 + i*11;
203                                        int b = a + 8;
204
205                                        String val = line.substring(a,b).trim();
206                                        if (val == "") {
207                                                logger.warn("Unable to parse energy for resn "+index);
208                                                continue;
209                                        }
210
211                                        String[] p = val.split(",");
212
213                                        int partner = Integer.parseInt(p[0]);
214                                        if (partner != 0) partner += index;
215                                        double energy = Double.valueOf(p[1]) * 1000.0;
216
217                                        switch(i){
218                                        case 0:
219                                                ss.getAccept1().setPartner(partner);
220                                                ss.getAccept1().setEnergy(energy);
221                                                break;
222                                        case 1:
223                                                ss.getDonor1().setPartner(partner);
224                                                ss.getDonor1().setEnergy(energy);
225                                                break;
226                                        case 2:
227                                                ss.getAccept2().setPartner(partner);
228                                                ss.getAccept2().setEnergy(energy);
229                                                break;
230                                        case 3:
231                                                ss.getDonor2().setPartner(partner);
232                                                ss.getDonor1().setEnergy(energy);
233                                                break;
234                                        }
235                                }
236
237                                //Angle properties
238                                String val = line.substring(91,97).trim();
239                                if (val != "") ss.setKappa(Float.valueOf(val));
240                                else logger.warn("Unable to parse kappa for resn "+index);
241
242                                val = line.substring(103,109).trim();
243                                if (val != "") ss.setPhi(Float.valueOf(val));
244                                else logger.warn("Unable to parse phi for resn "+index);
245
246                                val = line.substring(109,116).trim();
247                                if (val != "") ss.setPsi(Float.valueOf(val));
248                                else logger.warn("Unable to parse psi for resn "+index);
249
250                                if (assign) parent.setProperty(Group.SEC_STRUC, ss);
251                                secstruc.add(ss);
252                        }
253                }
254
255                reader.close();
256                return secstruc;
257        }
258
259}