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.potential.cli;
39  
40  import static ffx.utilities.StringUtils.parseAtomRanges;
41  
42  import ffx.potential.MolecularAssembly;
43  import ffx.potential.bonded.Atom;
44  
45  import java.util.List;
46  import java.util.function.BiConsumer;
47  import java.util.logging.Logger;
48  import javax.annotation.Nonnull;
49  import javax.annotation.Nullable;
50  
51  import picocli.CommandLine.ArgGroup;
52  import picocli.CommandLine.Option;
53  
54  /**
55   * Represents command line options for scripts that support atom selections.
56   *
57   * @author Michael J. Schnieders
58   * @since 1.0
59   */
60  public class AtomSelectionOptions {
61  
62    private static final Logger logger = Logger.getLogger(AtomSelectionOptions.class.getName());
63  
64    /**
65     * The ArgGroup keeps the Atom Selection Options together when printing help.
66     */
67    @ArgGroup(heading = "%n Atom Selection Options%n", validate = false)
68    private final AtomSelectionOptionGroup group = new AtomSelectionOptionGroup();
69  
70    public static void actOnAtoms(@Nonnull MolecularAssembly assembly, @Nullable String selection,
71                                  @Nonnull BiConsumer<Atom, Boolean> action, @Nonnull String description) {
72      if (selection == null || selection.equalsIgnoreCase("")) {
73        // Empty or null string -- no changes.
74        return;
75      }
76  
77      Atom[] atoms = assembly.getAtomArray();
78  
79      // No atoms selected.
80      if (selection.equalsIgnoreCase("NONE")) {
81        for (Atom atom : atoms) {
82          action.accept(atom, false);
83        }
84        logger.info(" No atoms are " + description + ".\n");
85        return;
86      }
87  
88      // All atoms selected
89      if (selection.equalsIgnoreCase("ALL")) {
90        for (Atom atom : atoms) {
91          action.accept(atom, true);
92        }
93        logger.info(" All atoms are " + description + ".\n");
94        return;
95      }
96  
97      // A range(s) of atoms are active.
98      int nAtoms = atoms.length;
99      for (Atom atom : atoms) {
100       action.accept(atom, false);
101     }
102 
103     List<Integer> atomRanges = parseAtomRanges(description, selection, nAtoms);
104     for (int i : atomRanges) {
105       action.accept(atoms[i], true);
106     }
107     logger.info("\n " + description + " atoms set to: " + selection);
108 
109   }
110 
111   /**
112    * --aa or --activeAtoms Ranges of active atoms [NONE, ALL, Range(s): 1-3,6-N].
113    *
114    * @return Returns active atoms.
115    */
116   public String getActiveAtoms() {
117     return group.activeAtoms;
118   }
119 
120   /**
121    * Set active atoms for a MolecularAssembly.
122    *
123    * @param molecularAssembly a {@link ffx.potential.MolecularAssembly} object.
124    */
125   public void setActiveAtoms(MolecularAssembly molecularAssembly) {
126     // First, evaluate the inactive atom selection.
127     setInactive(molecularAssembly);
128 
129     // Second, evaluate the active atom selection, which takes precedence over the inactive flag.
130     setActive(molecularAssembly);
131   }
132 
133   /**
134    * --ia or --inactiveAtoms Ranges of inactive atoms [NONE, ALL, Range(s): 1-3,6-N].
135    *
136    * @return Returns inactive atoms.
137    */
138   public String getInactiveAtoms() {
139     return group.inactiveAtoms;
140   }
141 
142   /**
143    * Check if either the active or inactive atom selection is set.
144    *
145    * @return True if one of the fields is not empty.
146    */
147   public boolean isAtomSelectionSet() {
148     if (group.activeAtoms != null && !group.activeAtoms.isEmpty()) {
149       return true;
150     }
151     return group.inactiveAtoms != null && !group.inactiveAtoms.isEmpty();
152   }
153 
154   private void setInactive(MolecularAssembly assembly) {
155     actOnAtoms(assembly, getInactiveAtoms(), (Atom a, Boolean b) -> a.setActive(!b), "Inactive");
156   }
157 
158   private void setActive(MolecularAssembly assembly) {
159     actOnAtoms(assembly, getActiveAtoms(), Atom::setActive, "Active");
160   }
161 
162   /**
163    * Collection of Atom Selection Options.
164    */
165   private static class AtomSelectionOptionGroup {
166 
167     /**
168      * --aa or --activeAtoms Ranges of active atoms [NONE, ALL, Range(s): 1-3,6-N].
169      */
170     @Option(names = {"--aa",
171         "--active"}, paramLabel = "<selection>", defaultValue = "",
172         description = "Ranges of active atoms [NONE, ALL, Range(s): 1-3,6-N].")
173     public String activeAtoms = "";
174 
175     /**
176      * --ia or --inactiveAtoms Ranges of inactive atoms [NONE, ALL, Range(s): 1-3,6-N].
177      */
178     @Option(names = {"--ia",
179         "--inactive"}, paramLabel = "<selection>", defaultValue = "",
180         description = "Ranges of inactive atoms [NONE, ALL, Range(s): 1-3,6-N].")
181     public String inactiveAtoms = "";
182   }
183 }