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 org.biojava.nbio.structure.Atom;
024import org.biojava.nbio.structure.Group;
025import org.biojava.nbio.structure.StructureTools;
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029/**
030 * This class extends the basic container for secondary structure annotation,
031 * including all the information used in the DSSP algorithm.
032 *
033 * @author Andreas Prlic
034 * @author Aleix Lafita
035 *
036 */
037public class SecStrucState extends SecStrucInfo {
038
039        private static final long serialVersionUID = -5549430890272724340L;
040
041        private static final Logger logger = LoggerFactory
042                        .getLogger(SecStrucState.class);
043
044        private double phi;
045        private double psi;
046        private double omega;
047        private float kappa;
048
049        private HBond accept1; // from CO of partner to NH of this
050        private HBond accept2; // this is the donor of accept partner
051        private HBond donor1; // from CO of this to NH of partner
052        private HBond donor2; // this is the acceptor of donor partner
053
054        // Symbols: starting '>', ending '<', or both 'X'.
055        // Number means bracketed n-turn residue without h-bond
056        private char[] turn;
057        private boolean bend;
058
059        private BetaBridge bridge1;
060        private BetaBridge bridge2;
061
062        public SecStrucState(Group g, String ass, SecStrucType t) {
063                super(g, ass, t);
064
065                phi = 360;
066                psi = 360;
067                omega = 360;
068
069                accept1 = new HBond();
070                accept2 = new HBond();
071                donor1 = new HBond();
072                donor2 = new HBond();
073
074                bridge1 = null;
075                bridge2 = null;
076
077                turn = new char[3];
078                turn[0] = ' ';
079                turn[1] = ' ';
080                turn[2] = ' ';
081
082                bend = false;
083                kappa = 360;
084        }
085
086        public boolean isBend() {
087                return bend;
088        }
089
090        public void setBend(boolean bend) {
091                this.bend = bend;
092        }
093
094        public float getKappa() {
095                return kappa;
096        }
097
098        public void setKappa(float kappa) {
099                this.kappa = kappa;
100        }
101
102        public char[] getTurn() {
103                return turn;
104        }
105
106        /**
107         * Set the turn column corresponding to 3,4 or 5 helix patterns. If starting
108         * > or ending < was set and the opposite is being set, the value will be
109         * converted to X. If a number was set, it will be overwritten by the new
110         * character.
111         *
112         * @param c
113         *            character in the column
114         * @param t
115         *            turn of the helix {3,4,5}
116         */
117        public void setTurn(char c, int t) {
118                if (turn[t - 3] == 'X')
119                        return;
120                else if (turn[t - 3] == '<' && c == '>' || turn[t - 3] == '>'
121                                && c == '<') {
122                        turn[t - 3] = 'X';
123                } else if (turn[t - 3] == '<' || turn[t - 3] == '>')
124                        return;
125                else
126                        turn[t - 3] = c;
127        }
128
129        public HBond getAccept1() {
130                return accept1;
131        }
132
133        public void setAccept1(HBond accept1) {
134                this.accept1 = accept1;
135        }
136
137        public HBond getAccept2() {
138                return accept2;
139        }
140
141        public void setAccept2(HBond accept2) {
142                this.accept2 = accept2;
143        }
144
145        public HBond getDonor1() {
146                return donor1;
147        }
148
149        public void setDonor1(HBond donor1) {
150                this.donor1 = donor1;
151        }
152
153        public HBond getDonor2() {
154                return donor2;
155        }
156
157        public void setDonor2(HBond donor2) {
158                this.donor2 = donor2;
159        }
160
161        public double getPhi() {
162                return phi;
163        }
164
165        public void setPhi(double phi) {
166                this.phi = phi;
167        }
168
169        public double getPsi() {
170                return psi;
171        }
172
173        public void setPsi(double psi) {
174                this.psi = psi;
175        }
176
177        public double getOmega() {
178                return omega;
179        }
180
181        public void setOmega(double omega) {
182                this.omega = omega;
183        }
184
185        public BetaBridge getBridge1() {
186                return bridge1;
187        }
188
189        public BetaBridge getBridge2() {
190                return bridge2;
191        }
192
193        /**
194         * Adds a Bridge to the residue. Each residue can only store two bridges. If
195         * the residue contains already two Bridges, the Bridge will not be added
196         * and the method returns false.
197         *
198         * @param bridge
199         * @return false if the Bridge was not added, true otherwise
200         */
201        public boolean addBridge(BetaBridge bridge) {
202                if (bridge1 == null) {
203                        bridge1 = bridge;
204                        return true;
205                } else if (bridge1.equals(bridge)) {
206                        return true;
207                } else if (bridge2 == null) {
208                        bridge2 = bridge;
209                        return true;
210                } else if (bridge2.equals(bridge)) {
211                        return true;
212                } else { //no space left, cannot add the bridge
213                        logger.info("Residue forms more than 2 beta Bridges, "
214                                        + "DSSP output might differ in Bridges column.");
215                        return false;
216                }
217        }
218
219        public void setBridge1(BetaBridge bridge1) {
220                this.bridge1 = bridge1;
221        }
222
223        public void setBridge2(BetaBridge bridge2) {
224                this.bridge2 = bridge2;
225        }
226
227        public String printDSSPline(int index) {
228
229                StringBuffer buf = new StringBuffer();
230
231                // #
232                if (index < 9)
233                        buf.append("    ");
234                else if (index < 99)
235                        buf.append("   ");
236                else if (index < 999)
237                        buf.append("  ");
238                else
239                        buf.append(" ");
240                buf.append(index + 1);
241
242                // RESIDUE
243                int resnum = parent.getResidueNumber().getSeqNum();
244                if (resnum < 10)
245                        buf.append("    ");
246                else if (resnum < 100)
247                        buf.append("   ");
248                else
249                        buf.append("  ");
250                buf.append(resnum);
251                Character insCode = parent.getResidueNumber().getInsCode();
252                if (insCode != null)
253                        buf.append(insCode);
254                else
255                        buf.append(" ");
256                buf.append(parent.getChainId());
257                if (parent.getChainId().length() == 1)
258                        buf.append(" ");
259
260                // AA
261                char aaLetter = StructureTools.get1LetterCode(parent.getPDBName());
262                buf.append(aaLetter).append("  ");
263
264                // STRUCTURE
265                buf.append(type).append(" ");
266
267                for (int t = 0; t < 3; t++) {
268                        buf.append(turn[t]);
269                }
270
271                buf.append("  ");
272
273                if (isBend())
274                        buf.append('S');
275                else
276                        buf.append(" ");
277
278                buf.append(" ");
279
280                int bp1 = 0;
281                if (bridge1 != null) {
282                        if (bridge1.partner1 != index)
283                                bp1 = bridge1.partner1 + 1;
284                        else
285                                bp1 = bridge1.partner2 + 1;
286                }
287                // TODO a clever way to do this?
288                if (bp1 < 10)
289                        buf.append("   ").append(bp1);
290                else if (bp1 < 100)
291                        buf.append("  ").append(bp1);
292                else if (bp1 < 1000)
293                        buf.append(" ").append(bp1);
294                else
295                        buf.append(bp1);
296
297                int bp2 = 0;
298                if (bridge2 != null) {
299                        if (bridge2.partner1 != index)
300                                bp2 = bridge2.partner1 + 1;
301                        else
302                                bp2 = bridge2.partner2 + 1;
303                }
304                if (bp2 < 10)
305                        buf.append("   ").append(bp2);
306                else if (bp2 < 100)
307                        buf.append("  ").append(bp2);
308                else if (bp2 < 1000)
309                        buf.append(" ").append(bp2);
310                else
311                        buf.append(bp2);
312
313                // beta-sheet label TODO
314                buf.append(" ");
315
316                // ACC TODO
317                buf.append("     ");
318
319                // N-H-->O
320                int p1 = accept1.getPartner();
321                double e1 = (accept1.getEnergy() / 1000.0);
322                if (e1 < 0.0)
323                        p1 -= index;
324                buf.append(String.format("%6d,%4.1f", p1, e1));
325
326                // O-->H-N
327                int p2 = donor1.getPartner();
328                double e2 = (donor1.getEnergy() / 1000.0);
329                if (e2 < 0.0)
330                        p2 -= index;
331                buf.append(String.format("%6d,%4.1f", p2, e2));
332
333                // N-H-->O
334                int p3 = accept2.getPartner();
335                double e3 = (accept2.getEnergy() / 1000.0);
336                if (e3 < 0.0)
337                        p3 -= index;
338                buf.append(String.format("%6d,%4.1f", p3, e3));
339
340                // O-->H-N
341                int p4 = donor2.getPartner();
342                double e4 = (donor2.getEnergy() / 1000.0);
343                if (e4 < 0.0)
344                        p4 -= index;
345                buf.append(String.format("%6d,%4.1f", p4, e4));
346
347                // TCO TODO
348                buf.append("        ");
349
350                // KAPPA
351                buf.append(String.format("%6.1f", kappa));
352
353                // ALPHA TODO
354                buf.append("      ");
355
356                // PHI PSI
357                buf.append(String.format("%6.1f %6.1f ", phi, psi));
358
359                // X-CA Y-CA Z-CA
360                Atom ca = parent.getAtom("CA");
361                buf.append(String.format("%6.1f %6.1f %6.1f", ca.getX(), ca.getY(),
362                                ca.getZ()));
363
364                return buf.toString();
365        }
366
367}