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   * The GKEnergyQI class computes the Generalized Kirkwood energy and forces using a QI frame.
49   */
50  public class GKEnergyQI {
51  
52    private final GKSource gkSource;
53    private final GKTensorQI gkMonopole;
54    private final GKTensorQI gkDipole;
55    private final GKTensorQI gkQuadrupole;
56  
57    /**
58     * Compute the GK Energy using a QI frame.
59     *
60     * @param soluteDielectric  Solute dielectric constant.
61     * @param solventDielectric Solvent dielectric constant.
62     * @param gkc               The GK interaction parameter.
63     * @param gradient          If true, the gradient will be computed.
64     */
65    public GKEnergyQI(double soluteDielectric, double solventDielectric, double gkc, boolean gradient) {
66      int monopoleOrder = 2;
67      int dipoleOrder = 3;
68      int quadrupoleOrder = 4;
69      if (gradient) {
70        monopoleOrder = 3;
71        dipoleOrder = 4;
72        quadrupoleOrder = 5;
73      }
74      gkSource = new GKSource(quadrupoleOrder, gkc);
75      gkMonopole = new GKTensorQI(MONOPOLE, monopoleOrder, gkSource, soluteDielectric, solventDielectric);
76      gkDipole = new GKTensorQI(DIPOLE, dipoleOrder, gkSource, soluteDielectric, solventDielectric);
77      gkQuadrupole = new GKTensorQI(QUADRUPOLE, quadrupoleOrder, gkSource, soluteDielectric, solventDielectric);
78    }
79  
80    /**
81     * Initialize the potential.
82     *
83     * @param r   The separation. vector.
84     * @param r2  The squared separation.
85     * @param rbi The Born radius of atom i.
86     * @param rbk The Born radius of atom k.
87     */
88    public void initPotential(double[] r, double r2, double rbi, double rbk) {
89      gkSource.generateSource(POTENTIAL, QUADRUPOLE, r2, rbi, rbk);
90      gkMonopole.setR(r);
91      gkDipole.setR(r);
92      gkQuadrupole.setR(r);
93      gkMonopole.generateTensor();
94      gkDipole.generateTensor();
95      gkQuadrupole.generateTensor();
96    }
97  
98    /**
99     * Initialize for computing Born chain-rule terms.
100    *
101    * @param r   The separation vector.
102    * @param r2  The squared separation.
103    * @param rbi The Born radius of atom i.
104    * @param rbk The Born radius of atom k.
105    */
106   public void initBorn(double[] r, double r2, double rbi, double rbk) {
107     gkSource.generateSource(BORN, QUADRUPOLE, r2, rbi, rbk);
108     gkMonopole.setR(r);
109     gkDipole.setR(r);
110     gkQuadrupole.setR(r);
111     gkMonopole.generateTensor();
112     gkDipole.generateTensor();
113     gkQuadrupole.generateTensor();
114   }
115 
116   /**
117    * Compute the multipole energy.
118    *
119    * @param mI The polarizable multipole of atom i.
120    * @param mK The polarizable multipole of atom k.
121    * @return The multipole energy.
122    */
123   public double multipoleEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
124     double em = gkMonopole.multipoleEnergy(mI, mK);
125     double ed = gkDipole.multipoleEnergy(mI, mK);
126     double eq = gkQuadrupole.multipoleEnergy(mI, mK);
127     return em + ed + eq;
128   }
129 
130   /**
131    * Compute the polarization energy.
132    *
133    * @param mI The polarizable multipole of atom i.
134    * @param mK The polarizable multipole of atom k.
135    * @return The polarization energy.
136    */
137   public double polarizationEnergy(PolarizableMultipole mI, PolarizableMultipole mK) {
138     double emp = gkMonopole.polarizationEnergy(mI, mK);
139     double edp = gkDipole.polarizationEnergy(mI, mK);
140     double eqp = gkQuadrupole.polarizationEnergy(mI, mK);
141     return emp + edp + eqp;
142   }
143 
144   /**
145    * Compute the multipole energy and gradient.
146    *
147    * @param mI      The polarizable multipole of atom i.
148    * @param mK      The polarizable multipole of atom k.
149    * @param gradI   The gradient for atom i.
150    * @param torqueI The torque on atom i.
151    * @param torqueK The torque on atom k.
152    * @return The multipole energy.
153    */
154   public double multipoleEnergyAndGradient(PolarizableMultipole mI, PolarizableMultipole mK,
155                                            double[] gradI, double[] torqueI, double[] torqueK) {
156     double[] gI = new double[3];
157     double[] gK = new double[3];
158     double[] tI = new double[3];
159     double[] tK = new double[3];
160     double em = gkMonopole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
161     for (int j = 0; j < 3; j++) {
162       gradI[j] = gI[j];
163       torqueI[j] = tI[j];
164       torqueK[j] = tK[j];
165     }
166     fill(gI, 0.0);
167     fill(gK, 0.0);
168     fill(tI, 0.0);
169     fill(tK, 0.0);
170     double ed = gkDipole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
171     for (int j = 0; j < 3; j++) {
172       gradI[j] += gI[j];
173       torqueI[j] += tI[j];
174       torqueK[j] += tK[j];
175     }
176     fill(gI, 0.0);
177     fill(gK, 0.0);
178     fill(tI, 0.0);
179     fill(tK, 0.0);
180     double eq = gkQuadrupole.multipoleEnergyAndGradient(mI, mK, gI, gK, tI, tK);
181     for (int j = 0; j < 3; j++) {
182       gradI[j] += gI[j];
183       torqueI[j] += tI[j];
184       torqueK[j] += tK[j];
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,
201                                               double mutualMask, 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 True if mutual polarization is included.
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 }