LCOV - code coverage report
Current view: top level - core - Group.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 64 67 95.5 %
Date: 2025-12-04 11:19:34 Functions: 3 4 75.0 %

          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             : 

Generated by: LCOV version 1.16