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