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