LCOV - code coverage report
Current view: top level - tools - Keywords.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 271 498 54.4 %
Date: 2025-11-25 13:55:50 Functions: 37 48 77.1 %

          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             : 
      28             : namespace PLMD {
      29             : 
      30     2167718 : Keywords::KeyType::KeyType( const std::string& type ) {
      31     2167718 :   if( type=="compulsory" ) {
      32      580669 :     style=compulsory;
      33     1587049 :   } else if( type=="flag" ) {
      34      453060 :     style=flag;
      35     1133989 :   } else if( type=="optional" ) {
      36      685586 :     style=optional;
      37      448403 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      38      222403 :     style=atoms;
      39      226000 :   } else if( type=="hidden" ) {
      40      226000 :     style=hidden;
      41           0 :   } else if( type=="vessel" ) {
      42           0 :     style=vessel;
      43             :   } else {
      44           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      45             :   }
      46     2167718 : }
      47             : 
      48         987 : void Keywords::KeyType::setStyle( const std::string& type ) {
      49         987 :   if( type=="compulsory" ) {
      50         439 :     style=compulsory;
      51         548 :   } else if( type=="flag" ) {
      52           0 :     style=flag;
      53         548 :   } else if( type=="optional" ) {
      54          25 :     style=optional;
      55         523 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      56         523 :     style=atoms;
      57           0 :   } else if( type=="hidden" ) {
      58           0 :     style=hidden;
      59           0 :   } else if( type=="vessel" ) {
      60           0 :     style=vessel;
      61             :   } else {
      62           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      63             :   }
      64         987 : }
      65             : 
      66     1890167 : std::string Keywords::getStyle( const std::string & k ) const {
      67           0 :   plumed_massert( types.count(k), "Did not find keyword " + k );
      68     1890167 :   return (types.find(k)->second).toString();
      69             : }
      70             : 
      71           0 : void Keywords::add( const Keywords& newkeys ) {
      72           0 :   newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs  );
      73           0 : }
      74             : 
      75           0 : void Keywords::copyData( std::vector<std::string>& kk, std::vector<std::string>& rk, std::map<std::string,KeyType>& tt, std::map<std::string,bool>& am,
      76             :                          std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums,
      77             :                          std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck,
      78             :                          std::map<std::string,std::string>& cd ) const {
      79           0 :   for(unsigned i=0; i<keys.size(); ++i) {
      80           0 :     std::string thiskey=keys[i];
      81           0 :     for(unsigned j=0; j<kk.size(); ++j) {
      82           0 :       plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
      83             :     }
      84           0 :     for(unsigned j=0; j<rk.size(); ++j) {
      85           0 :       plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
      86             :     }
      87           0 :     kk.push_back( thiskey );
      88           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
      89           0 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
      90           0 :     if( (types.find(thiskey)->second).isAtomList() ) {
      91           0 :       atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
      92             :     }
      93           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
      94           0 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
      95           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
      96           0 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
      97             :     if( booldefs.count( thiskey ) ) {
      98           0 :       bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
      99             :     }
     100             :     if( numdefs.count( thiskey ) ) {
     101           0 :       nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
     102             :     }
     103             :   }
     104           0 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     105           0 :     std::string thiskey=reserved_keys[i];
     106           0 :     for(unsigned j=0; j<kk.size(); ++j) {
     107           0 :       plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
     108             :     }
     109           0 :     for(unsigned j=0; j<rk.size(); ++j) {
     110           0 :       plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
     111             :     }
     112           0 :     rk.push_back( thiskey );
     113           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
     114           0 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
     115           0 :     if( (types.find(thiskey)->second).isAtomList() ) {
     116           0 :       atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
     117             :     }
     118           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
     119           0 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
     120           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
     121           0 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
     122             :     if( booldefs.count( thiskey ) ) {
     123           0 :       bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
     124             :     }
     125             :     if( numdefs.count( thiskey ) ) {
     126           0 :       nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
     127             :     }
     128             :   }
     129           0 :   for(unsigned i=0; i<cnames.size(); ++i) {
     130           0 :     std::string thisnam=cnames[i];
     131           0 :     for(unsigned j=0; j<cnam.size(); ++j) {
     132           0 :       plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
     133             :     }
     134           0 :     cnam.push_back( thisnam );
     135           0 :     plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
     136           0 :     ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
     137           0 :     plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
     138           0 :     cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
     139             :   }
     140           0 : }
     141             : 
     142      260331 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
     143      260331 :   plumed_assert( !exists(k) && !reserved(k) );
     144      260331 :   std::string fd, lowkey=k;
     145             :   // Convert to lower case
     146      260331 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
     147     2450991 :     return std::tolower(c);
     148             :   });
     149             : // Remove any underscore characters
     150             :   for(unsigned i=0;; ++i) {
     151      410845 :     std::size_t num=lowkey.find_first_of("_");
     152      410845 :     if( num==std::string::npos ) {
     153             :       break;
     154             :     }
     155      150514 :     lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
     156      150514 :   }
     157      260331 :   if( t=="vessel" ) {
     158           0 :     fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
     159           0 :     if(d.find("flag")==std::string::npos)
     160           0 :       fd += ".  You can use multiple instances of this keyword i.e. " +
     161           0 :             k +"1, " + k + "2, " + k + "3...  The corresponding values are then "
     162           0 :             "referenced using <em>label</em>."+ lowkey +"-1,  <em>label</em>." + lowkey +
     163           0 :             "-2,  <em>label</em>." + lowkey + "-3...";
     164           0 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     165           0 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
     166      260331 :   } else if( t=="numbered" ) {
     167       36290 :     fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     168       18145 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     169       36290 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
     170             :   } else {
     171             :     fd = d;
     172      242186 :     if( t=="atoms" && isaction ) {
     173        1998 :       fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     174             :     }
     175      242186 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     176      484372 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     177      242186 :     if( (types.find(k)->second).isAtomList() ) {
     178        1998 :       atomtags.insert( std::pair<std::string,std::string>(k,t) );
     179             :     }
     180             :   }
     181      260331 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     182      260331 :   reserved_keys.push_back(k);
     183      260331 : }
     184             : 
     185        1322 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
     186        1322 :   plumed_assert( !exists(k) && !reserved(k) );
     187             :   std::string defstr;
     188        1322 :   if( def ) {
     189             :     defstr="( default=on ) ";
     190             :   } else {
     191             :     defstr="( default=off ) ";
     192             :   }
     193        2644 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     194        1322 :   std::string fd,lowkey=k;
     195        1322 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
     196       18241 :     return std::tolower(c);
     197             :   });
     198        1322 :   fd=defstr + d;
     199        2644 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     200        1322 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     201           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     202        1322 :   reserved_keys.push_back(k);
     203        1322 : }
     204             : 
     205       44637 : void Keywords::use( const std::string & k ) {
     206       44637 :   plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
     207      262586 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     208      217949 :     if(reserved_keys[i]==k) {
     209       44637 :       keys.push_back( reserved_keys[i] );
     210             :     }
     211             :   }
     212       44637 : }
     213             : 
     214        7522 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
     215        7522 :   plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
     216        7522 :   if( style=="numbered" ) {
     217        6535 :     allowmultiple[k]=true;
     218        6535 :     return;
     219             :   }
     220         987 :   (types.find(k)->second).setStyle(style);
     221         987 :   if( (types.find(k)->second).isVessel() ) {
     222           0 :     allowmultiple[k]=true;
     223             :   }
     224         987 :   if( (types.find(k)->second).isAtomList() ) {
     225        1046 :     atomtags.insert( std::pair<std::string,std::string>(k,style) );
     226             :   }
     227             : }
     228             : 
     229     1007012 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
     230     3021036 :   plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
     231             :   std::string fd;
     232     1007012 :   if( t=="numbered" ) {
     233       40188 :     fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     234       20094 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     235       40188 :     types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
     236             :   } else {
     237             :     fd=d;
     238      986918 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     239     1973836 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     240      986918 :     if( (types.find(k)->second).isAtomList() ) {
     241      442808 :       atomtags.insert( std::pair<std::string,std::string>(k,t) );
     242             :     }
     243             :   }
     244     1007012 :   if( t=="atoms" && isaction ) {
     245       95296 :     fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     246             :   }
     247     1007012 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     248     1007012 :   keys.push_back(k);
     249     1007012 : }
     250             : 
     251      447315 : void Keywords::add( const std::string & t, const std::string & k, const std::string &  def, const std::string & d ) {
     252      894952 :   plumed_assert( !exists(k) && !reserved(k) &&  (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
     253      447315 :   types.insert(  std::pair<std::string,KeyType>(k, KeyType(t)) );
     254      894630 :   documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
     255      447315 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     256      447315 :   numdefs.insert( std::pair<std::string,std::string>(k,def) );
     257      447315 :   keys.push_back(k);
     258      447315 : }
     259             : 
     260      451738 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
     261      451738 :   plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
     262             :   std::string defstr;
     263      451738 :   plumed_massert( !def, "the second argument to addFlag must be false " + k );
     264             :   defstr="( default=off ) ";
     265      903476 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     266      903476 :   documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
     267      451738 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     268           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     269      451738 :   keys.push_back(k);
     270      451738 : }
     271             : 
     272       14282 : void Keywords::remove( const std::string & k ) {
     273             :   bool found=false;
     274             :   unsigned j=0, n=0;
     275             : 
     276             :   while(true) {
     277      146059 :     for(j=0; j<keys.size(); j++)
     278      130583 :       if(keys[j]==k) {
     279             :         break;
     280             :       }
     281      122440 :     for(n=0; n<reserved_keys.size(); n++)
     282       95070 :       if(reserved_keys[n]==k) {
     283             :         break;
     284             :       }
     285       29563 :     if(j<keys.size()) {
     286       14087 :       keys.erase(keys.begin()+j);
     287             :       found=true;
     288       15476 :     } else if(n<reserved_keys.size()) {
     289        1194 :       reserved_keys.erase(reserved_keys.begin()+n);
     290             :       found=true;
     291             :     } else {
     292             :       break;
     293             :     }
     294             :   }
     295             :   // Delete documentation, type and so on from the description
     296             :   types.erase(k);
     297             :   documentation.erase(k);
     298             :   allowmultiple.erase(k);
     299             :   booldefs.erase(k);
     300             :   numdefs.erase(k);
     301             :   // Remove any output comonents that this keyword creates
     302       28505 :   for(const auto& dkey : ckey ) {
     303       14223 :     if( dkey.second==k ) {
     304         108 :       removeOutputComponent( dkey.first );
     305             :     }
     306             :   }
     307       14282 :   plumed_massert(found,"You are trying to forbid " + k + " a keyword that isn't there"); // You have tried to forbid a keyword that isn't there
     308       14282 : }
     309             : 
     310      317731 : bool Keywords::numbered( const std::string & k ) const {
     311      635462 :   if( style( k,"atoms") ) {
     312             :     return true;
     313             :   }
     314           0 :   plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
     315      273317 :   return allowmultiple.find(k)->second;
     316             : }
     317             : 
     318     1885104 : bool Keywords::style( const std::string & k, const std::string & t ) const {
     319     1885104 :   if( getStyle(k)==t ) {
     320      419808 :     return true;
     321             :   }
     322             :   return false;
     323             : }
     324             : 
     325     1332388 : unsigned Keywords::size() const {
     326     1332388 :   return keys.size();
     327             : }
     328             : 
     329       77185 : std::string Keywords::getKeyword( const unsigned i ) const {
     330       77185 :   plumed_assert( i<size() );
     331       77185 :   return keys[i];
     332             : }
     333             : 
     334     3335446 : bool Keywords::exists( const std::string & k ) const {
     335    29343177 :   for(unsigned i=0; i<keys.size(); ++i) {
     336    26827539 :     if( keys[i]==k ) {
     337             :       return true;
     338             :     }
     339             :   }
     340             :   return false;
     341             : }
     342             : 
     343     2212355 : bool Keywords::reserved( const std::string & k ) const {
     344     4541072 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     345     2373354 :     if( reserved_keys[i]==k ) {
     346             :       return true;
     347             :     }
     348             :   }
     349             :   return false;
     350             : }
     351             : 
     352           0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
     353             :   unsigned nkeys=0;
     354             :   std::printf("%s",actionname.c_str());
     355           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     356           0 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     357           0 :       nkeys++;
     358             :     }
     359             :   }
     360           0 :   if( nkeys>0 ) {
     361           0 :     std::string prevtag="start";
     362           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     363           0 :       if( (types.find(keys[i])->second).isAtomList() ) {
     364           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     365           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) {
     366             :           break;
     367             :         }
     368           0 :         if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) {
     369             :           std::printf(" %s=<residue selection>", keys[i].c_str() );
     370             :         } else {
     371             :           std::printf(" %s=<atom selection>", keys[i].c_str() );
     372             :         }
     373           0 :         prevtag=atomtags.find(keys[i])->second;
     374             :       }
     375             :     }
     376             :   }
     377             :   nkeys=0;
     378           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     379           0 :     if ( include_optional || \
     380             :          (types.find(keys[i])->second).isCompulsory() ) {
     381           0 :       nkeys++;
     382             :     }
     383             :   }
     384           0 :   if( nkeys>0 ) {
     385           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     386           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     387             :         std::string def;
     388           0 :         if( getDefaultValue( keys[i], def) ) {
     389             :           std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
     390             :         } else {
     391             :           std::printf(" %s=    ", keys[i].c_str() );
     392             :         }
     393           0 :       } else if (include_optional) {
     394             :         // TG no defaults for optional keywords?
     395             :         std::printf(" [%s]", keys[i].c_str() );
     396             :       }
     397             :     }
     398             :   }
     399             :   std::printf("\n");
     400             :   std::flush(std::cout);
     401           0 : }
     402             : 
     403         439 : void Keywords::print_vim() const {
     404        5502 :   for(unsigned i=0; i<keys.size(); ++i) {
     405        5063 :     if( (types.find(keys[i])->second).isFlag() ) {
     406             :       std::printf( ",flag:%s", keys[i].c_str() );
     407             :     } else {
     408        4061 :       if( allowmultiple.find(keys[i])->second ) {
     409             :         std::printf(",numbered:%s",keys[i].c_str() );
     410             :       } else {
     411             :         std::printf(",option:%s",keys[i].c_str() );
     412             :       }
     413             :     }
     414             :   }
     415         439 :   std::fprintf(stdout, "\n%s", getHelpString().c_str() );
     416         439 : }
     417             : 
     418           0 : void Keywords::print_html() const {
     419             : 
     420             : // This is the part that outputs the details of the components
     421           0 :   if( cnames.size()>0 ) {
     422             :     unsigned ndef=0;
     423           0 :     for(unsigned i=0; i<cnames.size(); ++i) {
     424           0 :       if(ckey.find(cnames[i])->second=="default") {
     425           0 :         ndef++;
     426             :       }
     427             :     }
     428             : 
     429           0 :     if( ndef>0 ) {
     430           0 :       std::cout<<"\\par Description of components\n\n";
     431           0 :       std::cout<<cstring<<"\n\n";
     432           0 :       std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     433             :       std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
     434             :       unsigned nndef=0;
     435           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     436             :         //plumed_assert( ckey.find(cnames[i])->second=="default" );
     437           0 :         if( ckey.find(cnames[i])->second!="default" ) {
     438           0 :           nndef++;
     439           0 :           continue;
     440             :         }
     441             :         std::printf("<tr>\n");
     442             :         std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
     443             :         std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     444             :         std::printf("</tr>\n");
     445             :       }
     446           0 :       std::cout<<"</table>\n\n";
     447           0 :       if( nndef>0 ) {
     448           0 :         std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
     449           0 :         std::cout<<"\n\n";
     450           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     451             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     452           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     453           0 :           if( ckey.find(cnames[i])->second!="default") {
     454             :             std::printf("<tr>\n");
     455             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     456             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     457             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     458             :             std::printf("</tr>\n");
     459             :           }
     460             :         }
     461           0 :         std::cout<<"</table>\n\n";
     462             :       }
     463             :     } else {
     464             :       unsigned nregs=0;
     465           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     466           0 :         if( exists(ckey.find(cnames[i])->second) ) {
     467           0 :           nregs++;
     468             :         }
     469             :       }
     470           0 :       if( nregs>0 ) {
     471           0 :         std::cout<<"\\par Description of components\n\n";
     472           0 :         std::cout<<cstring<<"\n\n";
     473           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     474             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     475           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     476           0 :           if( exists(ckey.find(cnames[i])->second) ) {
     477             :             std::printf("<tr>\n");
     478             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     479             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     480             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     481             :             std::printf("</tr>\n");
     482             :           }
     483             :         }
     484           0 :         std::cout<<"</table>\n\n";
     485             :       }
     486             :     }
     487             :   }
     488             : 
     489             :   unsigned nkeys=0;
     490           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     491           0 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     492           0 :       nkeys++;
     493             :     }
     494             :   }
     495           0 :   if( nkeys>0 ) {
     496           0 :     if(isaction && isatoms) {
     497           0 :       std::cout<<"\\par The atoms involved can be specified using\n\n";
     498           0 :     } else if(isaction) {
     499           0 :       std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
     500             :     } else {
     501           0 :       std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     502             :     }
     503           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     504           0 :     std::string prevtag="start";
     505             :     unsigned counter=0;
     506           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     507           0 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     508           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     509           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
     510           0 :           std::cout<<"</table>\n\n";
     511           0 :           if( isatoms ) {
     512           0 :             std::cout<<"\\par Or alternatively by using\n\n";
     513           0 :           } else if( counter==0 ) {
     514           0 :             std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n";
     515           0 :             counter++;
     516             :           } else {
     517           0 :             std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
     518             :           }
     519           0 :           std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     520             :         }
     521           0 :         print_html_item( keys[i] );
     522           0 :         prevtag=atomtags.find(keys[i])->second;
     523             :       }
     524             :     }
     525           0 :     std::cout<<"</table>\n\n";
     526             :   }
     527             :   nkeys=0;
     528           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     529           0 :     if ( (types.find(keys[i])->second).isCompulsory() ) {
     530           0 :       nkeys++;
     531             :     }
     532             :   }
     533           0 :   if( nkeys>0 ) {
     534           0 :     if(isaction) {
     535           0 :       std::cout<< "\\par Compulsory keywords\n\n";
     536             :     } else {
     537           0 :       std::cout<<"\\par The following must be present\n\n";
     538             :     }
     539           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     540           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     541           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     542           0 :         print_html_item( keys[i] );
     543             :       }
     544             :     }
     545           0 :     std::cout<<"</table>\n\n";
     546             :   }
     547             :   nkeys=0;
     548           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     549           0 :     if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     550           0 :       nkeys++;
     551             :     }
     552             :   }
     553           0 :   if( nkeys>0 ) {
     554           0 :     if(isaction) {
     555           0 :       std::cout<<"\\par Options\n\n";
     556             :     } else {
     557           0 :       std::cout<<"\\par The following options are available\n\n";
     558             :     }
     559           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     560           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     561           0 :       if ( (types.find(keys[i])->second).isFlag() ) {
     562           0 :         print_html_item( keys[i] );
     563             :       }
     564             :     }
     565           0 :     std::cout<<"\n";
     566             :   }
     567             :   nkeys=0;
     568           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     569           0 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     570           0 :       nkeys++;
     571             :     }
     572             :   }
     573           0 :   if( nkeys>0 ) {
     574           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     575           0 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     576           0 :         print_html_item( keys[i] );
     577             :       }
     578             :     }
     579             :   }
     580           0 :   std::cout<<"</table>\n\n";
     581           0 : }
     582             : 
     583           0 : void Keywords::print_spelling() const {
     584           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     585             :     std::printf("%s\n", keys[i].c_str() );
     586             :   }
     587           0 :   for(unsigned i=0; i<cnames.size(); ++i) {
     588             :     std::printf("%s\n",cnames[i].c_str() );
     589             :   }
     590           0 : }
     591             : 
     592        7990 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
     593        7990 :   bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
     594        7990 :   std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
     595        7990 :   std::stringstream sstr;
     596        7990 :   sstr<<std::setw(23)<<key<<" - ";
     597             :   unsigned nl=0;
     598        7990 :   std::string blank=" ";
     599      190988 :   for(unsigned i=0; i<w.size(); ++i) {
     600      183484 :     nl+=w[i].length() + 1;
     601      183484 :     if( nl>60 ) {
     602       39858 :       sstr<<"\n"<<std::setw(23)<<blank<<"   "<<w[i]<<" ";
     603             :       nl=0;
     604             :     } else {
     605      170198 :       sstr<<w[i]<<" ";
     606             :     }
     607      183484 :     if( killdot && w[i].find(".")!=std::string::npos ) {
     608             :       break;  // If there is latex only write up to first dot
     609             :     }
     610             :   }
     611        7990 :   sstr<<"\n";
     612        7990 :   return sstr.str();
     613        7990 : }
     614             : 
     615         878 : std::string Keywords::getHelpString() const {
     616             :   std::string helpstr;
     617             :   unsigned nkeys=0;
     618       11004 :   for(unsigned i=0; i<keys.size(); ++i) {
     619       10126 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     620         670 :       nkeys++;
     621             :     }
     622             :   }
     623         878 :   if( nkeys>0 ) {
     624             :     helpstr += "The input trajectory can be in any of the following formats: \n\n";
     625        5160 :     for(unsigned i=0; i<keys.size(); ++i) {
     626        4846 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     627        1340 :         helpstr += getKeywordDocs( keys[i] );
     628             :       }
     629             :     }
     630             :   }
     631             :   nkeys=0;
     632       11004 :   for(unsigned i=0; i<keys.size(); ++i) {
     633       10126 :     if ( (types.find(keys[i])->second).isCompulsory() ) {
     634        2250 :       nkeys++;
     635             :     }
     636             :   }
     637             :   unsigned ncompulsory=nkeys;
     638         878 :   if( nkeys>0 ) {
     639             :     helpstr += "\nThe following arguments are compulsory: \n\n";
     640        8924 :     for(unsigned i=0; i<keys.size(); ++i) {
     641        8262 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     642        4500 :         helpstr += getKeywordDocs( keys[i] );
     643             :       }
     644             :     }
     645             :   }
     646             :   nkeys=0;
     647       11004 :   for(unsigned i=0; i<keys.size(); ++i) {
     648       10126 :     if ( (types.find(keys[i])->second).isFlag() ) {
     649        2004 :       nkeys++;
     650             :     }
     651             :   }
     652         878 :   if( nkeys>0 ) {
     653         704 :     if(ncompulsory>0) {
     654             :       helpstr += "\nIn addition you may use the following options: \n\n";
     655             :     } else {
     656             :       helpstr += "\nThe following options are available\n\n";
     657             :     }
     658        9696 :     for(unsigned i=0; i<keys.size(); ++i) {
     659        8992 :       if ( (types.find(keys[i])->second).isFlag() ) {
     660        4008 :         helpstr += getKeywordDocs( keys[i] ).c_str();
     661             :       }
     662             :     }
     663             :   }
     664             :   nkeys=0;
     665       11004 :   for(unsigned i=0; i<keys.size(); ++i) {
     666       17186 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     667        3066 :       nkeys++;
     668             :     }
     669             :   }
     670         878 :   if( nkeys>0 ) {
     671        9452 :     for(unsigned i=0; i<keys.size(); ++i) {
     672       14494 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     673        6132 :         helpstr += getKeywordDocs( keys[i] );
     674             :       }
     675             :     }
     676             :     helpstr += "\n";
     677             :   }
     678         878 :   return helpstr;
     679             : }
     680             : 
     681           0 : void Keywords::print( Log& log ) const {
     682           0 :   log.printf("%s", getHelpString().c_str() );
     683           0 : }
     684             : 
     685           0 : void Keywords::print( FILE* out ) const {
     686           0 :   fprintf( out,"%s", getHelpString().c_str() );
     687           0 : }
     688             : 
     689           0 : std::string Keywords::getTooltip( const std::string& name ) const {
     690           0 :   std::size_t dd=name.find_first_of("0123456789");
     691           0 :   std::string kname=name.substr(0,dd);
     692           0 :   if( !exists(kname) ) {
     693           0 :     return "<b> could not find this keyword </b>";
     694             :   }
     695           0 :   std::string mystring, docstr = documentation.find(kname)->second;
     696           0 :   if( types.find(kname)->second.isCompulsory() ) {
     697             :     mystring += "<b>compulsory keyword ";
     698           0 :     if( docstr.find("default")!=std::string::npos ) {
     699           0 :       std::size_t bra = docstr.find_first_of(")");
     700           0 :       mystring += docstr.substr(0,bra+1);
     701           0 :       docstr = docstr.substr(bra+1);
     702             :     }
     703             :     mystring += "</b>\n";
     704             :   }
     705           0 :   std::vector<std::string> w=Tools::getWords( docstr );
     706             :   unsigned nl=0;
     707           0 :   for(unsigned i=0; i<w.size(); ++i) {
     708           0 :     nl+=w[i].length() + 1;
     709           0 :     if( nl>80 ) {
     710           0 :       mystring += w[i] + "\n";
     711             :       nl=0;
     712             :     } else {
     713           0 :       mystring += w[i] + " ";
     714             :     }
     715           0 :     if( w[i].find(".")!=std::string::npos ) {
     716             :       break;  // Only write up the the first dot
     717             :     }
     718             :   }
     719             :   return mystring;
     720           0 : }
     721             : 
     722           0 : void Keywords::print_html_item( const std::string& key ) const {
     723             :   std::printf("<tr>\n");
     724             :   std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
     725             :   std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
     726             :   std::printf("</tr>\n");
     727           0 : }
     728             : 
     729      568609 : std::string Keywords::get( const unsigned k ) const {
     730      568609 :   plumed_assert( k<size() );
     731      568609 :   return keys[k];
     732             : }
     733             : 
     734       83665 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
     735       83665 :   if( booldefs.find(key)!=booldefs.end() ) {
     736       83665 :     def=booldefs.find(key)->second;
     737       83665 :     return true;
     738             :   } else {
     739             :     return false;
     740             :   }
     741             : }
     742             : 
     743       26103 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
     744       37783 :   plumed_assert( style(key,"compulsory") || style(key,"hidden") );
     745             : 
     746       26103 :   if( numdefs.find(key)!=numdefs.end() ) {
     747       20264 :     def=numdefs.find(key)->second;
     748       20264 :     return true;
     749             :   } else {
     750             :     return false;
     751             :   }
     752             : }
     753             : 
     754           0 : void Keywords::destroyData() {
     755           0 :   keys.clear();
     756           0 :   reserved_keys.clear();
     757             :   types.clear();
     758             :   allowmultiple.clear();
     759             :   documentation.clear();
     760             :   booldefs.clear();
     761             :   numdefs.clear();
     762             :   atomtags.clear();
     763             :   ckey.clear();
     764             :   cdocs.clear();
     765             :   ckey.clear();
     766           0 : }
     767             : 
     768       33634 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
     769       33634 :   cstring = instr;
     770       33634 : }
     771             : 
     772      131915 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
     773      131915 :   plumed_assert( !outputComponentExists(name) );
     774      131915 :   plumed_massert( name!=".#!value", name + " is reserved for storing description of value" );
     775      131915 :   plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
     776             : 
     777      131915 :   std::size_t num2=name.find_first_of("_");
     778      131915 :   if( num2!=std::string::npos ) {
     779         662 :     char uu = '_';
     780         662 :     plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
     781         662 :     plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
     782             :   }
     783      131915 :   if( key=="default" ) {
     784             :     cstring = "By default this Action calculates the following quantities. These quantities can "
     785             :               "be referenced elsewhere in the input by using this Action's label followed by a "
     786       97671 :               "dot and the name of the quantity required from the list below.";
     787             :   }
     788             : 
     789      131915 :   ckey.insert( std::pair<std::string,std::string>(name,key) );
     790      131915 :   cdocs.insert( std::pair<std::string,std::string>(name,descr) );
     791      131915 :   cnames.push_back(name);
     792      131915 : }
     793             : 
     794         108 : void Keywords::removeOutputComponent( const std::string& name ) {
     795             :   unsigned j=0;
     796             :   while(true) {
     797         762 :     for(j=0; j<cnames.size(); j++)
     798         654 :       if(cnames[j]==name) {
     799             :         break;
     800             :       }
     801         216 :     if(j<cnames.size()) {
     802         108 :       cnames.erase(cnames.begin()+j);
     803             :     } else {
     804             :       break;
     805             :     }
     806             :   }
     807             :   cdocs.erase(name);
     808         108 : }
     809             : 
     810       55090 : void Keywords::setValueDescription( const std::string& descr ) {
     811      110180 :   if( !outputComponentExists(".#!value") ) {
     812       48065 :     ckey.insert( std::pair<std::string,std::string>(".#!value","default") );
     813       48065 :     cdocs.insert( std::pair<std::string,std::string>(".#!value",descr) );
     814       96130 :     cnames.push_back(".#!value");
     815             :   } else {
     816       14050 :     cdocs[".#!value"] = descr;
     817             :   }
     818       55090 : }
     819             : 
     820      298396 : bool Keywords::outputComponentExists( const std::string& name ) const {
     821      298396 :   if( cstring.find("customize")!=std::string::npos ) {
     822             :     return true;
     823             :   }
     824             : 
     825             :   std::string sname;
     826      293929 :   std::size_t num=name.find_first_of("-");
     827      293929 :   std::size_t num2=name.find_last_of("_");
     828             : 
     829      293929 :   if( num2!=std::string::npos ) {
     830        5076 :     sname=name.substr(num2);
     831      291391 :   } else if( num!=std::string::npos ) {
     832       54492 :     sname=name.substr(0,num);
     833             :   } else {
     834             :     sname=name;
     835             :   }
     836             : 
     837     1041001 :   for(unsigned i=0; i<cnames.size(); ++i) {
     838      859806 :     if( sname==cnames[i] ) {
     839             :       return true;
     840             :     }
     841             :   }
     842             :   return false;
     843             : }
     844             : 
     845       51055 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
     846       51055 :   return ckey.find(name)->second;
     847             : }
     848             : 
     849        6020 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
     850        6020 :   std::string checkname = name;
     851        6020 :   std::size_t hyp=name.find_first_of("-");
     852        6020 :   if( hyp!=std::string::npos ) {
     853           4 :     checkname = name.substr(0,hyp);
     854             :   }
     855             : 
     856             :   bool found=false;
     857       21160 :   for(unsigned i=0; i<cnames.size(); ++i) {
     858       15140 :     if( checkname==cnames[i] ) {
     859             :       found=true;
     860             :     }
     861             :   }
     862        6020 :   if( !found ) {
     863           3 :     if( name==".#!value" ) {
     864           3 :       return "the value calculated by this action";
     865             :     }
     866           0 :     if( outputComponentExists( name ) ) {
     867           0 :       plumed_merror("cannot find description for component " + name + " that allegedly exists. Gareth Tribello might know what the fuck that is about.");
     868             :     }
     869           0 :     plumed_merror("could not find output component named " + name );
     870             :   }
     871        6017 :   return cdocs.find(checkname)->second;
     872             : }
     873             : 
     874           0 : void Keywords::removeComponent( const std::string& name ) {
     875             :   bool found=false;
     876             : 
     877             :   while(true) {
     878             :     unsigned j;
     879           0 :     for(j=0; j<cnames.size(); j++)
     880           0 :       if(cnames[j]==name) {
     881             :         break;
     882             :       }
     883           0 :     if(j<cnames.size()) {
     884           0 :       cnames.erase(cnames.begin()+j);
     885             :       found=true;
     886             :     } else {
     887             :       break;
     888             :     }
     889           0 :   }
     890             :   // Delete documentation, type and so on from the description
     891             :   cdocs.erase(name);
     892             :   ckey.erase(name);
     893           0 :   plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
     894           0 : }
     895             : 
     896        5750 : std::vector<std::string> Keywords::getOutputComponents() const {
     897        5750 :   return cnames;
     898             : }
     899             : 
     900        5063 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
     901        5063 :   plumed_assert( exists( key ) );
     902        5063 :   return documentation.find(key)->second;
     903             : }
     904             : 
     905       74854 : void Keywords::needsAction( const std::string& name ) {
     906       74854 :   if( std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end() ) {
     907             :     return;
     908             :   }
     909       74207 :   neededActions.push_back( name );
     910             : }
     911             : 
     912         561 : const std::vector<std::string>& Keywords::getNeededKeywords() const {
     913         561 :   return neededActions;
     914             : }
     915             : 
     916       43961 : void Keywords::addActionNameSuffix( const std::string& suffix ) {
     917       43961 :   if( std::find(actionNameSuffixes.begin(), actionNameSuffixes.end(), suffix )!=actionNameSuffixes.end() ) {
     918             :     return;
     919             :   }
     920       43961 :   actionNameSuffixes.push_back( suffix );
     921             : }
     922             : 
     923       31668 : void Keywords::setDisplayName( const std::string& name ) {
     924       31668 :   thisactname = name;
     925       31668 : }
     926             : 
     927       68808 : std::string Keywords::getDisplayName() const {
     928       68808 :   return thisactname;
     929             : }
     930             : 
     931             : }

Generated by: LCOV version 1.16