LCOV - code coverage report
Current view: top level - tools - Keywords.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 430 610 70.5 %
Date: 2025-03-25 09:33:27 Functions: 78 88 88.6 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2012-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 "Keywords.h"
      23             : #include "Log.h"
      24             : #include "Tools.h"
      25             : #include <iostream>
      26             : #include <iomanip>
      27             : #include <algorithm>
      28             : 
      29             : template <typename T>
      30       13757 : void erase_remove(std::vector<T>& vec, const T& value) {
      31       13757 :   vec.erase(std::remove(vec.begin(), vec.end(), value), vec.end());
      32       13757 : }
      33             : 
      34           0 : void erase_remove(std::string& vec, const char value) {
      35           0 :   vec.erase(std::remove(vec.begin(), vec.end(), value), vec.end());
      36           0 : }
      37             : 
      38             : //few definition to avoid rewriting the too many times the same docstring
      39             : #define NUMBERED_DOCSTRING(key) ". You can use multiple instances of this keyword i.e. " \
      40             :         + std::string(key) +"1, " + std::string(key) + "2, " + std::string(key) + "3..."
      41             : 
      42             : 
      43             : namespace PLMD {
      44             : 
      45       10295 : std::string toString(Keywords::argType at) {
      46             :   //the simple cases
      47       10295 :   switch (at) {
      48             :   case Keywords::argType::scalar:
      49        3138 :     return  "scalar";
      50             : 
      51             :   case Keywords::argType::vector:
      52         437 :     return  "vector";
      53             : 
      54             :   case Keywords::argType::matrix:
      55         184 :     return  "matrix";
      56             : 
      57             :   case Keywords::argType::grid:
      58         257 :     return  "grid";
      59             :   }
      60             :   //the not simple cases
      61             :   {
      62        6279 :     std::string ret="";
      63        6279 :     std::string next="";
      64        6279 :     if(valid(at & Keywords::argType::scalar)) {
      65             :       ret+="scalar";
      66             :       next="/";
      67             :     }
      68        6279 :     if(valid(at & Keywords::argType::vector)) {
      69       10492 :       ret+=next+"vector";
      70             :       next="/";
      71             :     }
      72        6279 :     if(valid(at & Keywords::argType::matrix)) {
      73        5888 :       ret+=next+"matrix";
      74             :       next="/";
      75             :     }
      76        6279 :     if(valid(at & Keywords::argType::grid)) {
      77        1270 :       ret+=next+"grid";
      78             :     }
      79             :     return ret;
      80             :   }
      81             :   //the return is outsids so the compile should block the compilation
      82             :   //when expanding the enum without updating the toString
      83             :   return "";
      84             : }
      85             : 
      86       98755 : Keywords::argType stoat(std::string_view str) {
      87       98755 :   if(auto pos = str.find("/"); pos!=str.npos) {
      88             :     //here we can express that we do not want certain combinations
      89       35972 :     auto val=stoat(str.substr(0,pos));
      90       35972 :     return val | stoat(str.substr(pos+1));
      91             :   }
      92       62783 :   if (str == "scalar") {
      93             :     return Keywords::argType::scalar;
      94             :   }
      95       38681 :   if (str == "vector") {
      96             :     return Keywords::argType::vector;
      97             :   }
      98       20588 :   if (str == "matrix") {
      99             :     return Keywords::argType::matrix;
     100             :   }
     101        7483 :   if (str == "grid") {
     102             :     return Keywords::argType::grid;
     103             :   }
     104             :   // Handle the case where the string does not match any enum value.
     105           0 :   plumed_massert(false,"invalid argType specifier " + std::string(str));
     106             : }
     107             : 
     108        1318 : std::string toString(Keywords::componentType at) {
     109        1318 :   switch (at) {
     110             :   case Keywords::componentType::scalar:
     111         979 :     return  "scalar";
     112             : 
     113             :   case Keywords::componentType::vector:
     114         101 :     return  "vector";
     115             : 
     116             :   case Keywords::componentType::matrix:
     117          85 :     return  "matrix";
     118             : 
     119             :   case Keywords::componentType::grid:
     120          16 :     return  "grid";
     121             : 
     122             :   case Keywords::componentType::atom:
     123           1 :     return  "atom";
     124             : 
     125             :   case Keywords::componentType::atoms:
     126           1 :     return  "atoms";
     127             :   }
     128             :   //the not simple cases
     129             :   {
     130         135 :     std::string ret="";
     131         135 :     std::string next="";
     132         135 :     if(valid(at & Keywords::componentType::scalar)) {
     133             :       ret+="scalar";
     134             :       next="/";
     135             :     }
     136         135 :     if(valid(at & Keywords::componentType::vector)) {
     137         266 :       ret+=next+"vector";
     138             :       next="/";
     139             :     }
     140         135 :     if(valid(at & Keywords::componentType::matrix)) {
     141          48 :       ret+=next+"matrix";
     142             :       next="/";
     143             :     }
     144         135 :     if(valid(at & Keywords::componentType::grid)) {
     145          16 :       ret+=next+"grid";
     146             :       next="/";
     147             :     }
     148             :     //I do not think these two are necessary
     149         135 :     if(valid(at & Keywords::componentType::atom)) {
     150           0 :       ret+=next+"atom";
     151             :       next="/";
     152             :     }
     153         135 :     if(valid(at & Keywords::componentType::atoms)) {
     154           0 :       ret+=next+"atoms";
     155             :     }
     156             :     return ret;
     157             :   }
     158             :   //the return is outsids so the compile should block the compilation
     159             :   //when expanding the enum without updating the toString
     160             :   return "";
     161             : }
     162             : 
     163      315575 : inline Keywords::componentType stoct(std::string_view str) {
     164      315575 :   if(auto pos = str.find("/"); pos!=str.npos) {
     165             :     //here we can express that we do not want certain combinations
     166       71913 :     auto val=stoct(str.substr(0,pos));
     167       71913 :     return val | stoct(str.substr(pos+1));
     168             :   }
     169      243662 :   if (str == "scalar") {
     170             :     return Keywords::componentType::scalar;
     171             :   }
     172       97893 :   if (str == "grid") {
     173             :     return Keywords::componentType::grid;
     174             :   }
     175       77925 :   if (str == "vector") {
     176             :     return Keywords::componentType::vector;
     177             :   }
     178       39008 :   if (str == "matrix") {
     179             :     return Keywords::componentType::matrix;
     180             :   }
     181        7754 :   if (str == "atom") {
     182             :     return Keywords::componentType::atom;
     183             :   }
     184           2 :   if (str == "atoms") {
     185             :     return Keywords::componentType::atoms;
     186             :   }
     187             : 
     188           0 :   plumed_massert(false,"invalid componentType specifier " + std::string(str));
     189             : }
     190             : 
     191     2159653 : Keywords::KeyType::keyStyle Keywords::KeyType::keyStyleFromString(std::string_view type ) {
     192     2159653 :   if( type=="compulsory" ) {
     193             :     return keyStyle::compulsory;
     194     1557041 :   } else if( type=="flag" ) {
     195             :     return keyStyle::flag;
     196     1106698 :   } else if( type=="optional" ) {
     197             :     return keyStyle::optional;
     198             :     //this is special: some atoms keywords have extra characters usually a "-" followed by a number
     199      447870 :   } else if( type.find("atoms")!=type.npos || type.find("residues")!=type.npos) {
     200             :     return keyStyle::atoms;
     201      225429 :   } else if( type=="hidden" ) {
     202             :     return keyStyle::hidden;
     203             :   } else {
     204           0 :     plumed_massert(false,"invalid keyword specifier " + std::string(type));
     205             :   }
     206             : }
     207             : 
     208     2158682 : Keywords::KeyType::KeyType( std::string_view type )
     209     2158682 :   : style(keyStyleFromString(type)) {}
     210             : 
     211     4321330 : Keywords::KeyType::KeyType( Keywords::KeyType::keyStyle type )
     212     4321330 :   : style(type) {}
     213             : 
     214         971 : void Keywords::KeyType::setStyle( std::string_view type ) {
     215         971 :   style=keyStyleFromString(type);
     216         971 : }
     217             : 
     218     4320008 : Keywords::keyInfo::keyInfo()
     219     4320008 :   : type(Keywords::KeyType::keyStyle::unknown),
     220     4320008 :     docstring(""),
     221             :     defaultValue(std::monostate()),
     222     4320008 :     allowmultiple(false)
     223     4320008 : {}
     224             : 
     225     2160004 : Keywords::keyInfo& Keywords::keyInfo::setType(Keywords::KeyType t) {
     226     2160004 :   type=t;
     227     2160004 :   return *this;
     228             : }
     229     2160004 : Keywords::keyInfo& Keywords::keyInfo::setDocString(std::string_view d) {
     230     2160004 :   docstring=d;
     231     2160004 :   return *this;
     232             : }
     233      445652 : Keywords::keyInfo& Keywords::keyInfo::setDefaultValue(std::string_view d) {
     234      445652 :   defaultValue=std::string(d);
     235      445652 :   return *this;
     236             : }
     237      451665 : Keywords::keyInfo& Keywords::keyInfo::setDefaultFlag(bool a) {
     238      451665 :   defaultValue=a;
     239      451665 :   return *this;
     240             : }
     241       26843 : Keywords::keyInfo& Keywords::keyInfo::setArgumentType(argType a) {
     242       26843 :   argument_type=a;
     243       26843 :   return *this;
     244             : }
     245     2160004 : Keywords::keyInfo& Keywords::keyInfo::setAllowMultiple(bool a) {
     246     2160004 :   allowmultiple=a;
     247     2160004 :   return *this;
     248             : }
     249     2163871 : Keywords::keyInfo& Keywords::keyInfo::setLinkedAction(std::string_view a) {
     250     2163871 :   linkaction=a;
     251     2163871 :   return *this;
     252             : }
     253      825547 : bool Keywords::keyInfo::isArgument() const {
     254      825547 :   return std::holds_alternative<argType>(argument_type);
     255             : }
     256             : 
     257      361834 : Keywords::component::component():
     258             : //the 0 ensures something that always fails unles explicitly set
     259      361834 :   type(static_cast<componentType>(0)) {};
     260      180917 : Keywords::component& Keywords::component::setKey(std::string_view k) {
     261      180917 :   key=k;
     262      180917 :   return *this;
     263             : }
     264      180917 : Keywords::component& Keywords::component::setDocstring(std::string_view d) {
     265      180917 :   docstring=d;
     266      180917 :   return *this;
     267             : }
     268      180917 : Keywords::component& Keywords::component::setType(componentType t) {
     269      180917 :   type=t;
     270      180917 :   return *this;
     271             : }
     272             : 
     273     1886971 : std::string Keywords::getStyle( const std::string&  k ) const {
     274     1886971 :   plumed_massert( exists(k)||reserved(k), "Did not find keyword " + k );
     275     1886971 :   return (keywords.at(k).type).toString();
     276             : }
     277             : 
     278           0 : void Keywords::add( const Keywords& newkeys ) {
     279             :   //copies data from
     280             :   //loop on the declared keys
     281           0 :   for(const auto& thiskey:newkeys.keys) {
     282           0 :     plumed_massert( !exists(thiskey), "keyword " + thiskey + " is in twice" );
     283           0 :     plumed_massert( !reserved(thiskey), "keyword " + thiskey + " is in twice" );
     284           0 :     keywords[thiskey] = newkeys.keywords.at(thiskey);
     285           0 :     keys.emplace_back( thiskey );
     286             :   }
     287             :   //loop on the reserved keys
     288           0 :   for (const auto&thiskey : newkeys.reserved_keys) {
     289           0 :     plumed_massert( !exists(thiskey), "keyword " + thiskey + " is in twice" );
     290           0 :     plumed_massert( !reserved(thiskey), "keyword " + thiskey + " is in twice" );
     291             : 
     292           0 :     keywords[thiskey] = newkeys.keywords.at(thiskey);
     293           0 :     reserved_keys.emplace_back( thiskey );
     294             :   }
     295           0 :   for (const auto& thisnam : newkeys.cnames) {
     296           0 :     plumed_massert( components.find(thisnam)!=components.end(), "keyword for component" + thisnam + " is in twice" );
     297           0 :     cnames.push_back( thisnam );
     298           0 :     components[thisnam]=newkeys.components.at(thisnam);
     299             :   }
     300           0 : }
     301             : 
     302     1262687 : void Keywords::addOrReserve( std::string_view keytype,
     303             :                              std::string_view key,
     304             :                              std::string_view docstring,
     305             :                              const bool reserve ) {
     306     1262687 :   plumed_massert(!exists(key),  "keyword " + std::string(key) + " has already been registered");
     307     1262687 :   plumed_massert(!reserved(key),"keyword " + std::string(key) + " has already been reserved");
     308     1262687 :   std::string t_type{keytype};
     309     1262687 :   bool isNumbered = keytype=="numbered";
     310     1262687 :   if( isNumbered ) {
     311             :     t_type="optional";
     312             :   }
     313             :   //let's fail asap in case of typo
     314     1262687 :   auto type = KeyType(t_type);
     315     1262687 :   if (!reserve) {
     316     1020814 :     plumed_massert( !type.isFlag(),   "use addFlag() to register a flag keyword (" + std::string(key) + ")");
     317             :   }
     318             : 
     319     1262687 :   std::string fd{docstring};
     320             :   bool allowMultiple= false;
     321     1262687 :   if( isNumbered ) {
     322       24798 :     fd += NUMBERED_DOCSTRING(key);
     323             :     allowMultiple = true;
     324             :   }
     325             : 
     326     3788061 :   keywords[std::string(key)] = keyInfo()
     327     1262687 :                                .setType(type)
     328     1262687 :                                .setDocString(fd)
     329     1262687 :                                .setAllowMultiple(allowMultiple)
     330     3788061 :                                .setLinkedAction("none");
     331     1262687 :   if( type.isAtomList() ) {
     332             :     //keytype may be "residues" or something like "atoms-3"
     333      221934 :     keywords.find(key)->second.atomtag=keytype;
     334      221934 :     if (isaction && keytype == "atoms") { //this narrow the doctrstring ONLY to atoms
     335       48862 :       keywords.find(key)->second.docstring+= ".  For more information on how to specify lists of atoms see \\ref Group";
     336             :     }
     337             :   }
     338     1262687 :   if (reserve) {
     339      241873 :     reserved_keys.emplace_back(key);
     340             :   } else {
     341     1020814 :     keys.emplace_back(key);
     342             :   }
     343     1262687 : }
     344             : 
     345      241873 : void Keywords::reserve( std::string_view keytype,
     346             :                         std::string_view key,
     347             :                         std::string_view docstring ) {
     348             :   //If you modify this function, please update also the add with three arguments
     349      241873 :   addOrReserve(keytype,key,docstring,true);
     350      241873 : }
     351             : 
     352        1322 : void Keywords::reserveFlag(const std::string & key, const bool defaultValue, const std::string & docstring ) {
     353        1322 :   plumed_assert( !exists(key) && !reserved(key) );
     354             :   std::string defstr;
     355        1322 :   if( defaultValue ) {
     356             :     defstr="( default=on ) ";
     357             :   } else {
     358             :     defstr="( default=off ) ";
     359             :   }
     360             : 
     361        2644 :   keywords[key] = keyInfo()
     362        1322 :                   .setType(KeyType{KeyType::keyStyle::flag})
     363        2644 :                   .setDocString(defstr + docstring)
     364        1322 :                   .setAllowMultiple(false)
     365        1322 :                   .setDefaultFlag(defaultValue)
     366        2644 :                   .setLinkedAction("none");
     367        1322 :   reserved_keys.emplace_back(key);
     368        1322 : }
     369             : 
     370             : ///this "copies" a reserved key into the keylist so it can be used
     371       25045 : void Keywords::use(std::string_view  k ) {
     372       25045 :   plumed_massert( reserved(k), "the " + std::string(k) + " keyword is not reserved");
     373       25045 :   keys.emplace_back(k);
     374       25045 : }
     375             : 
     376        7502 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
     377        7502 :   plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
     378             :   //Adding this two feels correct, but breaks some actions where a numbered keyword is changed to compulsory
     379             :   //So also the atomtag is removed
     380             :   //keywords.at(k).atomtag="";
     381             :   //keywords.at(k).allowmultiple=false;
     382        7502 :   if( style=="numbered" ) {
     383        6531 :     keywords.at(k).allowmultiple=true;
     384        6531 :     return;
     385             :   }
     386         971 :   keywords.at(k).type.setStyle(style);
     387         971 :   if( (keywords.at(k).type).isAtomList() ) {
     388         507 :     keywords.at(k).atomtag=style;
     389             :   }
     390             : }
     391             : 
     392     1020814 : void Keywords::add(std::string_view keytype,
     393             :                    std::string_view key,
     394             :                    std::string_view docstring ) {
     395             :   //the 'false' deactivates the "reserve mode"
     396     1020814 :   addOrReserve(keytype,key,docstring,false);
     397     1020814 : }
     398             : 
     399       26803 : void Keywords::addInputKeyword( const std::string & keyType,
     400             :                                 const std::string & key,
     401             :                                 const std::string & datatype,
     402             :                                 const std::string & docstring ) {
     403       26803 :   addInputKeyword(keyType,key,stoat(datatype),docstring);
     404       26803 : }
     405             : 
     406       26835 : void Keywords::addInputKeyword( const std::string & keyType,
     407             :                                 const std::string & key,
     408             :                                 argType datatype,
     409             :                                 const std::string & docstring ) {
     410       26835 :   if( exists(key) ) {
     411         571 :     remove(key);
     412             :   }
     413             :   //insert({k,datatype}) Inserts element(s) into the container, if the container doesn't already contain an element with an equivalent key.[cit.]
     414             :   //operator[] inserts if the key doesn't exist, or overwrites if it does
     415       26835 :   add( keyType, key, docstring );
     416       26835 :   keywords.at(key).setArgumentType(datatype);
     417       26835 : }
     418             : 
     419           8 : void Keywords::addInputKeyword( const std::string & keyType,
     420             :                                 const std::string & key,
     421             :                                 const std::string & datatype,
     422             :                                 const std::string & defaultV,
     423             :                                 const std::string & docstring ) {
     424           8 :   addInputKeyword(keyType,key,stoat(datatype),defaultV,docstring);
     425           8 : }
     426             : 
     427           8 : void Keywords::addInputKeyword( const std::string & keyType,
     428             :                                 const std::string & key,
     429             :                                 argType datatype,
     430             :                                 const std::string & defaultV,
     431             :                                 const std::string & docstring ) {
     432           8 :   if( exists(key) ) {
     433           0 :     remove(key);
     434             :   }
     435           8 :   add( keyType, key, defaultV, docstring );
     436           8 :   keywords[key].setArgumentType(datatype);
     437           8 : }
     438             : 
     439      445652 : void Keywords::add( std::string_view keytype,
     440             :                     std::string_view key,
     441             :                     std::string_view defaultValue,
     442             :                     std::string_view docstring ) {
     443             :   //let's fail asap in case of typo
     444      445652 :   auto type = KeyType(keytype);
     445             : 
     446      445652 :   plumed_massert( !exists(key) && !reserved(key), "failing on keyword " + std::string(key) );
     447             :   // An optional keyword can't have a default
     448      445652 :   plumed_massert(type.isCompulsory() || type.isHidden(), "You can't set a default value for an optional keyword, failing on " + std::string(key));
     449      891304 :   keywords[std::string(key)] = keyInfo()
     450      445652 :                                .setType(type)
     451      445652 :                                .setDefaultValue(defaultValue)
     452      891304 :                                .setDocString("( default=" + std::string(defaultValue) + " ) " + std::string(docstring) )
     453      445652 :                                .setAllowMultiple(false)
     454     1336956 :                                .setLinkedAction("none");
     455             : 
     456      445652 :   keys.emplace_back(key);
     457      445652 : }
     458             : 
     459      450343 : void Keywords::addFlag(std::string_view key, bool defaultValue, std::string_view docstring) {
     460      450343 :   plumed_massert( !exists(key) && !reserved(key), "keyword " + std::string(key) + " has already been registered");
     461      450343 :   plumed_massert( !defaultValue, "the second argument to addFlag must be false " + std::string(key) );
     462      450343 :   std::string defstr="( default=off ) ";
     463      900686 :   keywords[std::string(key)] = keyInfo()
     464      450343 :                                .setType(KeyType("flag"))
     465      450343 :                                .setDefaultFlag(false)
     466      900686 :                                .setDocString(std::string(defstr) + std::string(docstring))
     467      450343 :                                .setAllowMultiple(false)
     468     1351029 :                                .setLinkedAction("none");
     469             : 
     470      450343 :   keys.emplace_back(key);
     471      450343 : }
     472             : 
     473       13649 : void Keywords::remove( const std::string & k ) {
     474             :   bool found=false;
     475       13649 :   if(exists(k)) {
     476       13649 :     erase_remove(keys,k);
     477             :     found=true;
     478           0 :   } else if(reserved(k)) {
     479           0 :     erase_remove(reserved_keys,k);
     480             :     found=true;
     481             :   }
     482           0 :   plumed_massert(found,"You are trying to forbid " + k + " a keyword that isn't there");
     483             :   // Delete documentation, type and so on from the description
     484             :   keywords.erase(k);
     485             : 
     486             :   // Remove any output components that this keyword creates
     487             :   //we need the double loop because we should not remove and iterate on the map at the same time
     488             :   std::vector<std::string> markForRemoval{};
     489       29304 :   for(const auto& dkey : components ) {
     490       15655 :     if( dkey.second.key==k ) {
     491         108 :       markForRemoval.push_back(dkey.first);
     492             :     }
     493             :   }
     494       13757 :   for(const auto& toremove : markForRemoval ) {
     495         108 :     removeOutputComponent( toremove );
     496             :   }
     497       13649 : }
     498             : 
     499      317979 : bool Keywords::numbered( const std::string & k ) const {
     500      635958 :   if( style( k,"atoms") ) {
     501             :     return true;
     502             :   }
     503             :   //should I add also the "reserved(k)" to the test?
     504      273425 :   plumed_massert( exists(k), "Did not find keyword " + k );
     505      273425 :   return keywords.at(k).allowmultiple;
     506             : }
     507             : 
     508     1881666 : bool Keywords::style( const std::string & k, const std::string & t ) const {
     509     1881666 :   if( getStyle(k)==t ) {
     510      419075 :     return true;
     511             :   }
     512             :   return false;
     513             : }
     514             : 
     515     1148901 : unsigned Keywords::size() const {
     516     1148901 :   return keys.size();
     517             : }
     518             : 
     519      526518 : std::string Keywords::getKeyword( const unsigned i ) const {
     520      526518 :   plumed_assert( i<size() );
     521      526518 :   return keys[i];
     522             : }
     523             : 
     524     5536012 : bool Keywords::exists( std::string_view k ) const {
     525     5536012 :   return std::find(keys.begin(), keys.end(), k) != keys.end();
     526             : }
     527             : 
     528     2185049 : bool Keywords::reserved( std::string_view k ) const {
     529     2185049 :   return std::find(reserved_keys.begin(), reserved_keys.end(), k) != reserved_keys.end();
     530             : }
     531             : 
     532           0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
     533             :   std::printf("%s",actionname.c_str());
     534             :   {
     535           0 :     std::string prevtag="start";
     536           0 :     for(const auto& key : keys) {
     537           0 :       if( keywords.at(key).type.isAtomList() ) {
     538           0 :         plumed_massert( keywords.at(key).atomtag!="", "keyword " + key + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     539           0 :         const auto & currentTag=keywords.at(key).atomtag;
     540           0 :         if( prevtag!="start" && prevtag!=currentTag ) {
     541             :           break;
     542             :         }
     543           0 :         if( currentTag.find("residues")!=std::string::npos) {
     544             :           std::printf(" %s=<residue selection>", key.c_str() );
     545             :         } else {
     546             :           std::printf(" %s=<atom selection>", key.c_str() );
     547             :         }
     548             :         prevtag=currentTag;
     549             :       }
     550             :     }
     551             :   }
     552             : 
     553           0 :   for(const auto& key : keys) {
     554           0 :     if ( keywords.at(key).type.isCompulsory() ) {
     555             :       std::string def;
     556           0 :       if( getDefaultValue( key, def) ) {
     557             :         std::printf(" %s=%s ", key.c_str(), def.c_str() );
     558             :       } else {
     559             :         std::printf(" %s=    ", key.c_str() );
     560             :       }
     561           0 :     } else if (include_optional) {
     562             :       // TG no defaults for optional keywords?
     563             :       std::printf(" [%s]", key.c_str() );
     564             : 
     565             :     }
     566             :   }
     567             :   std::printf("\n");
     568             :   std::flush(std::cout);
     569           0 : }
     570             : 
     571         441 : void Keywords::print_vim() const {
     572        5512 :   for(const auto& key : keys) {
     573        5071 :     if( keywords.at(key).type.isFlag() ) {
     574             :       std::printf( ",flag:%s", key.c_str() );
     575             :     } else {
     576        4066 :       if( keywords.at(key).allowmultiple ) {
     577             :         std::printf(",numbered:%s",key.c_str() );
     578             :       } else {
     579             :         std::printf(",option:%s",key.c_str() );
     580             :       }
     581             :     }
     582             :   }
     583         441 :   std::fprintf(stdout, "\n%s", getHelpString().c_str() );
     584         441 : }
     585             : 
     586           0 : void Keywords::print_html() const {
     587             : // This is the part that outputs the details of the components
     588           0 :   if( cnames.size()>0 ) {
     589             :     unsigned ndef=0;
     590             :     //running on the order of insertion
     591           0 :     for(const auto& cname : cnames) {
     592           0 :       if(components.at(cname).key=="default") {
     593           0 :         ndef++;
     594             :       }
     595             :     }
     596             : 
     597           0 :     if( ndef>0 ) {
     598           0 :       std::cout<<"\\par Description of components\n\n";
     599           0 :       std::cout<<cstring<<"\n\n";
     600           0 :       std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     601             :       std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
     602             :       unsigned nndef=0;
     603           0 :       for(const auto& cname : cnames) {
     604             :         //plumed_assert( components.at(cname).key=="default" );
     605           0 :         if( components.at(cname).key!="default" ) {
     606           0 :           nndef++;
     607           0 :           continue;
     608             :         }
     609             :         std::printf("<tr>\n");
     610             :         std::printf("<td width=15%%> <b> %s </b></td>\n",cname.c_str() );
     611           0 :         std::printf("<td> %s </td>\n",(components.at(cname).docstring).c_str() );
     612             :         std::printf("</tr>\n");
     613             :       }
     614           0 :       std::cout<<"</table>\n\n";
     615           0 :       if( nndef>0 ) {
     616           0 :         std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
     617           0 :         std::cout<<"\n\n";
     618           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     619             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     620           0 :         for(const auto& cname : cnames) {
     621           0 :           if( components.at(cname).key!="default") {
     622             :             std::printf("<tr>\n");
     623             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     624           0 :                         cname.c_str(),(components.at(cname).key).c_str() );
     625           0 :             std::printf("<td> %s </td>\n",(components.at(cname).docstring).c_str() );
     626             :             std::printf("</tr>\n");
     627             :           }
     628             :         }
     629           0 :         std::cout<<"</table>\n\n";
     630             :       }
     631             :     } else {
     632             :       unsigned nregs=0;
     633           0 :       for(const auto& cname : cnames) {
     634           0 :         if( exists(components.at(cname).key) ) {
     635           0 :           nregs++;
     636             :         }
     637             :       }
     638           0 :       if( nregs>0 ) {
     639           0 :         std::cout<<"\\par Description of components\n\n";
     640           0 :         std::cout<<cstring<<"\n\n";
     641           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     642             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     643           0 :         for(const auto& cname : cnames) {
     644           0 :           if( exists(components.at(cname).key) ) {
     645             :             std::printf("<tr>\n");
     646             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     647           0 :                         cname.c_str(),(components.at(cname).key).c_str() );
     648           0 :             std::printf("<td> %s </td>\n",(components.at(cname).docstring).c_str() );
     649             :             std::printf("</tr>\n");
     650             :           }
     651             :         }
     652           0 :         std::cout<<"</table>\n\n";
     653             :       }
     654             :     }
     655             :   }
     656             : 
     657             :   unsigned nkeys=0;
     658           0 :   for(const auto& key : keys) {
     659           0 :     if ( keywords.at(key).type.isAtomList() ) {
     660           0 :       nkeys++;
     661             :     }
     662             :   }
     663           0 :   if( nkeys>0 ) {
     664           0 :     if(isaction && isatoms) {
     665           0 :       std::cout<<"\\par The atoms involved can be specified using\n\n";
     666           0 :     } else if(isaction) {
     667           0 :       std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
     668             :     } else {
     669           0 :       std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     670             :     }
     671           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     672           0 :     std::string prevtag="start";
     673             :     unsigned counter=0;
     674           0 :     for(const auto& key : keys) {
     675           0 :       if ( keywords.at(key).type.isAtomList() ) {
     676           0 :         const auto& currentTag = keywords.at(key).atomtag;
     677           0 :         plumed_massert( currentTag!="", "keyword " + key + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     678           0 :         if( prevtag!="start" && prevtag!=currentTag && isaction ) {
     679           0 :           std::cout<<"</table>\n\n";
     680           0 :           if( isatoms ) {
     681           0 :             std::cout<<"\\par Or alternatively by using\n\n";
     682           0 :           } else if( counter==0 ) {
     683           0 :             std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n";
     684           0 :             counter++;
     685             :           } else {
     686           0 :             std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
     687             :           }
     688           0 :           std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     689             :         }
     690           0 :         print_html_item( key );
     691             :         prevtag=currentTag;
     692             :       }
     693             :     }
     694           0 :     std::cout<<"</table>\n\n";
     695             :   }
     696             :   nkeys=0;
     697           0 :   for(const auto& key : keys) {
     698           0 :     if ( keywords.at(key).type.isCompulsory() ) {
     699           0 :       nkeys++;
     700             :     }
     701             :   }
     702           0 :   if( nkeys>0 ) {
     703           0 :     if(isaction) {
     704           0 :       std::cout<< "\\par Compulsory keywords\n\n";
     705             :     } else {
     706           0 :       std::cout<<"\\par The following must be present\n\n";
     707             :     }
     708           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     709           0 :     for(const auto& key : keys) {
     710           0 :       if ( keywords.at(key).type.isCompulsory() ) {
     711           0 :         print_html_item( key );
     712             :       }
     713             :     }
     714           0 :     std::cout<<"</table>\n\n";
     715             :   }
     716             :   nkeys=0;
     717           0 :   for(const auto& key : keys) {
     718           0 :     if ( keywords.at(key).type.isFlag() || keywords.at(key).type.isOptional() ) {
     719           0 :       nkeys++;
     720             :     }
     721             :   }
     722           0 :   if( nkeys>0 ) {
     723           0 :     if(isaction) {
     724           0 :       std::cout<<"\\par Options\n\n";
     725             :     } else {
     726           0 :       std::cout<<"\\par The following options are available\n\n";
     727             :     }
     728           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     729           0 :     for(const auto& key : keys) {
     730           0 :       if ( keywords.at(key).type.isFlag() ) {
     731           0 :         print_html_item( key );
     732             :       }
     733             :     }
     734           0 :     std::cout<<"\n";
     735             :   }
     736             :   nkeys=0;
     737           0 :   for(const auto& key : keys) {
     738           0 :     if ( keywords.at(key).type.isOptional() ) {
     739           0 :       nkeys++;
     740             :     }
     741             :   }
     742           0 :   if( nkeys>0 ) {
     743           0 :     for(const auto& key : keys) {
     744           0 :       if ( keywords.at(key).type.isOptional() ) {
     745           0 :         print_html_item( key );
     746             :       }
     747             :     }
     748             :   }
     749           0 :   std::cout<<"</table>\n\n";
     750           0 : }
     751             : 
     752           0 : void Keywords::print_spelling() const {
     753           0 :   for(const auto& key : keys) {
     754             :     std::printf("%s\n", key.c_str() );
     755             :   }
     756           0 :   for(const auto& cname : cnames) {
     757             :     std::printf("%s\n",cname.c_str() );
     758             :   }
     759           0 : }
     760             : 
     761        7992 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
     762        7992 :   bool killdot=( keywords.at(key).docstring.find("\\f$")!=std::string::npos ); // Check for latex
     763        7992 :   std::vector<std::string> w=Tools::getWords( keywords.at(key).docstring );
     764        7992 :   std::stringstream sstr;
     765        7992 :   sstr<<std::setw(23)<<key<<" - ";
     766             :   unsigned nl=0;
     767        7992 :   std::string blank=" ";
     768      130402 :   for(unsigned i=0; i<w.size(); ++i) {
     769      122896 :     nl+=w[i].length() + 1;
     770      122896 :     if( nl>60 ) {
     771       23622 :       sstr<<"\n"<<std::setw(23)<<blank<<"   "<<w[i]<<" ";
     772             :       nl=0;
     773             :     } else {
     774      115022 :       sstr<<w[i]<<" ";
     775             :     }
     776      122896 :     if( killdot && w[i].find(".")!=std::string::npos ) {
     777             :       break;  // If there is latex only write up to first dot
     778             :     }
     779             :   }
     780        7992 :   sstr<<"\n";
     781        7992 :   return sstr.str();
     782        7992 : }
     783             : 
     784         882 : std::string Keywords::getHelpString() const {
     785             :   std::string helpstr;
     786             :   unsigned nkeys=0;
     787       11024 :   for(const auto& key : keys) {
     788       10142 :     if ( keywords.at(key).type.isAtomList() ) {
     789         680 :       nkeys++;
     790             :     }
     791             :   }
     792         882 :   if( nkeys>0 ) {
     793             :     helpstr += "The input trajectory can be in any of the following formats: \n\n";
     794        5218 :     for(const auto& key : keys) {
     795        4902 :       if ( keywords.at(key).type.isAtomList() ) {
     796        1360 :         helpstr += getKeywordDocs( key );
     797             :       }
     798             :     }
     799             :   }
     800             :   unsigned ncompulsory=0;
     801       11024 :   for(const auto& key : keys) {
     802       10142 :     if ( keywords.at(key).type.isCompulsory() ) {
     803        2558 :       ncompulsory++;
     804             :     }
     805             :   }
     806         882 :   if( ncompulsory>0 ) {
     807             :     helpstr += "\nThe following arguments are compulsory: \n\n";
     808        9350 :     for(const auto& key : keys) {
     809        8624 :       if ( keywords.at(key).type.isCompulsory() ) {
     810        5116 :         helpstr += getKeywordDocs( key );
     811             :       }
     812             :     }
     813             :   }
     814             :   nkeys=0;
     815       11024 :   for(const auto& key : keys) {
     816       10142 :     if ( keywords.at(key).type.isFlag() ) {
     817        2010 :       nkeys++;
     818             :     }
     819             :   }
     820         882 :   if( nkeys>0 ) {
     821         708 :     if(ncompulsory>0) {
     822             :       helpstr += "\nIn addition you may use the following options: \n\n";
     823             :     } else {
     824             :       helpstr += "\nThe following options are available\n\n";
     825             :     }
     826        9708 :     for(const auto& key : keys) {
     827        9000 :       if ( keywords.at(key).type.isFlag() ) {
     828        4020 :         helpstr += getKeywordDocs( key ).c_str();
     829             :       }
     830             :     }
     831             :   }
     832             :   nkeys=0;
     833       11024 :   for(const auto& key : keys) {
     834       10142 :     if ( keywords.at(key).type.isOptional() ) {
     835        2744 :       nkeys++;
     836             :     }
     837             :   }
     838         882 :   if( nkeys>0 ) {
     839        8482 :     for(const auto& key : keys) {
     840        7944 :       if ( keywords.at(key).type.isOptional() ) {
     841        5488 :         helpstr += getKeywordDocs( key );
     842             :       }
     843             :     }
     844             :     helpstr += "\n";
     845             :   }
     846         882 :   return helpstr;
     847             : }
     848             : 
     849           0 : void Keywords::print( Log& log ) const {
     850           0 :   log.printf("%s", getHelpString().c_str() );
     851           0 : }
     852             : 
     853           0 : void Keywords::print( FILE* out ) const {
     854           0 :   fprintf( out,"%s", getHelpString().c_str() );
     855           0 : }
     856             : 
     857           0 : std::string Keywords::getTooltip( const std::string& name ) const {
     858           0 :   std::size_t dd=name.find_first_of("0123456789");
     859           0 :   std::string kname=name.substr(0,dd);
     860           0 :   if( !exists(kname) ) {
     861           0 :     return "<b> could not find this keyword </b>";
     862             :   }
     863             :   std::string mystring;
     864           0 :   std::string docstr = keywords.at(kname).docstring;
     865           0 :   if( keywords.at(kname).type.isCompulsory() ) {
     866             :     mystring += "<b>compulsory keyword ";
     867           0 :     if( docstr.find("default")!=std::string::npos ) {
     868           0 :       std::size_t bra = docstr.find_first_of(")");
     869           0 :       mystring += docstr.substr(0,bra+1);
     870           0 :       docstr = docstr.substr(bra+1);
     871             :     }
     872             :     mystring += "</b>\n";
     873             :   }
     874           0 :   std::vector<std::string> w=Tools::getWords( docstr );
     875             :   unsigned nl=0;
     876           0 :   for(unsigned i=0; i<w.size(); ++i) {
     877           0 :     nl+=w[i].length() + 1;
     878           0 :     if( nl>80 ) {
     879           0 :       mystring += w[i] + "\n";
     880             :       nl=0;
     881             :     } else {
     882           0 :       mystring += w[i] + " ";
     883             :     }
     884           0 :     if( w[i].find(".")!=std::string::npos ) {
     885             :       break;  // Only write up the the first dot
     886             :     }
     887             :   }
     888             :   return mystring;
     889           0 : }
     890             : 
     891           0 : void Keywords::print_html_item( const std::string& key ) const {
     892             :   std::printf("<tr>\n");
     893             :   std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
     894           0 :   std::printf("<td> %s </td>\n",(keywords.at(key).docstring).c_str() );
     895             :   std::printf("</tr>\n");
     896           0 : }
     897             : 
     898       83544 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
     899             :   // plumed_massert(exists(key)||reserved(key),"You can't ask for the default value of a keyword that doesn't exist("+key+")");
     900       83544 :   if (std::holds_alternative<bool>(keywords.at(key).defaultValue)) {
     901       83544 :     def = std::get<bool>(keywords.at(key).defaultValue);
     902       83544 :     return true;
     903             :   } else {
     904             :     return false;
     905             :   }
     906             : }
     907             : 
     908       26085 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
     909       37717 :   plumed_massert( style(key,"compulsory") || style(key,"hidden"),"You can't ask for the default value of a keyword that doesn't have one ("+key+")" );
     910       26085 :   if (std::holds_alternative<std::string>(keywords.at(key).defaultValue)) {
     911       20270 :     def = std::get<std::string>(keywords.at(key).defaultValue);
     912       20270 :     return true;
     913             :   } else {
     914             :     return false;
     915             :   }
     916             : }
     917             : 
     918           0 : void Keywords::destroyData() {
     919           0 :   keys.clear();
     920           0 :   reserved_keys.clear();
     921             :   keywords.clear();
     922             :   components.clear();
     923             :   //cname was missing before, is it wanted or not?
     924           0 :   cnames.clear();
     925           0 : }
     926             : 
     927       33554 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
     928       33554 :   cstring = instr;
     929       33554 : }
     930             : 
     931          76 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
     932          76 :   addOutputComponent( name, key, "scalar", descr );
     933          76 : }
     934             : 
     935      117821 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& type, const std::string& descr ) {
     936      117821 :   addOutputComponent(name,key,stoct(type),descr);
     937      117821 : }
     938             : 
     939      132101 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, componentType type, const std::string& descr ) {
     940      132101 :   plumed_assert( !outputComponentExists(name) );
     941      132101 :   plumed_massert( name!=".#!value", name + " is reserved for storing description of value" );
     942      132101 :   plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
     943             : 
     944      132101 :   std::size_t num2=name.find_first_of("_");
     945      132101 :   if( num2!=std::string::npos ) {
     946         659 :     char uu = '_';
     947         659 :     plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
     948         659 :     plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
     949             :   }
     950      132101 :   if( key=="default" ) {
     951             :     cstring = "By default this Action calculates the following quantities. These quantities can "
     952             :               "be referenced elsewhere in the input by using this Action's label followed by a "
     953       97632 :               "dot and the name of the quantity required from the list below.";
     954             :   }
     955      264202 :   components[name] = component()
     956      132101 :                      .setKey(key)
     957      132101 :                      .setDocstring(descr)
     958      264202 :                      .setType(type);
     959      132101 :   cnames.emplace_back(name);
     960      132101 : }
     961             : 
     962       53928 : void Keywords::setValueDescription( const std::string& type, const std::string& descr ) {
     963       53928 :   setValueDescription(stoct (type),descr);
     964       53928 : }
     965             : 
     966       56308 : void Keywords::setValueDescription( componentType type, const std::string& descr ) {
     967      112616 :   if( !outputComponentExists(".#!value") ) {
     968       97632 :     components[".#!value"] =component()
     969       97632 :                             .setKey("default")
     970       48816 :                             .setDocstring(descr)
     971       97632 :                             .setType(type);
     972       48816 :     cnames.emplace_back(".#!value");
     973             :   } else {
     974        7492 :     components[".#!value"].docstring = descr;
     975        7492 :     components[".#!value"].type = type;
     976             :   }
     977       56308 : }
     978             : 
     979      299693 : bool Keywords::outputComponentExists( const std::string& name ) const {
     980      299693 :   if( cstring.find("customize")!=std::string::npos ) {
     981             :     return true;
     982             :   }
     983             : 
     984             :   std::string sname;
     985      295226 :   std::size_t num=name.find_first_of("-");
     986      295226 :   std::size_t num2=name.find_last_of("_");
     987             : 
     988      295226 :   if( num2!=std::string::npos ) {
     989        5064 :     sname=name.substr(num2);
     990      292694 :   } else if( num!=std::string::npos ) {
     991       54492 :     sname=name.substr(0,num);
     992             :   } else {
     993             :     sname=name;
     994             :   }
     995             : 
     996             :   return components.find(sname)!=components.end();
     997             : }
     998             : 
     999      106759 : bool Keywords::componentHasCorrectType( const std::string& name, const std::size_t& rank, const bool& hasderiv ) const {
    1000      106759 :   if( cstring.find("customize")!=std::string::npos ) {
    1001             :     return true;
    1002             :   }
    1003             : 
    1004             :   std::string sname;
    1005      102304 :   std::size_t num=name.find_first_of("-");
    1006      102304 :   std::size_t num2=name.find_last_of("_");
    1007      102304 :   if( num2!=std::string::npos ) {
    1008        3746 :     sname=name.substr(num2);
    1009      100431 :   } else if( num!=std::string::npos ) {
    1010       54492 :     sname=name.substr(0,num);
    1011             :   } else {
    1012             :     sname=name;
    1013             :   }
    1014             : 
    1015             :   // using valid(components.at(sname).type & (componentType::atom | componentType::atoms) will have a sligthly different flavour
    1016             :   // == means "is exactly", the valid(&) construct instead measn "can be different, but must contain the asked flag"
    1017      102304 :   if( thisactname=="CENTER" && (components.at(sname).type == componentType::atom || components.at(sname).type == componentType::atoms)) {
    1018           0 :     return true;
    1019             :   }
    1020             : 
    1021      102304 :   if( rank==0 ) {
    1022       88109 :     return (valid(components.at(sname).type | componentType::scalar));
    1023       14195 :   } else if( hasderiv ) {
    1024         834 :     return (valid(components.at(sname).type | componentType::grid));
    1025       13361 :   } else if( rank==1 ) {
    1026        9771 :     return (valid(components.at(sname).type | componentType::vector));
    1027        3590 :   } else if( rank==2 ) {
    1028        3590 :     return (valid(components.at(sname).type | componentType::matrix ));
    1029             :   }
    1030             :   return false;
    1031             : }
    1032             : 
    1033       68832 : std::vector<std::string> Keywords::getArgumentKeys() const {
    1034             :   std::vector<std::string> arguments;
    1035       68832 :   std::copy_if(keys.begin(), keys.end(),std::back_inserter(arguments),
    1036      825547 :   [this](auto const& kw) {
    1037      825547 :     return keywords.at(kw).isArgument();
    1038             :   });
    1039       68832 :   return arguments;
    1040           0 : }
    1041             : 
    1042       53430 : bool Keywords::checkArgumentType( const std::size_t& rank, const bool& hasderiv ) const {
    1043             :   bool allArgumentsAreCorrect = true;
    1044      125263 :   for(auto const& kw : getArgumentKeys() ) {
    1045       71833 :     const auto & at = std::get<argType>(keywords.at(kw).argument_type);
    1046             :     bool kwIsCorrect = false;
    1047       71833 :     if( rank==0  && valid(at | argType::scalar)) {
    1048             :       kwIsCorrect = true;
    1049             :     }
    1050       71833 :     if( hasderiv && valid(at | argType::grid)) {
    1051             :       kwIsCorrect = true;
    1052             :     }
    1053       71833 :     if( rank==1  && valid(at | argType::vector)) {
    1054             :       kwIsCorrect = true;
    1055             :     }
    1056       71833 :     if( rank==2  && valid(at | argType::matrix)) {
    1057             :       kwIsCorrect = true;
    1058             :     }
    1059             :     allArgumentsAreCorrect &= kwIsCorrect;
    1060       53430 :   }
    1061       53430 :   return allArgumentsAreCorrect;
    1062             : }
    1063             : 
    1064       15402 : std::string Keywords::getArgumentType( const std::string& name ) const {
    1065       15402 :   auto argument_keys = getArgumentKeys();
    1066       15402 :   if( find(argument_keys.begin(),argument_keys.end(),name)==argument_keys.end() ) {
    1067        5107 :     return "";
    1068             :   }
    1069       20590 :   return toString(std::get<argType>(keywords.at(name).argument_type));
    1070       15402 : }
    1071             : 
    1072       54068 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
    1073       54068 :   return components.at(name).key;
    1074             : }
    1075             : 
    1076        1318 : std::string Keywords::getOutputComponentType( const std::string& name ) const {
    1077             :   //return toString( components.find(name)->second.type); brings to segfault in case name is ot present
    1078             :   //at at least throws
    1079        1318 :   return toString( components.at(name).type);
    1080             : }
    1081             : 
    1082        6033 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
    1083        6033 :   std::string checkname = name;
    1084        6033 :   std::size_t hyp=name.find_first_of("-");
    1085        6033 :   if( hyp!=std::string::npos ) {
    1086           4 :     checkname = name.substr(0,hyp);
    1087             :   }
    1088             : 
    1089             :   bool found=components.find(checkname)!=components.end();
    1090             : 
    1091        6033 :   if( !found ) {
    1092           0 :     if( name==".#!value" ) {
    1093           0 :       return "the value calculated by this action";
    1094             :     }
    1095           0 :     if( outputComponentExists( name ) ) {
    1096           0 :       plumed_merror("cannot find description for component " + name + " that allegedly exists. Gareth Tribello might know what the fuck that is about.");
    1097             :     }
    1098           0 :     plumed_merror("could not find output component named " + name );
    1099             :   }
    1100        6033 :   return components.at(checkname).docstring;
    1101             : }
    1102             : 
    1103             : ///////////DUPLICATED??????????///////
    1104         108 : void Keywords::removeOutputComponent( const std::string& name ) {
    1105             :   components.erase(name);
    1106         108 :   erase_remove(cnames,name);
    1107         108 : }
    1108             : 
    1109        5305 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
    1110        5305 :   plumed_assert( exists( key ) );
    1111        5305 :   return keywords.at(key).docstring;
    1112             : }
    1113             : 
    1114       74851 : void Keywords::needsAction( const std::string& name ) {
    1115       74851 :   if( std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end() ) {
    1116             :     return;
    1117             :   }
    1118       74204 :   neededActions.push_back( name );
    1119             : }
    1120             : 
    1121       21141 : bool Keywords::isActionNeeded( std::string_view name ) const {
    1122       21141 :   return std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end();
    1123             : }
    1124             : 
    1125         564 : const std::vector<std::string>& Keywords::getNeededKeywords() const {
    1126         564 :   return neededActions;
    1127             : }
    1128             : 
    1129       43857 : void Keywords::addActionNameSuffix( const std::string& suffix ) {
    1130       43857 :   if( std::find(actionNameSuffixes.begin(), actionNameSuffixes.end(), suffix )!=actionNameSuffixes.end() ) {
    1131             :     return;
    1132             :   }
    1133       43857 :   actionNameSuffixes.push_back( suffix );
    1134             : }
    1135             : 
    1136       14575 : bool Keywords::isActionSuffixed( std::string_view name, std::string_view basename) const {
    1137       14575 :   std::string bname{basename};
    1138       14575 :   return std::any_of(actionNameSuffixes.begin(),
    1139             :                      actionNameSuffixes.end(),
    1140       19364 :   [name,&bname](const std::string& suffix)->bool{
    1141       19364 :     return (bname + suffix)==name ;
    1142             :   }
    1143       14575 :                     );
    1144             : }
    1145             : 
    1146      105449 : void Keywords::setDisplayName( const std::string& name ) {
    1147      105449 :   thisactname = name;
    1148      105449 : }
    1149             : 
    1150       89240 : std::string Keywords::getDisplayName() const {
    1151       89240 :   return thisactname;
    1152             : }
    1153             : 
    1154          10 : void Keywords::setDeprecated( const std::string& name ) {
    1155          10 :   replaceaction = name;
    1156          10 : }
    1157             : 
    1158         441 : std::string Keywords::getReplacementAction() const {
    1159         441 :   return replaceaction;
    1160             : }
    1161             : 
    1162       18098 : void Keywords::addDOI( const std::string& doi ) {
    1163       18098 :   doilist.push_back( doi );
    1164       18098 : }
    1165             : 
    1166         561 : const std::vector<std::string>& Keywords::getDOIList() const {
    1167         561 :   return doilist;
    1168             : }
    1169             : 
    1170        3867 : void Keywords::linkActionInDocs( const std::string& k, const std::string& action ) {
    1171        3867 :   plumed_massert( exists(k), "no " + k + " keyword" );
    1172        3867 :   keywords.at(k).setLinkedAction(action);
    1173        3867 : }
    1174             : 
    1175        5305 : std::string Keywords::getLinkedActions( const std::string& key ) const {
    1176        5305 :   plumed_assert( exists( key ) );
    1177        5305 :   return keywords.at(key).linkaction;
    1178             : }
    1179             : 
    1180             : }// namespace PLMD

Generated by: LCOV version 1.16