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.ParallelRegion;
42  import edu.rit.pj.reduction.SharedDouble;
43  import ffx.algorithms.optimize.RotamerOptimization;
44  import ffx.potential.bonded.Residue;
45  
46  import java.util.ArrayList;
47  import java.util.Arrays;
48  import java.util.logging.Level;
49  import java.util.logging.Logger;
50  import java.util.stream.IntStream;
51  
52  import static java.lang.Double.isFinite;
53  import static java.lang.String.format;
54  
55  public class GoldsteinPairRegion extends ParallelRegion {
56  
57    private static final Logger logger = Logger.getLogger(GoldsteinPairRegion.class.getName());
58  
59    private RotamerOptimization rotamerOptimization;
60    private Residue[] residues;
61    private int i, riA, rjC;
62    private int j, riB, rjD;
63    private int[] possK;
64    private int nK;
65    private final GoldsteinRotamerPairLoop[] goldsteinRotamerPairLoop;
66    private final SharedDouble sharedSumOverK = new SharedDouble();
67    private ArrayList<Residue> blockedResidues;
68  
69    public GoldsteinPairRegion(int nThreads) {
70      goldsteinRotamerPairLoop = new GoldsteinRotamerPairLoop[nThreads];
71    }
72  
73    public void finish() {
74      for (GoldsteinRotamerPairLoop rotamerPairLoop : goldsteinRotamerPairLoop) {
75        blockedResidues.addAll(rotamerPairLoop.blockedResidues);
76      }
77    }
78  
79    public ArrayList<Residue> getMissedResidues() {
80      return blockedResidues;
81    }
82  
83    public double getSumOverK() {
84      return sharedSumOverK.get();
85    }
86  
87    /**
88     * Initializes a ParallelRegion to attempt the elimination of riA,rjC by riB,rjD.
89     *
90     * @param residues The residue array.
91     * @param i First residue of the pair.
92     * @param riA First member of the pair to attempt eliminating.
93     * @param riB First member of the pair to try eliminating by.
94     * @param j Second residue of the pair.
95     * @param rjC Second member of the pair to attempt eliminating.
96     * @param rjD Second member of the pair to try eliminating by.
97     * @param bidiResNeighbors All interaction partners of a Residue, including prior residues
98     * @param rotamerOptimization RotamerOptimization instance.
99     */
100   public void init(Residue[] residues, int i, int riA, int riB, int j, int rjC, int rjD,
101       int[][] bidiResNeighbors, RotamerOptimization rotamerOptimization) {
102     this.residues = residues;
103     this.i = i;
104     this.riA = riA;
105     this.riB = riB;
106     this.j = j;
107     this.rjC = rjC;
108     this.rjD = rjD;
109     this.rotamerOptimization = rotamerOptimization;
110     int[] nI = bidiResNeighbors[i];
111     int[] nJ = bidiResNeighbors[j];
112     IntStream kStream = IntStream.concat(Arrays.stream(nI), Arrays.stream(nJ));
113     possK = kStream.distinct().filter(k -> (k != i && k != j)).sorted().toArray();
114     nK = possK.length;
115   }
116 
117   @Override
118   public void run() {
119     int threadID = getThreadIndex();
120     if (goldsteinRotamerPairLoop[threadID] == null) {
121       goldsteinRotamerPairLoop[threadID] = new GoldsteinRotamerPairLoop();
122     }
123     try {
124       execute(0, nK - 1, goldsteinRotamerPairLoop[threadID]);
125     } catch (Exception e) {
126       logger.log(Level.WARNING, " Exception in GoldsteinPairRegion.", e);
127     }
128   }
129 
130   public void start() {
131     sharedSumOverK.set(0.0);
132     blockedResidues = new ArrayList<>();
133   }
134 
135   private class GoldsteinRotamerPairLoop extends IntegerForLoop {
136 
137     double sumOverK;
138     ArrayList<Residue> blockedResidues;
139 
140     @Override
141     public void finish() {
142       sharedSumOverK.addAndGet(sumOverK);
143     }
144 
145     @Override
146     public void run(int lb, int ub) {
147       if (blockedResidues.isEmpty()) {
148         double locSumOverK = rotamerOptimization.goldsteinPairSumOverK(residues, lb, ub, i, riA, riB,
149             j, rjC, rjD, blockedResidues, possK);
150         // Should be redundant checks.
151         if (isFinite(locSumOverK) && blockedResidues.isEmpty()) {
152           sumOverK += locSumOverK;
153         } else {
154           sumOverK = 0;
155         }
156       } else {
157         rotamerOptimization.logIfRank0(
158             format(" Skipping %d to %d because we cannot eliminate", lb, ub), Level.FINE);
159       }
160     }
161 
162     @Override
163     public void start() {
164       sumOverK = 0.0;
165       blockedResidues = new ArrayList<>();
166     }
167   }
168 }