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.algorithms.optimize.manybody;
39  
40  import edu.rit.pj.IntegerForLoop;
41  import edu.rit.pj.IntegerSchedule;
42  import edu.rit.pj.ParallelRegion;
43  import ffx.algorithms.AlgorithmListener;
44  import ffx.crystal.Crystal;
45  import ffx.crystal.SymOp;
46  import ffx.potential.MolecularAssembly;
47  import ffx.potential.bonded.Residue;
48  import ffx.potential.bonded.Rotamer;
49  import ffx.potential.bonded.RotamerLibrary;
50  
51  import java.util.logging.Level;
52  import java.util.logging.Logger;
53  
54  /** Compute the minimum distance between each pair of residues for all rotamer permutations. */
55  public class DistanceRegion extends ParallelRegion {
56  
57    private static final Logger logger = Logger.getLogger(DistanceRegion.class.getName());
58    private final DistanceLoop[] distanceLoops;
59    private final int nResidues;
60    private final Crystal crystal;
61    private final int nSymm;
62    private final int[][][] lists;
63    private final IntegerSchedule pairwiseSchedule;
64    /**
65     * AlgorithmListener who should receive updates as the optimization runs.
66     */
67    protected AlgorithmListener algorithmListener;
68    /**
69     * The DistanceMatrix to fill.
70     */
71    private DistanceMatrix dM;
72    /**
73     * MolecularAssembly to perform rotamer optimization on.
74     */
75    private MolecularAssembly molecularAssembly;
76    /**
77     * An array of all residues being optimized. Note that Box and Window optimizations operate on
78     * subsets of this list.
79     */
80    private Residue[] allResiduesArray;
81    /**
82     * The minimum distance between atoms of a residue pair, taking into account interactions with
83     * symmetry mates.
84     */
85    private DistanceMatrix.NeighborDistances[][] distanceMatrix;
86  
87    public DistanceRegion(
88        int nt, int nResidues, Crystal crystal, int[][][] lists, IntegerSchedule schedule) {
89      distanceLoops = new DistanceLoop[nt];
90      this.nResidues = nResidues;
91      this.crystal = crystal;
92      this.nSymm = crystal.spaceGroup.getNumberOfSymOps();
93      this.lists = lists;
94      for (int i = 0; i < nt; i++) {
95        distanceLoops[i] = new DistanceLoop();
96      }
97      pairwiseSchedule = schedule;
98    }
99  
100   public void init(
101       DistanceMatrix dM,
102       MolecularAssembly molecularAssembly,
103       Residue[] allResiduesArray,
104       AlgorithmListener algorithmListener,
105       DistanceMatrix.NeighborDistances[][] distanceMatrix) {
106     this.dM = dM;
107     this.molecularAssembly = molecularAssembly;
108     this.allResiduesArray = allResiduesArray;
109     this.algorithmListener = algorithmListener;
110     this.distanceMatrix = distanceMatrix;
111   }
112 
113   @Override
114   public void run() {
115     try {
116       int threadID = getThreadIndex();
117       execute(0, nResidues - 1, distanceLoops[threadID]);
118     } catch (Exception e) {
119       String message = " Exception computing residue-residue distances.";
120       logger.log(Level.SEVERE, message, e);
121     }
122   }
123 
124   /**
125    * Get the coordinates of a requested residue.
126    *
127    * @param i Residue index.
128    * @param residues Array of residues.
129    * @param rotamer Rotamer to apply.
130    * @return Returns the coordinates.
131    */
132   private double[][] getCoordinates(int i, Residue[] residues, Rotamer rotamer) {
133     synchronized (residues[i]) {
134       Residue residue = residues[i];
135       RotamerLibrary.applyRotamer(residue, rotamer);
136       return residue.storeCoordinateArray();
137     }
138   }
139 
140   private class DistanceLoop extends IntegerForLoop {
141 
142     @Override
143     public void run(int lb, int ub) {
144       // Loop over symmetry operators.
145       for (int iSymOp = 0; iSymOp < nSymm; iSymOp++) {
146         SymOp symOp = crystal.spaceGroup.getSymOp(iSymOp);
147         // Loop over residues.
148         for (int i = lb; i <= ub; i++) {
149           Residue residueI = allResiduesArray[i];
150           Rotamer[] rotamersI = residueI.getRotamers();
151           int lengthRi = rotamersI.length;
152           int[] list = lists[iSymOp][i];
153           // Loop over Residue i's rotamers
154           for (int ri = 0; ri < lengthRi; ri++) {
155             double[][] xi = getCoordinates(i, allResiduesArray, rotamersI[ri]);
156             // Loop over Residue i's neighbors.
157             for (int j : list) {
158               if (i == j) {
159                 continue;
160               }
161               Residue residueJ = allResiduesArray[j];
162               Rotamer[] rotamersJ = residueJ.getRotamers();
163               int lengthRj = rotamersJ.length;
164               // Loop over the neighbor's rotamers
165               for (int rj = 0; rj < lengthRj; rj++) {
166                 double[][] xj = getCoordinates(j, allResiduesArray, rotamersJ[rj]);
167                 if (getThreadIndex() == 0 && algorithmListener != null) {
168                   algorithmListener.algorithmUpdate(molecularAssembly);
169                 }
170                 double r = dM.interResidueDistance(xi, xj, symOp);
171                 if (i < j) {
172                   distanceMatrix[i][ri].storeDistance(j, rj, r);
173                 } else {
174                   distanceMatrix[j][rj].storeDistance(i, ri, r);
175                 }
176               }
177             }
178           }
179         }
180       }
181     }
182 
183     @Override
184     public IntegerSchedule schedule() {
185       return pairwiseSchedule;
186     }
187   }
188 }