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