View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.bonded;
39  
40  import ffx.potential.parameters.ForceField;
41  
42  import java.io.Serial;
43  import java.util.Objects;
44  import java.util.logging.Logger;
45  
46  /**
47   * The Molecule class is a general container used for simple compounds or in cases where more
48   * specialized classes have not been implemented.
49   *
50   * @author Michael J. Schnieders
51   * @since 1.0
52   */
53  @SuppressWarnings("CloneableImplementsClone")
54  public class Molecule extends MSGroup {
55  
56    @Serial
57    private static final long serialVersionUID = 1L;
58  
59    private static final Logger logger = Logger.getLogger(Molecule.class.getName());
60  
61    /** Residue number assigned in PDB files. */
62    private int residueNum;
63    /** Residue name assigned in PDB files. */
64    private String residueName;
65    /** Possibly redundant chainID assigned in PDB files. */
66    private Character chainID;
67    /** Unique segID. */
68    private final String segID;
69  
70    /**
71     * Constructor for Molecule.
72     *
73     * @param name a {@link java.lang.String} object.
74     */
75    public Molecule(String name) {
76      super(name);
77      residueName = name;
78      residueNum = -1;
79      chainID = 'A';
80      segID = "A";
81    }
82  
83    /**
84     * Constructor for Molecule.
85     *
86     * @param name a {@link java.lang.String} object.
87     * @param residueNum The residue number.
88     * @param chainID a {@link java.lang.Character} object.
89     * @param segID a {@link java.lang.String} object.
90     */
91    public Molecule(String name, int residueNum, Character chainID, String segID) {
92      super(name + "-" + residueNum + " " + segID);
93      this.residueName = name;
94      this.residueNum = residueNum;
95      this.chainID = chainID;
96      this.segID = segID;
97    }
98  
99    /**
100    * Setter for the field <code>chainID</code>.
101    *
102    * @param c a {@link java.lang.Character} object.
103    */
104   public void setChainID(Character c) {
105     chainID = c;
106 
107     for (Atom atom : getAtomList()) {
108       atom.setChainID(c);
109     }
110   }
111 
112   /**
113    * Setter for the field <code>residueNum</code>.
114    *
115    * @param residueNum The molecule number.
116    */
117   public void setResidueNum(int residueNum) {
118     this.residueNum = residueNum;
119     for (Atom atom : getAtomList()) {
120       atom.setResidueNumber(residueNum);
121     }
122   }
123 
124   /**
125    * {@inheritDoc}
126    *
127    * <p>Allows adding Atom MSNodes to the Molecule.
128    */
129   @Override
130   public MSNode addMSNode(MSNode o) {
131     Atom currentAtom = null;
132     if (o instanceof Atom) {
133       Atom newAtom = (Atom) o;
134       Character newAlt = newAtom.getAltLoc();
135       MSNode atoms = getAtomNode();
136       currentAtom = (Atom) atoms.contains(newAtom);
137       if (currentAtom == null) {
138         currentAtom = newAtom;
139         atoms.add(newAtom);
140         setFinalized(false);
141       } else {
142         // Allow overwriting of the root alternate conformer (' ' or 'A').
143         Character currentAlt = currentAtom.getAltLoc();
144         if (currentAlt.equals(' ') || currentAlt.equals('A')) {
145           if (!newAlt.equals(' ') && !newAlt.equals('A')) {
146             newAtom.setXyzIndex(currentAtom.getXyzIndex());
147             atoms.remove(currentAtom);
148             currentAtom = newAtom;
149             atoms.add(currentAtom);
150             setFinalized(false);
151           }
152         }
153       }
154     } else {
155       logger.warning(" Only an Atom can be added to a Residue.");
156     }
157     return currentAtom;
158   }
159 
160   @Override
161   public boolean equals(Object o) {
162     if (this == o) {
163       return true;
164     }
165     if (o == null || getClass() != o.getClass()) {
166       return false;
167     }
168     Molecule molecule = (Molecule) o;
169     return residueNum == molecule.residueNum
170         && Objects.equals(residueName, molecule.residueName)
171         && Objects.equals(segID, molecule.segID);
172   }
173 
174   /** {@inheritDoc} */
175   @Override
176   public void finalize(boolean finalizeGeometry, ForceField forceField) {
177     setFinalized(false);
178     getAtomNode().setName("Atoms (" + getAtomList().size() + ")");
179     if (finalizeGeometry) {
180       assignBondedTerms(forceField);
181       removeLeaves();
182     }
183     setCenter(getMultiScaleCenter(false));
184     setFinalized(true);
185   }
186 
187   /**
188    * getAtom
189    *
190    * @param name a {@link java.lang.String} object.
191    * @return a {@link ffx.potential.bonded.Atom} object.
192    */
193   public Atom getAtom(String name) {
194     for (Atom a : getAtomList()) {
195       if (a.getName().equalsIgnoreCase(name)) {
196         return a;
197       }
198     }
199     return null;
200   }
201 
202   /**
203    * Getter for the field <code>chainID</code>.
204    *
205    * @return a {@link java.lang.Character} object.
206    */
207   public Character getChainID() {
208     return chainID;
209   }
210 
211   public String getKey() {
212     return residueNum + residueName + segID;
213   }
214 
215   /**
216    * Getter for the field <code>residueName</code>.
217    *
218    * @return a {@link java.lang.String} object.
219    */
220   public String getResidueName() {
221     return residueName;
222   }
223 
224   /**
225    * getResidueNumber
226    *
227    * @return The residue number.
228    */
229   public int getResidueNumber() {
230     return residueNum;
231   }
232 
233   /**
234    * Getter for the field <code>segID</code>.
235    *
236    * @return a {@link java.lang.String} object.
237    */
238   public String getSegID() {
239     return segID;
240   }
241 
242   @Override
243   public int hashCode() {
244     return Objects.hash(residueNum, residueName, segID);
245   }
246 
247   /** {@inheritDoc} */
248   @Override
249   public void setName(String name) {
250     if (name != null) {
251       if (segID != null) {
252         super.setName(name + "-" + residueNum + " " + segID);
253       } else {
254         super.setName(name);
255       }
256       this.residueName = name;
257     }
258   }
259 }