1 /* Copyright (C) 2005-2007  The Chemistry Development Kit (CDK) Project
2  *                    2014  Egon Willighagen <egonw@users.sf.net>
3  *
4  * Contact: cdk-devel@lists.sourceforge.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  * All we ask is that proper credit is given for our work, which includes
11  * - but is not limited to - adding the above copyright notice to the beginning
12  * of your source code files, and to any copyright notice that you may distribute
13  * with programs based on this work.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  */
25 package org.openscience.cdk.tools;
26 
27 import org.openscience.cdk.DefaultChemObjectBuilder;
28 import org.openscience.cdk.exception.CDKException;
29 import org.openscience.cdk.interfaces.IAminoAcid;
30 import org.openscience.cdk.interfaces.IAtom;
31 import org.openscience.cdk.interfaces.IBioPolymer;
32 import org.openscience.cdk.interfaces.IBond;
33 import org.openscience.cdk.interfaces.IChemObjectBuilder;
34 import org.openscience.cdk.interfaces.IStrand;
35 import org.openscience.cdk.templates.AminoAcids;
36 import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
37 
38 import java.util.Map;
39 
40 /**
41  * Class that facilitates building protein structures. Building DNA and RNA
42  * is done by a complementary class <code>NucleicAcidBuilderTool</code> (to be
43  * written).
44  *
45  * @cdk.module pdb
46  * @cdk.githash
47  */
48 public class ProteinBuilderTool {
49 
50     private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(ProteinBuilderTool.class);
51 
52     /**
53      * Builds a protein by connecting a new amino acid at the N-terminus of the
54      * given strand.
55      *
56      * @param protein protein to which the strand belongs
57      * @param aaToAdd amino acid to add to the strand of the protein
58      * @param strand  strand to which the protein is added
59      */
addAminoAcidAtNTerminus(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand, IAminoAcid aaToAddTo)60     public static IBioPolymer addAminoAcidAtNTerminus(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand,
61             IAminoAcid aaToAddTo) {
62         // then add the amino acid
63         addAminoAcid(protein, aaToAdd, strand);
64         // Now think about the protein back bone connection
65         if (protein.getMonomerCount() == 0) {
66             // make the connection between that aminoAcid's C-terminus and the
67             // protein's N-terminus
68             protein.addBond(aaToAdd.getBuilder().newInstance(IBond.class, aaToAddTo.getNTerminus(),
69                     aaToAdd.getCTerminus(), IBond.Order.SINGLE));
70         } // else : no current N-terminus, so nothing special to do
71         return protein;
72     }
73 
74     /**
75      * Builds a protein by connecting a new amino acid at the C-terminus of the
76      * given strand. The acidic oxygen of the added amino acid is removed so that
77      * additional amino acids can be added savely. But this also means that you
78      * might want to add an oxygen at the end of the protein building!
79      *
80      * @param protein protein to which the strand belongs
81      * @param aaToAdd amino acid to add to the strand of the protein
82      * @param strand  strand to which the protein is added
83      */
addAminoAcidAtCTerminus(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand, IAminoAcid aaToAddTo)84     public static IBioPolymer addAminoAcidAtCTerminus(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand,
85             IAminoAcid aaToAddTo) {
86         // then add the amino acid
87         addAminoAcid(protein, aaToAdd, strand);
88         // Now think about the protein back bone connection
89         if ((protein.getMonomerCount() != 0) && (aaToAddTo != null)) {
90             // make the connection between that aminoAcid's N-terminus and the
91             // protein's C-terminus
92             protein.addBond(aaToAdd.getBuilder().newInstance(IBond.class, aaToAddTo.getCTerminus(),
93                     aaToAdd.getNTerminus(), IBond.Order.SINGLE));
94         } // else : no current C-terminus, so nothing special to do
95         return protein;
96     }
97 
98     /**
99      * Creates a BioPolymer from a sequence of amino acid as identified by a
100      * the sequence of their one letter codes. It uses the {@link DefaultChemObjectBuilder}
101      * to create a data model.
102      *
103      * <p>For example:
104      * <pre>
105      * BioPolymer protein = ProteinBuilderTool.createProtein("GAGA");
106      * </pre>
107      *
108      * @see #createProtein(String)
109      */
createProtein(String sequence)110     public static IBioPolymer createProtein(String sequence) throws CDKException {
111         return createProtein(sequence, DefaultChemObjectBuilder.getInstance());
112     }
113 
114     /**
115      * Creates a BioPolymer from a sequence of amino acid as identified by a
116      * the sequence of their one letter codes. It uses the given {@link IChemObjectBuilder}
117      * to create a data model.
118      *
119      * <p>For example:
120      * <pre>
121      * BioPolymer protein = ProteinBuilderTool.createProtein(
122      *     "GAGA", SilentChemObjectBuilder.getInstance()
123      * );
124      * </pre>
125      *
126      * @see #createProtein(String)
127      */
createProtein(String sequence, IChemObjectBuilder builder)128     public static IBioPolymer createProtein(String sequence, IChemObjectBuilder builder) throws CDKException {
129         Map<String, IAminoAcid> templates = AminoAcids.getHashMapBySingleCharCode();
130         IBioPolymer protein = builder.newInstance(IBioPolymer.class);
131         IStrand strand = builder.newInstance(IStrand.class);
132         IAminoAcid previousAA = null;
133         for (int i = 0; i < sequence.length(); i++) {
134             String aminoAcidCode = "" + sequence.charAt(i);
135             logger.debug("Adding AA: " + aminoAcidCode);
136             if (aminoAcidCode.equals(" ")) {
137                 // fine, just skip spaces
138             } else {
139                 IAminoAcid aminoAcid = (IAminoAcid) templates.get(aminoAcidCode);
140                 if (aminoAcid == null) {
141                     throw new CDKException("Cannot build sequence! Unknown amino acid: " + aminoAcidCode);
142                 }
143                 try {
144                     aminoAcid = (IAminoAcid) aminoAcid.clone();
145                 } catch (CloneNotSupportedException e) {
146                     throw new CDKException("Cannot build sequence! Clone exception: " + e.getMessage(), e);
147                 }
148                 aminoAcid.setMonomerName(aminoAcidCode + i);
149                 logger.debug("protein: ", protein);
150                 logger.debug("strand: ", strand);
151                 addAminoAcidAtCTerminus(protein, aminoAcid, strand, previousAA);
152                 previousAA = aminoAcid;
153             }
154         }
155         // add the last oxygen of the protein
156         IAtom oxygen = builder.newInstance(IAtom.class, "O");
157         // ... to amino acid
158         previousAA.addAtom(oxygen);
159         IBond bond = builder.newInstance(IBond.class, oxygen, previousAA.getCTerminus(), IBond.Order.SINGLE);
160         previousAA.addBond(bond);
161         // ... and to protein
162         protein.addAtom(oxygen, previousAA, strand);
163         protein.addBond(bond);
164         return protein;
165     }
166 
addAminoAcid(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand)167     private static IBioPolymer addAminoAcid(IBioPolymer protein, IAminoAcid aaToAdd, IStrand strand) {
168         for (IAtom atom : AtomContainerManipulator.getAtomArray(aaToAdd))
169             protein.addAtom(atom, aaToAdd, strand);
170         for (IBond bond : AtomContainerManipulator.getBondArray(aaToAdd))
171             protein.addBond(bond);
172         return protein;
173     }
174 }
175