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