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.commands.test;
39  
40  import ffx.algorithms.cli.AlgorithmsCommand;
41  import ffx.numerics.Potential;
42  import ffx.potential.bonded.Atom;
43  import ffx.potential.bonded.Molecule;
44  import ffx.utilities.FFXBinding;
45  import picocli.CommandLine.Command;
46  import picocli.CommandLine.Option;
47  import picocli.CommandLine.Parameters;
48  
49  import java.util.ArrayList;
50  import java.util.Arrays;
51  import java.util.List;
52  
53  import static java.lang.String.format;
54  
55  /**
56   * The FindRestraints script identifies guest molecule atoms that should be restrained based on
57   * their proximity to specific atoms in a host molecule.
58   * <br>
59   * Usage:
60   * <br>
61   * ffxc test.FindRestraints [options] &lt;filename&gt;
62   */
63  @Command(description = " Find guest atoms to restrain near host molecule.", name = "test.FindRestraints")
64  public class FindRestraints extends AlgorithmsCommand {
65  
66    /**
67     * --hostName Molecule name of the host in the file.
68     */
69    @Option(names = {"--hostName"}, paramLabel = "BCD", defaultValue = "BCD",
70        description = "Host molecule name in the file.")
71    private String hostName;
72  
73    /**
74     * --guestName Molecule name of the guest in the file.
75     */
76    @Option(names = {"--guestName"}, paramLabel = "LIG", defaultValue = "LIG",
77        description = "Ligand molecule name in the file.")
78    private String guestName;
79  
80    /**
81     * --distanceCutoff Cutoff to use when selecting guest atoms near host COM.
82     */
83    @Option(names = {"--distanceCutoff"}, paramLabel = "5", defaultValue = "5",
84        description = "Cutoff to use when selecting guest atoms near host COM")
85    private double distanceCutoff;
86  
87    /**
88     * One or more filenames.
89     */
90    @Parameters(arity = "1..*", paramLabel = "files",
91        description = "XYZ or PDB input files.")
92    private List<String> filenames;
93  
94    /**
95     * Creation of a public field to try and make the JUnit test work, original code does not declare this as a public field.
96     * Originally it is declared in the run method
97     */
98    public Potential potential;
99  
100   /**
101    * Get the potential object.
102    * @return The potential object.
103    */
104   public Potential getPotentialObject() {
105     return potential;
106   }
107 
108   /**
109    * FindRestraints Constructor.
110    */
111   public FindRestraints() {
112     super();
113   }
114 
115   /**
116    * FindRestraints Constructor.
117    * @param binding The Binding to use.
118    */
119   public FindRestraints(FFXBinding binding) {
120     super(binding);
121   }
122 
123   /**
124    * FindRestraints constructor that sets the command line arguments.
125    * @param args Command line arguments.
126    */
127   public FindRestraints(String[] args) {
128     super(args);
129   }
130 
131   /**
132    * {@inheritDoc}
133    */
134   @Override
135   public FindRestraints run() {
136     if (!init()) {
137       return this;
138     }
139 
140     activeAssembly = getActiveAssembly(filenames.get(0));
141     if (activeAssembly == null) {
142       logger.info(helpString());
143       return this;
144     }
145 
146     Molecule[] molArr = activeAssembly.getMoleculeArray();
147 
148     List<Atom> restrainHostList = new ArrayList<>();
149     List<Atom> restrainList = new ArrayList<>();
150     double[] COM = new double[3];
151     double[] subCOM = new double[3];
152     int[] restrainHostIndices = new int[]{11, 16, 17, 20, 23, 26, 31, 32, 39, 40, 51, 63, 64, 70, 71, 82, 94, 95, 101, 102, 113, 125, 126, 132, 133, 144, 156, 157, 163, 164, 175, 187, 188, 191, 198};
153     for (Molecule molecule : molArr) {
154       logger.info(format(" Molecule name: " + molecule.getName()));
155       if (molecule.getName().contains(hostName)) {
156         Atom[] host_atoms = molecule.getAtomList().toArray(new Atom[0]);
157         COM = getCOM(host_atoms);
158         logger.info(format(" Center of mass of host molecule: " + Arrays.toString(COM)));
159         for (Atom atom : host_atoms) {
160           if (contains(restrainHostIndices, atom.getIndex())) {
161             restrainHostList.add(atom);
162             logger.info(format(" Atom: " + atom));
163           }
164         }
165         Atom[] subAtoms = restrainHostList.toArray(new Atom[0]);
166         subCOM = getCOM(subAtoms);
167         logger.info(format(" Center of mass of subsection host atoms: " + Arrays.toString(subCOM)));
168         double comdist = Math.sqrt(Math.pow(subCOM[0] - COM[0], 2) +
169             Math.pow(subCOM[1] - COM[1], 2) +
170             Math.pow(subCOM[2] - COM[2], 2));
171         logger.info(format(" Distance between COMs: " + comdist));
172       } else if (molecule.getName().contains(guestName)) {
173         Atom[] guest_atoms = molecule.getAtomList().toArray(new Atom[0]);
174         for (Atom atom : guest_atoms) {
175           double dist = Math.sqrt(Math.pow(atom.getXYZ().get()[0] - subCOM[0], 2) +
176               Math.pow(atom.getXYZ().get()[1] - subCOM[1], 2) +
177               Math.pow(atom.getXYZ().get()[2] - subCOM[2], 2));
178           //logger.info(format("Atom: " + atom));
179           //logger.info(format("XYZ: " + atom.getXYZ().get()));
180           //logger.info(format("Distance from host COM: " + dist));
181 
182           if (dist < distanceCutoff && atom.isHeavy()) {
183             restrainList.add(atom);
184           }
185         }
186       }
187     }
188     logger.info(format(" Number of atoms to restrain: " + restrainList.size()));
189     int[] restrainIndices = restrainList.stream()
190         .mapToInt(Atom::getIndex)
191         .toArray();
192     logger.info(format(" Restrain list indices: " + Arrays.toString(restrainIndices)));
193 
194     return this;
195   }
196 
197   /**
198    * Gets the center of mass of a set of atoms.
199    *
200    * @param atoms Array of atoms
201    * @return x,y,z coordinates of center of mass
202    */
203   private static double[] getCOM(Atom[] atoms) {
204     // Get center of mass of moleculeOneAtoms
205     double[] COM = new double[3];
206     double totalMass = 0.0;
207     for (Atom s : atoms) {
208       double[] pos = s.getXYZ().get();
209       COM[0] += pos[0] * s.getMass();
210       COM[1] += pos[1] * s.getMass();
211       COM[2] += pos[2] * s.getMass();
212       totalMass += s.getMass();
213     }
214     totalMass = 1 / totalMass;
215     COM[0] *= totalMass;
216     COM[1] *= totalMass;
217     COM[2] *= totalMass;
218 
219     return COM;
220   }
221 
222   /**
223    * Checks if an int array contains a specific value.
224    *
225    * @param array Array to search
226    * @param value Value to find
227    * @return true if array contains value
228    */
229   private static boolean contains(int[] array, int value) {
230     return Arrays.stream(array).anyMatch(element -> element == value);
231   }
232 }