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  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    private DistanceMatrix.NeighborDistances[][] distanceMatrix;
85  
86    public DistanceRegion(
87        int nt, int nResidues, Crystal crystal, int[][][] lists, IntegerSchedule schedule) {
88      distanceLoops = new DistanceLoop[nt];
89      this.nResidues = nResidues;
90      this.crystal = crystal;
91      this.nSymm = crystal.spaceGroup.getNumberOfSymOps();
92      this.lists = lists;
93      for (int i = 0; i < nt; i++) {
94        distanceLoops[i] = new DistanceLoop();
95      }
96      pairwiseSchedule = schedule;
97    }
98  
99    public void init(
100       DistanceMatrix dM,
101       MolecularAssembly molecularAssembly,
102       Residue[] allResiduesArray,
103       AlgorithmListener algorithmListener,
104       DistanceMatrix.NeighborDistances[][] distanceMatrix) {
105     this.dM = dM;
106     this.molecularAssembly = molecularAssembly;
107     this.allResiduesArray = allResiduesArray;
108     this.algorithmListener = algorithmListener;
109     this.distanceMatrix = distanceMatrix;
110   }
111 
112   @Override
113   public void run() {
114     try {
115       int threadID = getThreadIndex();
116       execute(0, nResidues - 1, distanceLoops[threadID]);
117     } catch (Exception e) {
118       String message = " Exception computing residue-residue distances.";
119       logger.log(Level.SEVERE, message, e);
120     }
121   }
122 
123   /**
124    * Get the coordinates of a requested residue.
125    *
126    * @param i Residue index.
127    * @param residues Array of residues.
128    * @param rotamer Rotamer to apply.
129    * @return Returns the coordinates.
130    */
131   private double[][] getCoordinates(int i, Residue[] residues, Rotamer rotamer) {
132     synchronized (residues[i]) {
133       Residue residue = residues[i];
134       RotamerLibrary.applyRotamer(residue, rotamer);
135       return residue.storeCoordinateArray();
136     }
137   }
138 
139   private class DistanceLoop extends IntegerForLoop {
140 
141     @Override
142     public void run(int lb, int ub) {
143       // Loop over symmetry operators.
144       for (int iSymOp = 0; iSymOp < nSymm; iSymOp++) {
145         SymOp symOp = crystal.spaceGroup.getSymOp(iSymOp);
146         // Loop over residues.
147         for (int i = lb; i <= ub; i++) {
148           Residue residueI = allResiduesArray[i];
149           Rotamer[] rotamersI = residueI.getRotamers();
150           int lengthRi = rotamersI.length;
151           int[] list = lists[iSymOp][i];
152           // Loop over Residue i's rotamers
153           for (int ri = 0; ri < lengthRi; ri++) {
154             double[][] xi = getCoordinates(i, allResiduesArray, rotamersI[ri]);
155             // Loop over Residue i's neighbors.
156             for (int j : list) {
157               if (i == j) {
158                 continue;
159               }
160               Residue residueJ = allResiduesArray[j];
161               Rotamer[] rotamersJ = residueJ.getRotamers();
162               int lengthRj = rotamersJ.length;
163               // Loop over the neighbor's rotamers
164               for (int rj = 0; rj < lengthRj; rj++) {
165                 double[][] xj = getCoordinates(j, allResiduesArray, rotamersJ[rj]);
166                 if (getThreadIndex() == 0 && algorithmListener != null) {
167                   algorithmListener.algorithmUpdate(molecularAssembly);
168                 }
169                 double r = dM.interResidueDistance(xi, xj, symOp);
170                 if (i < j) {
171                   distanceMatrix[i][ri].storeDistance(j, rj, r);
172                 } else {
173                   distanceMatrix[j][rj].storeDistance(i, ri, r);
174                 }
175               }
176             }
177           }
178         }
179       }
180     }
181 
182     @Override
183     public IntegerSchedule schedule() {
184       return pairwiseSchedule;
185     }
186   }
187 }