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-2025.
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.numerics.multipole;
39  
40  import static ffx.numerics.multipole.GKMultipoleOrder.DIPOLE;
41  import static ffx.numerics.multipole.GKMultipoleOrder.MONOPOLE;
42  import static ffx.numerics.multipole.GKMultipoleOrder.QUADRUPOLE;
43  import static ffx.numerics.multipole.GKTensorMode.BORN;
44  import static ffx.numerics.multipole.GKTensorMode.POTENTIAL;
45  import static java.util.Arrays.fill;
46  
47  /**
48   * GKEnergyGlobal computes the generalized Kirkwood energy and forces in a global frame.
49   */
50  public class GKEnergyGlobal {
51  
52    private final GKSource gkSource;
53    private final GKTensorGlobal gkMonopole;
54    private final GKTensorGlobal gkDipole;
55    private final GKTensorGlobal gkQuadrupole;
56  
57    /**
58     * Constructor for GKEnergyGlobal.
59     *
60     * @param gkc      The GK generalizing function constant.
61     * @param epsilon  The solvent dielectric.
62     * @param gradient If true, compute the gradient and torque.
63     */
64    public GKEnergyGlobal(double gkc, double epsilon, boolean gradient) {
65      int monopoleOrder = 2;
66      int dipoleOrder = 3;
67      int quadrupoleOrder = 4;
68      if (gradient) {
69        monopoleOrder = 3;
70        dipoleOrder = 4;
71        quadrupoleOrder = 5;
72      }
73      gkSource = new GKSource(quadrupoleOrder, gkc);
74      gkMonopole = new GKTensorGlobal(MONOPOLE, monopoleOrder, gkSource, 1.0, epsilon);
75      gkDipole = new GKTensorGlobal(DIPOLE, dipoleOrder, gkSource, 1.0, epsilon);
76      gkQuadrupole = new GKTensorGlobal(QUADRUPOLE, quadrupoleOrder, gkSource, 1.0, epsilon);
77    }
78  
79    /**
80     * Initialize the potential.
81     *
82     * @param r   The separation. vector.
83     * @param r2  The squared separation.
84     * @param rbi The Born radius of atom i.
85     * @param rbk The Born radius of atom k.
86     */
87    public void initPotential(double[] r, double r2, double rbi, double rbk) {
88      gkSource.generateSource(POTENTIAL, QUADRUPOLE, r2, rbi, rbk);
89      gkMonopole.setR(r);
90      gkDipole.setR(r);
91      gkQuadrupole.setR(r);
92      gkMonopole.generateTensor();
93      gkDipole.generateTensor();
94      gkQuadrupole.generateTensor();
95    }
96  
97    /**
98     * Initialize for computing Born chain-rule terms.
99     *
100    * @param r   The separation vector.
101    * @param r2  The squared separation.
102    * @param rbi The Born radius of atom i.
103    * @param rbk The Born radius of atom k.
104    */
105   public void initBorn(double[] r, double r2, double rbi, double rbk) {
106     gkSource.generateSource(BORN, QUADRUPOLE, r2, rbi, rbk);
107     gkMonopole.setR(r);
108     gkDipole.setR(r);
109     gkQuadrupole.setR(r);
110     gkMonopole.generateTensor();
111     gkDipole.generateTensor();
112     gkQuadrupole.generateTensor();
113   }
114 
115   /**
116    * Compute the multipole energy.
117    *
118    * @param mI The polarizable multipole of atom i.
119    * @param mK The polarizable multipole of atom k.
120    * @return The multipole energy.
121    */
122   public double multipoleEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
123     double em = gkMonopole.multipoleEnergy(mI, mK);
124     double ed = gkDipole.multipoleEnergy(mI, mK);
125     double eq = gkQuadrupole.multipoleEnergy(mI, mK);
126     return em + ed + eq;
127   }
128 
129   /**
130    * Compute the polarization energy.
131    *
132    * @param mI The polarizable multipole of atom i.
133    * @param mK The polarizable multipole of atom k.
134    * @return The polarization energy.
135    */
136   public double polarizationEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
137     double emp = gkMonopole.polarizationEnergy(mI, mK);
138     double edp = gkDipole.polarizationEnergy(mI, mK);
139     double eqp = gkQuadrupole.polarizationEnergy(mI, mK);
140     return emp + edp + eqp;
141   }
142 
143   /**
144    * Compute the multipole energy and gradient.
145    *
146    * @param mI      The polarizable multipole of atom i.
147    * @param mK      The polarizable multipole of atom k.
148    * @param gradI   The gradient for atom i.
149    * @param torqueI The torque on atom i.
150    * @param torqueK The torque on atom k.
151    * @return The multipole energy.
152    */
153   public double multipoleEnergyAndGradient(PolarizableMultipole mI, PolarizableMultipole mK,
154                                            double[] gradI, double[] torqueI, double[] torqueK) {
155     double[] gI = new double[3];
156     double[] gK = new double[3];
157     double[] tI = new double[3];
158     double[] tK = new double[3];
159     double em = gkMonopole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
160     for (int j = 0; j < 3; j++) {
161       gradI[j] = gI[j];
162       torqueI[j] = tI[j];
163       torqueK[j] = tK[j];
164     }
165     fill(gI, 0.0);
166     fill(gK, 0.0);
167     fill(tI, 0.0);
168     fill(tK, 0.0);
169     double ed = gkDipole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
170     for (int j = 0; j < 3; j++) {
171       gradI[j] += gI[j];
172       torqueI[j] += tI[j];
173       torqueK[j] += tK[j];
174     }
175     fill(gI, 0.0);
176     fill(gK, 0.0);
177     fill(tI, 0.0);
178     fill(tK, 0.0);
179     double eq = gkQuadrupole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
180     for (int j = 0; j < 3; j++) {
181       gradI[j] += gI[j];
182       torqueI[j] += tI[j];
183       torqueK[j] += tK[j];
184     }
185 
186     return em + ed + eq;
187   }
188 
189   /**
190    * Compute the polarization energy and gradient.
191    *
192    * @param mI         The polarizable multipole of atom i.
193    * @param mK         The polarizable multipole of atom k.
194    * @param mutualMask The mutual polarization mask.
195    * @param gradI      The gradient for atom i.
196    * @param torqueI    The torque on atom i.
197    * @param torqueK    The torque on atom k.
198    * @return The polarization energy.
199    */
200   public double polarizationEnergyAndGradient(PolarizableMultipole mI, PolarizableMultipole mK, double mutualMask,
201                                               double[] gradI, double[] torqueI, double[] torqueK) {
202     double[] gI = new double[3];
203     double[] tI = new double[3];
204     double[] tK = new double[3];
205     double emp = gkMonopole.polarizationEnergyAndGradient(mI, mK, 1.0, 1.0, mutualMask, gI, tI, tK);
206     for (int j = 0; j < 3; j++) {
207       gradI[j] = gI[j];
208       torqueI[j] = tI[j];
209       torqueK[j] = tK[j];
210     }
211     fill(gI, 0.0);
212     fill(tI, 0.0);
213     fill(tK, 0.0);
214     double edp = gkDipole.polarizationEnergyAndGradient(mI, mK, 1.0, 1.0, mutualMask, gI, tI, tK);
215     for (int j = 0; j < 3; j++) {
216       gradI[j] += gI[j];
217       torqueI[j] += tI[j];
218       torqueK[j] += tK[j];
219     }
220     fill(gI, 0.0);
221     fill(tI, 0.0);
222     fill(tK, 0.0);
223     double eqp = gkQuadrupole.polarizationEnergyAndGradient(mI, mK, 1.0, 1.0, mutualMask, gI, tI, tK);
224     for (int j = 0; j < 3; j++) {
225       gradI[j] += gI[j];
226       torqueI[j] += tI[j];
227       torqueK[j] += tK[j];
228     }
229 
230     // Sum the GK polarization interaction energy.
231     return emp + edp + eqp;
232   }
233 
234   /**
235    * Compute the Born chain-rule term for the multipole energy.
236    *
237    * @param mI The polarizable multipole of atom i.
238    * @param mK The polarizable multipole of atom k.
239    * @return The Born chain-rule term.
240    */
241   public double multipoleEnergyBornGrad(PolarizableMultipole mI, PolarizableMultipole mK) {
242     double db = gkMonopole.multipoleEnergyBornGrad(mI, mK);
243     db += gkDipole.multipoleEnergyBornGrad(mI, mK);
244     db += gkQuadrupole.multipoleEnergyBornGrad(mI, mK);
245     return db;
246   }
247 
248   /**
249    * Compute the Born chain-rule term for the polarization energy.
250    *
251    * @param mI     The polarizable multipole of atom i.
252    * @param mK     The polarizable multipole of atom k.
253    * @param mutual If true, compute the mutual polarization contribution.
254    * @return The Born chain-rule term.
255    */
256   public double polarizationEnergyBornGrad(PolarizableMultipole mI, PolarizableMultipole mK,
257                                            boolean mutual) {
258     // Compute the GK polarization Born chain-rule term.
259     double db = gkMonopole.polarizationEnergyBornGrad(mI, mK);
260     db += gkDipole.polarizationEnergyBornGrad(mI, mK);
261     db += gkQuadrupole.polarizationEnergyBornGrad(mI, mK);
262     // Add the mutual polarization contribution to Born chain-rule term.
263     if (mutual) {
264       db += gkDipole.mutualPolarizationEnergyBornGrad(mI, mK);
265     }
266     return db;
267   }
268 
269 }