Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2011-2023 The plumed team
3 : (see the PEOPLE file at the root of the distribution for a list of names)
4 :
5 : See http://www.plumed.org for more information.
6 :
7 : This file is part of plumed, version 2.
8 :
9 : plumed is free software: you can redistribute it and/or modify
10 : it under the terms of the GNU Lesser General Public License as published by
11 : the Free Software Foundation, either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : plumed is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU Lesser General Public License for more details.
18 :
19 : You should have received a copy of the GNU Lesser General Public License
20 : along with plumed. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 : #include "Group.h"
23 : #include "ActionRegister.h"
24 : #include "PlumedMain.h"
25 : #include "Value.h"
26 : #include "ActionWithValue.h"
27 : #include "ActionWithVirtualAtom.h"
28 : #include "tools/IFile.h"
29 : #include "tools/Tools.h"
30 : #include <string>
31 : #include <vector>
32 : #include <algorithm>
33 :
34 : namespace PLMD {
35 :
36 : //+PLUMEDOC GENERIC GROUP
37 : /*
38 : Define a group of atoms so that a particular list of atoms can be referenced with a single label in definitions of CVs or virtual atoms.
39 :
40 : The GROUP command can be used to define a list of atoms so that the group can be referenced in the definitions of other
41 : CVs or virtual atoms as shown below:
42 :
43 : ```plumed
44 : o: GROUP ATOMS=1,4,7,11,14
45 : h: GROUP ATOMS=2,3,5,6,8,9,12,13
46 : # compute the coordination among the two groups
47 : c: COORDINATION GROUPA=o GROUPB=h R_0=0.3
48 : # same could have been obtained without GROUP, just writing:
49 : # c: COORDINATION GROUPA=1,4,7,11,14 GROUPB=2,3,5,6,8,9,12,13
50 :
51 : # print the coordination on file 'colvar'
52 : PRINT ARG=c FILE=colvar
53 : ```
54 :
55 : The first group command here creates a group of atoms called `o` containing atoms 1, 4, 7, 11 and 14.
56 : The second group command here creates a group of toms called `h` containing atoms 2, 3, 5, 6, 8, 9, 12, and 13.
57 :
58 : As discussed on [this page](specifying_atoms.md) atoms in groups can be listed as comma separated numbers (i.e. `1,2,3,10,45,7,9`),
59 : simple positive ranges (i.e. `20-40`), ranges with a stride either positive or negative (i.e. `20-40:2` or `80-50:-2`) or as
60 : comma separated combinations of all the former methods (`1,2,4,5,10-20,21-40:2,80-50:-2`).
61 :
62 : Oftentime people will store the definitions in a separate file as has been done in the following example input.
63 :
64 : ```plumed
65 : INCLUDE FILE=extras/groups.dat
66 : # compute the coordination among the two groups
67 : c: COORDINATION GROUPA=groupa GROUPB=groupb R_0=0.3
68 : # print the coordination on file 'colvar'
69 : PRINT ARG=c FILE=colvar
70 : ```
71 :
72 : Storing the groups in the extra file is particularly useful if the groups include list of thousand atoms. Putting these definitions
73 : in a separate file ensures that the main plumed.dat file is not cluttered. You can even use a [GROMACS index file](https://manual.gromacs.org/archive/5.0.4/online/ndx.html)
74 : to hold the groups as illustrated in the input below:
75 :
76 : ```plumed
77 : # import group named 'Protein' from file index.ndx
78 : pro: GROUP NDX_FILE=extras/index.ndx NDX_GROUP=Protein
79 : # dump all the atoms of the protein on a trajectory file
80 : DUMPATOMS ATOMS=pro FILE=traj.gro
81 : ```
82 :
83 : Notice that you use the keyword `NDX_FILE` to set the name of the index file and `NDX_GROUP` to set the name of the group to be imported (default is first one).
84 : Further notice that starting from version 2.10 it is possible to directly use an `@ndx:` selector in the input to an action as shwn below:
85 :
86 : ```plumed
87 : DUMPATOMS ATOMS={@ndx:{extras/index.ndx Protein}} FILE=traj.gro
88 : ```
89 :
90 : Notice that it is possible to remove atoms from the list of atoms specified in a GROUP by using the keyword `REMOVE` as shown below:
91 :
92 : ```plumed
93 : # take one atom every three, that is oxygens
94 : ox: GROUP ATOMS=1-90:3
95 : # take the remaining atoms, that is hydrogens
96 : hy: GROUP ATOMS=1-90 REMOVE=ox
97 : DUMPATOMS ATOMS=ox FILE=ox.gro
98 : DUMPATOMS ATOMS=hy FILE=hy.gro
99 : ```
100 :
101 : You can also `SORT` the atoms in a group into ascending order by using the SORT keyword as shown below:
102 :
103 : ```plumed
104 : # If you ask for this group in the input to another action the atoms will be
105 : # in ascending order i.e. the specified atoms will be 2,3,4,4,5,6
106 : g: GROUP ATOMS=5,4,6,3,4,2 SORT
107 : ```
108 :
109 : or you can sort the atoms and remove duplicated atoms by using the `UNIQUE` flag
110 :
111 : ```plumed
112 : # If you ask for this group in the input to another action the duplicate atom specifications will be removed
113 : # and the atoms will be ascending order i.e. the specified atoms will be 2,3,4,5,6
114 : g: GROUP ATOMS=5,4,6,3,4,2 UNIQUE
115 : ```
116 :
117 : When you used the GROUP command the flow as follows:
118 :
119 : - If `ATOMS` is present, then take the ordered list of atoms from the `ATOMS` keyword as a starting list.
120 : - Alternatively, if `NDX_FILE` is present, use the list obtained from the gromacs group.
121 : - If `REMOVE` is present, then remove the first occurrence of each of these atoms from the list.
122 : If one tries to remove an atom that was not listed plumed adds a notice in the output.
123 : An atom that is present twice in the original list might be removed twice.
124 : - If `SORT` is present, then the resulting list is sorted by increasing serial number.
125 : - If `UNIQUE` is present, then the resulting list is sorted by increasing serial number _and_ duplicate elements are removed.
126 :
127 : Notice that this command just creates a shortcut, and does not imply any real calculation.
128 : So, having a huge group defined does not slow down your calculation in any way.
129 : It is just convenient to better organize input files.
130 :
131 : */
132 : //+ENDPLUMEDOC
133 :
134 : PLUMED_REGISTER_ACTION(Group,"GROUP")
135 :
136 344 : Group::Group(const ActionOptions&ao):
137 : Action(ao),
138 344 : ActionAtomistic(ao) {
139 688 : parseAtomList("ATOMS",atoms);
140 : std::string ndxfile,ndxgroup;
141 344 : parse("NDX_FILE",ndxfile);
142 688 : parse("NDX_GROUP",ndxgroup);
143 344 : if(ndxfile.length()>0 && atoms.size()>0) {
144 0 : error("either use explicit atom list or import from index file");
145 : }
146 344 : if(ndxfile.length()==0 && ndxgroup.size()>0) {
147 0 : error("NDX_GROUP can be only used is NDX_FILE is also used");
148 : }
149 :
150 344 : if(ndxfile.length()>0) {
151 :
152 : std::vector<AtomNumber> add;
153 : std::vector<std::string> words;
154 46 : words.emplace_back("@ndx: " + ndxfile + " " + ndxgroup);
155 23 : interpretAtomList(words,add);
156 23 : atoms.insert(atoms.end(),add.begin(),add.end());
157 23 : }
158 :
159 : std::vector<AtomNumber> remove;
160 688 : parseAtomList("REMOVE",remove);
161 344 : if(remove.size()>0) {
162 : std::vector<AtomNumber> notfound;
163 : unsigned k=0;
164 2 : log<<" removing these atoms from the list:";
165 114 : for(unsigned i=0; i<remove.size(); i++) {
166 112 : const auto it = find(atoms.begin(),atoms.end(),remove[i]);
167 112 : if(it!=atoms.end()) {
168 111 : if(k%25==0) {
169 6 : log<<"\n";
170 : }
171 111 : log<<" "<<(*it).serial();
172 111 : k++;
173 : atoms.erase(it);
174 : } else {
175 1 : notfound.push_back(remove[i]);
176 : }
177 : }
178 2 : log<<"\n";
179 2 : if(notfound.size()>0) {
180 1 : log<<" the following atoms were not found:";
181 2 : for(unsigned i=0; i<notfound.size(); i++) {
182 1 : log<<" "<<notfound[i].serial();
183 : }
184 1 : log<<"\n";
185 : }
186 : }
187 :
188 344 : bool sortme=false;
189 344 : parseFlag("SORT",sortme);
190 344 : if(sortme) {
191 1 : log<<" atoms are sorted\n";
192 1 : sort(atoms.begin(),atoms.end());
193 : }
194 344 : bool uniqueFlag=false;
195 344 : parseFlag("UNIQUE",uniqueFlag);
196 344 : if(uniqueFlag) {
197 1 : log<<" sorting atoms and removing duplicates\n";
198 1 : Tools::removeDuplicates(atoms);
199 : }
200 :
201 344 : log.printf(" list of atoms:");
202 333462 : for(unsigned i=0; i<atoms.size(); i++) {
203 333118 : if(i%25==0) {
204 13509 : log<<"\n";
205 : }
206 333118 : log<<" "<<atoms[i].serial();
207 : }
208 344 : log.printf("\n");
209 344 : }
210 :
211 516 : void Group::registerKeywords( Keywords& keys ) {
212 516 : Action::registerKeywords( keys );
213 516 : ActionAtomistic::registerKeywords( keys );
214 516 : keys.add("atoms", "ATOMS", "the numerical indexes for the set of atoms in the group");
215 516 : keys.add("atoms", "REMOVE","remove these atoms from the list");
216 516 : keys.addFlag("SORT",false,"sort the resulting list");
217 516 : keys.addFlag("UNIQUE",false,"sort atoms and remove duplicated ones");
218 516 : keys.add("optional", "NDX_FILE", "the name of index file (gromacs syntax)");
219 516 : keys.add("optional", "NDX_GROUP", "the name of the group to be imported (gromacs syntax) - first group found is used by default");
220 516 : }
221 :
222 593 : std::vector<std::string> Group::getGroupAtoms() const {
223 593 : std::vector<std::string> atoms_str(atoms.size());
224 425070 : for(unsigned i=0; i<atoms.size(); ++i) {
225 424477 : std::pair<std::size_t,std::size_t> a = getValueIndices( atoms[i] );
226 424477 : if( xpos[a.first]->getNumberOfValues()==1 ) {
227 10653 : atoms_str[i] = (xpos[a.first]->getPntrToAction())->getLabel();
228 : } else {
229 413824 : Tools::convert( atoms[i].serial(), atoms_str[i] );
230 : }
231 : }
232 593 : return atoms_str;
233 0 : }
234 :
235 : }
236 :
|