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.numerics.atomic.AtomicDoubleArray3D;
41  import ffx.potential.parameters.ForceField;
42  import ffx.potential.parameters.UreyBradleyType;
43  
44  import java.io.Serial;
45  import java.util.logging.Logger;
46  
47  /**
48   * The UreyBradley class.
49   *
50   * @author Michael J. Schnieders
51   * @since 1.0
52   */
53  public class UreyBradley extends BondedTerm {
54  
55    @Serial
56    private static final long serialVersionUID = 1L;
57  
58    private static final Logger logger = Logger.getLogger(UreyBradley.class.getName());
59  
60    /**
61     * Force field parameters to compute the Stretch-Bend energy.
62     */
63    public final UreyBradleyType ureyBradleyType;
64    /**
65     * The Angle this UreyBradley term is based on.
66     */
67    protected final Angle angle;
68    /**
69     * Scale factor to apply to Urey-Bradley term.
70     */
71    private double rigidScale = 1.0;
72  
73    /**
74     * Constructor for the UreyBradley class.
75     *
76     * @param a               a {@link ffx.potential.bonded.Angle} object.
77     * @param ureyBradleyType The Urey-Bradley type to apply.
78     */
79    public UreyBradley(Angle a, UreyBradleyType ureyBradleyType) {
80      super();
81      angle = a;
82      bonds = a.bonds;
83      atoms = a.atoms;
84      this.ureyBradleyType = ureyBradleyType;
85      setID_Key(false);
86    }
87  
88    /**
89     * Attempt to create a new UreyBradley for the specified Angle.
90     *
91     * @param angle      the Angle to create the UreyBradley from.
92     * @param forceField the ForceField parameters to apply.
93     * @return a new UreyBradley, or null.
94     */
95    public static UreyBradley ureyBradlyFactory(Angle angle, ForceField forceField) {
96      if (angle == null) {
97        return null;
98      }
99      UreyBradleyType ureyBradleyType = forceField.getUreyBradleyType(angle.angleType.getKey());
100     if (ureyBradleyType == null) {
101       return null;
102     }
103     return new UreyBradley(angle, ureyBradleyType);
104   }
105 
106   /**
107    * {@inheritDoc}
108    */
109   @Override
110   public int compareTo(BondedTerm ub) {
111     if (!ub.getClass().isInstance(this)) {
112       return super.compareTo(ub);
113     }
114     return angle.compareTo(((UreyBradley) ub).angle);
115   }
116 
117   /**
118    * {@inheritDoc}
119    *
120    * <p>Evaluate the Urey-Bradley energy.
121    */
122   @Override
123   public double energy(boolean gradient, int threadID, AtomicDoubleArray3D grad, AtomicDoubleArray3D lambdaGrad) {
124     value = 0.0;
125     energy = 0.0;
126     // Only compute this term if at least one atom is being used.
127     if (!getUse()) {
128       return energy;
129     }
130     var atomA = atoms[0];
131     var atomC = atoms[2];
132     var va = atomA.getXYZ();
133     var vc = atomC.getXYZ();
134     var vac = va.sub(vc);
135     value = vac.length();
136     var dv = value - ureyBradleyType.distance;
137     var dv2 = dv * dv;
138     energy = ureyBradleyType.ureyUnit * rigidScale * ureyBradleyType.forceConstant * dv2
139         * (1.0 + ureyBradleyType.cubic * dv + ureyBradleyType.quartic * dv2);
140     if (gradient) {
141       var deddt = 2.0 * ureyBradleyType.ureyUnit * rigidScale * ureyBradleyType.forceConstant * dv
142           * (1.0 + 1.5 * ureyBradleyType.cubic * dv + 2.0 * ureyBradleyType.quartic * dv2);
143       var de = 0.0;
144       if (value > 0.0) {
145         de = deddt / value;
146       }
147       var ia = atomA.getIndex() - 1;
148       var ic = atomC.getIndex() - 1;
149       grad.add(threadID, ia, vac.scaleI(de));
150       grad.sub(threadID, ic, vac);
151     }
152     return energy;
153   }
154 
155   /**
156    * log
157    */
158   public void log() {
159     logger.info(
160         String.format(" %s %6d-%s %6d-%s %6.4f  %6.4f  %10.4f", "Urey-Bradley", atoms[0].getIndex(),
161             atoms[0].getAtomType().name, atoms[2].getIndex(), atoms[2].getAtomType().name,
162             ureyBradleyType.distance, value, energy));
163   }
164 
165   /**
166    * Setter for the field <code>rigidScale</code>.
167    *
168    * @param rigidScale a double.
169    */
170   public void setRigidScale(double rigidScale) {
171     this.rigidScale = rigidScale;
172   }
173 }