LCOV - code coverage report
Current view: top level - tools - Keywords.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 237 428 55.4 %
Date: 2024-10-18 14:00:25 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     2139914 : Keywords::KeyType::KeyType( const std::string& type ) {
      31     2139914 :   if( type=="compulsory" ) {
      32      568180 :     style=compulsory;
      33     1571734 :   } else if( type=="flag" ) {
      34      448371 :     style=flag;
      35     1123363 :   } else if( type=="optional" ) {
      36      679287 :     style=optional;
      37      444076 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      38      219224 :     style=atoms;
      39      224852 :   } else if( type=="hidden" ) {
      40      224852 :     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     2139914 : }
      47             : 
      48         922 : void Keywords::KeyType::setStyle( const std::string& type ) {
      49         922 :   if( type=="compulsory" ) {
      50         435 :     style=compulsory;
      51         487 :   } else if( type=="flag" ) {
      52           0 :     style=flag;
      53         487 :   } else if( type=="optional" ) {
      54          25 :     style=optional;
      55         462 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      56         462 :     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         922 : }
      65             : 
      66     1818345 : std::string Keywords::getStyle( const std::string & k ) const {
      67           0 :   plumed_massert( types.count(k), "Did not find keyword " + k );
      68     1818345 :   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) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
      82           0 :     for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
      83           0 :     kk.push_back( thiskey );
      84           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
      85           0 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
      86           0 :     if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
      87           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
      88           0 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
      89           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
      90           0 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
      91           0 :     if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
      92           0 :     if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
      93             :   }
      94           0 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
      95           0 :     std::string thiskey=reserved_keys[i];
      96           0 :     for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
      97           0 :     for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
      98           0 :     rk.push_back( thiskey );
      99           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
     100           0 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
     101           0 :     if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
     102           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
     103           0 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
     104           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
     105           0 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
     106           0 :     if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
     107           0 :     if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
     108             :   }
     109           0 :   for(unsigned i=0; i<cnames.size(); ++i) {
     110           0 :     std::string thisnam=cnames[i];
     111           0 :     for(unsigned j=0; j<cnam.size(); ++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
     112           0 :     cnam.push_back( thisnam );
     113           0 :     plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
     114           0 :     ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
     115           0 :     plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
     116           0 :     cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
     117             :   }
     118           0 : }
     119             : 
     120      261099 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
     121      261099 :   plumed_assert( !exists(k) && !reserved(k) );
     122      261099 :   std::string fd, lowkey=k;
     123             :   // Convert to lower case
     124     2721375 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
     125             : // Remove any underscore characters
     126             :   for(unsigned i=0;; ++i) {
     127      412315 :     std::size_t num=lowkey.find_first_of("_");
     128      412315 :     if( num==std::string::npos ) break;
     129      151216 :     lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
     130      151216 :   }
     131      261099 :   if( t=="vessel" ) {
     132           0 :     fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
     133           0 :     if(d.find("flag")==std::string::npos) fd += ".  You can use multiple instances of this keyword i.e. " +
     134           0 :           k +"1, " + k + "2, " + k + "3...  The corresponding values are then "
     135           0 :           "referenced using <em>label</em>."+ lowkey +"-1,  <em>label</em>." + lowkey +
     136           0 :           "-2,  <em>label</em>." + lowkey + "-3...";
     137           0 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     138           0 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
     139      261099 :   } else if( t=="numbered" ) {
     140       35876 :     fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     141       17938 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     142       35876 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
     143             :   } else {
     144             :     fd = d;
     145      244160 :     if( t=="atoms" && isaction ) fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     146      243161 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     147      486322 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     148      244160 :     if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
     149             :   }
     150      261099 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     151      261099 :   reserved_keys.push_back(k);
     152      261099 : }
     153             : 
     154        1322 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
     155        1322 :   plumed_assert( !exists(k) && !reserved(k) );
     156             :   std::string defstr;
     157        1322 :   if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; }
     158        2644 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     159       19563 :   std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
     160        1322 :   fd=defstr + d;
     161        2644 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     162        1322 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     163           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     164        1322 :   reserved_keys.push_back(k);
     165        1322 : }
     166             : 
     167       44231 : void Keywords::use( const std::string & k ) {
     168       44231 :   plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
     169      260528 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     170      216297 :     if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] );
     171             :   }
     172       44231 : }
     173             : 
     174        7453 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
     175        7453 :   plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
     176        7453 :   if( style=="numbered" ) { allowmultiple[k]=true; return; }
     177         922 :   (types.find(k)->second).setStyle(style);
     178         922 :   if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true;
     179        1384 :   if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,style) );
     180             : }
     181             : 
     182      993228 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
     183     2979684 :   plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
     184             :   std::string fd;
     185      993228 :   if( t=="numbered" ) {
     186       39480 :     fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     187       19740 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     188       39480 :     types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
     189             :   } else {
     190             :     fd=d;
     191      973488 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     192     1946976 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     193     1191713 :     if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
     194             :   }
     195     1041410 :   if( t=="atoms" && isaction ) fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     196      993228 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     197      993228 :   keys.push_back(k);
     198      993228 : }
     199             : 
     200      437216 : void Keywords::add( const std::string & t, const std::string & k, const std::string &  def, const std::string & d ) {
     201      874753 :   plumed_assert( !exists(k) && !reserved(k) &&  (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
     202      437216 :   types.insert(  std::pair<std::string,KeyType>(k, KeyType(t)) );
     203      874432 :   documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
     204      437216 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     205      437216 :   numdefs.insert( std::pair<std::string,std::string>(k,def) );
     206      437216 :   keys.push_back(k);
     207      437216 : }
     208             : 
     209      447049 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
     210      447049 :   plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
     211      447049 :   std::string defstr; plumed_massert( !def, "the second argument to addFlag must be false " + k );
     212             :   defstr="( default=off ) ";
     213      894098 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     214      894098 :   documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
     215      447049 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     216           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     217      447049 :   keys.push_back(k);
     218      447049 : }
     219             : 
     220       13978 : void Keywords::remove( const std::string & k ) {
     221             :   bool found=false; unsigned j=0, n=0;
     222             : 
     223             :   while(true) {
     224      140421 :     for(j=0; j<keys.size(); j++) if(keys[j]==k)break;
     225      119600 :     for(n=0; n<reserved_keys.size(); n++) if(reserved_keys[n]==k)break;
     226       28955 :     if(j<keys.size()) {
     227       13783 :       keys.erase(keys.begin()+j);
     228             :       found=true;
     229       15172 :     } else if(n<reserved_keys.size()) {
     230        1194 :       reserved_keys.erase(reserved_keys.begin()+n);
     231             :       found=true;
     232             :     } else break;
     233             :   }
     234             :   // Delete documentation, type and so on from the description
     235             :   types.erase(k); documentation.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k);
     236             :   // Remove any output comonents that this keyword creates
     237       27781 :   for(const auto& dkey : ckey ) {
     238       13803 :     if( dkey.second==k ) removeOutputComponent( dkey.first );
     239             :   }
     240       13978 :   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
     241       13978 : }
     242             : 
     243      291825 : bool Keywords::numbered( const std::string & k ) const {
     244      583650 :   if( style( k,"atoms") ) return true;
     245           0 :   plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
     246      247963 :   return allowmultiple.find(k)->second;
     247             : }
     248             : 
     249     1813301 : bool Keywords::style( const std::string & k, const std::string & t ) const {
     250     1813301 :   if( getStyle(k)==t ) return true;
     251             :   return false;
     252             : }
     253             : 
     254     1302062 : unsigned Keywords::size() const {
     255     1302062 :   return keys.size();
     256             : }
     257             : 
     258       76929 : std::string Keywords::getKeyword( const unsigned i ) const {
     259       76929 :   plumed_assert( i<size() );
     260       76929 :   return keys[i];
     261             : }
     262             : 
     263     3276102 : bool Keywords::exists( const std::string & k ) const {
     264    28660313 :   for(unsigned i=0; i<keys.size(); ++i) {
     265    26169449 :     if( keys[i]==k ) return true;
     266             :   }
     267             :   return false;
     268             : }
     269             : 
     270     2184145 : bool Keywords::reserved( const std::string & k ) const {
     271     4509454 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     272     2369540 :     if( reserved_keys[i]==k ) return true;
     273             :   }
     274             :   return false;
     275             : }
     276             : 
     277           0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
     278             :   unsigned nkeys=0;
     279             :   std::printf("%s",actionname.c_str());
     280           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     281           0 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     282             :   }
     283           0 :   if( nkeys>0 ) {
     284           0 :     std::string prevtag="start";
     285           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     286           0 :       if( (types.find(keys[i])->second).isAtomList() ) {
     287           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     288           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break;
     289           0 :         if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) std::printf(" %s=<residue selection>", keys[i].c_str() );
     290             :         else std::printf(" %s=<atom selection>", keys[i].c_str() );
     291           0 :         prevtag=atomtags.find(keys[i])->second;
     292             :       }
     293             :     }
     294             :   }
     295             :   nkeys=0;
     296           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     297           0 :     if ( include_optional || \
     298           0 :          (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     299             :   }
     300           0 :   if( nkeys>0 ) {
     301           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     302           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     303             :         std::string def;
     304           0 :         if( getDefaultValue( keys[i], def) ) {
     305             :           std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
     306             :         } else {
     307             :           std::printf(" %s=    ", keys[i].c_str() );
     308             :         }
     309           0 :       } else if (include_optional) {
     310             :         // TG no defaults for optional keywords?
     311             :         std::printf(" [%s]", keys[i].c_str() );
     312             :       }
     313             :     }
     314             :   }
     315             :   std::printf("\n");
     316             :   std::flush(std::cout);
     317           0 : }
     318             : 
     319         438 : void Keywords::print_vim() const {
     320        5482 :   for(unsigned i=0; i<keys.size(); ++i) {
     321        5044 :     if( (types.find(keys[i])->second).isFlag() ) {
     322             :       std::printf( ",flag:%s", keys[i].c_str() );
     323             :     } else {
     324        4044 :       if( allowmultiple.find(keys[i])->second ) std::printf(",numbered:%s",keys[i].c_str() );
     325             :       else std::printf(",option:%s",keys[i].c_str() );
     326             :     }
     327             :   }
     328         438 :   std::fprintf(stdout, "\n%s", getHelpString().c_str() );
     329         438 : }
     330             : 
     331           0 : void Keywords::print_html() const {
     332             : 
     333             : // This is the part that outputs the details of the components
     334           0 :   if( cnames.size()>0 ) {
     335             :     unsigned ndef=0;
     336           0 :     for(unsigned i=0; i<cnames.size(); ++i) {
     337           0 :       if(ckey.find(cnames[i])->second=="default") ndef++;
     338             :     }
     339             : 
     340           0 :     if( ndef>0 ) {
     341           0 :       std::cout<<"\\par Description of components\n\n";
     342           0 :       std::cout<<cstring<<"\n\n";
     343           0 :       std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     344             :       std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
     345             :       unsigned nndef=0;
     346           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     347             :         //plumed_assert( ckey.find(cnames[i])->second=="default" );
     348           0 :         if( ckey.find(cnames[i])->second!="default" ) { nndef++; continue; }
     349             :         std::printf("<tr>\n");
     350             :         std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
     351             :         std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     352             :         std::printf("</tr>\n");
     353             :       }
     354           0 :       std::cout<<"</table>\n\n";
     355           0 :       if( nndef>0 ) {
     356           0 :         std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
     357           0 :         std::cout<<"\n\n";
     358           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     359             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     360           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     361           0 :           if( ckey.find(cnames[i])->second!="default") {
     362             :             std::printf("<tr>\n");
     363             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     364             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     365             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     366             :             std::printf("</tr>\n");
     367             :           }
     368             :         }
     369           0 :         std::cout<<"</table>\n\n";
     370             :       }
     371             :     } else {
     372             :       unsigned nregs=0;
     373           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     374           0 :         if( exists(ckey.find(cnames[i])->second) ) nregs++;
     375             :       }
     376           0 :       if( nregs>0 ) {
     377           0 :         std::cout<<"\\par Description of components\n\n";
     378           0 :         std::cout<<cstring<<"\n\n";
     379           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     380             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     381           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     382           0 :           if( exists(ckey.find(cnames[i])->second) ) {
     383             :             std::printf("<tr>\n");
     384             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     385             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     386             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     387             :             std::printf("</tr>\n");
     388             :           }
     389             :         }
     390           0 :         std::cout<<"</table>\n\n";
     391             :       }
     392             :     }
     393             :   }
     394             : 
     395             :   unsigned nkeys=0;
     396           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     397           0 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     398             :   }
     399           0 :   if( nkeys>0 ) {
     400           0 :     if(isaction && isatoms) std::cout<<"\\par The atoms involved can be specified using\n\n";
     401           0 :     else if(isaction) std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
     402           0 :     else std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     403           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     404           0 :     std::string prevtag="start"; unsigned counter=0;
     405           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     406           0 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     407           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     408           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
     409           0 :           std::cout<<"</table>\n\n";
     410           0 :           if( isatoms ) std::cout<<"\\par Or alternatively by using\n\n";
     411           0 :           else if( counter==0 ) { std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n"; counter++; }
     412           0 :           else std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
     413           0 :           std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     414             :         }
     415           0 :         print_html_item( keys[i] );
     416           0 :         prevtag=atomtags.find(keys[i])->second;
     417             :       }
     418             :     }
     419           0 :     std::cout<<"</table>\n\n";
     420             :   }
     421             :   nkeys=0;
     422           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     423           0 :     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     424             :   }
     425           0 :   if( nkeys>0 ) {
     426           0 :     if(isaction) std::cout<< "\\par Compulsory keywords\n\n";
     427           0 :     else std::cout<<"\\par The following must be present\n\n";
     428           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     429           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     430           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] );
     431             :     }
     432           0 :     std::cout<<"</table>\n\n";
     433             :   }
     434             :   nkeys=0;
     435           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     436           0 :     if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     437             :   }
     438           0 :   if( nkeys>0 ) {
     439           0 :     if(isaction) std::cout<<"\\par Options\n\n";
     440           0 :     else std::cout<<"\\par The following options are available\n\n";
     441           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     442           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     443           0 :       if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] );
     444             :     }
     445           0 :     std::cout<<"\n";
     446             :   }
     447             :   nkeys=0;
     448           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     449           0 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     450             :   }
     451           0 :   if( nkeys>0 ) {
     452           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     453           0 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] );
     454             :     }
     455             :   }
     456           0 :   std::cout<<"</table>\n\n";
     457           0 : }
     458             : 
     459           0 : void Keywords::print_spelling() const {
     460           0 :   for(unsigned i=0; i<keys.size(); ++i) std::printf("%s\n", keys[i].c_str() );
     461           0 :   for(unsigned i=0; i<cnames.size(); ++i) std::printf("%s\n",cnames[i].c_str() );
     462           0 : }
     463             : 
     464        7956 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
     465        7956 :   bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
     466        7956 :   std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
     467       15912 :   std::stringstream sstr; sstr<<std::setw(23)<<key<<" - ";
     468        7956 :   unsigned nl=0; std::string blank=" ";
     469      190534 :   for(unsigned i=0; i<w.size(); ++i) {
     470      183064 :     nl+=w[i].length() + 1;
     471      183064 :     if( nl>60 ) {
     472       39774 :       sstr<<"\n"<<std::setw(23)<<blank<<"   "<<w[i]<<" "; nl=0;
     473      169806 :     } else sstr<<w[i]<<" ";
     474      183064 :     if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
     475             :   }
     476       15912 :   sstr<<"\n"; return sstr.str();
     477        7956 : }
     478             : 
     479         876 : std::string Keywords::getHelpString() const {
     480             :   std::string helpstr; unsigned nkeys=0;
     481       10964 :   for(unsigned i=0; i<keys.size(); ++i) {
     482       10088 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     483             :   }
     484         876 :   if( nkeys>0 ) {
     485             :     helpstr += "The input trajectory can be in any of the following formats: \n\n";
     486        5124 :     for(unsigned i=0; i<keys.size(); ++i) {
     487        5480 :       if ( (types.find(keys[i])->second).isAtomList() ) helpstr += getKeywordDocs( keys[i] );
     488             :     }
     489             :   }
     490             :   nkeys=0;
     491       10964 :   for(unsigned i=0; i<keys.size(); ++i) {
     492       10088 :     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     493             :   }
     494             :   unsigned ncompulsory=nkeys;
     495         876 :   if( nkeys>0 ) {
     496             :     helpstr += "\nThe following arguments are compulsory: \n\n";
     497        8884 :     for(unsigned i=0; i<keys.size(); ++i) {
     498       10468 :       if ( (types.find(keys[i])->second).isCompulsory() ) helpstr += getKeywordDocs( keys[i] );
     499             :     }
     500             :   }
     501             :   nkeys=0;
     502       10964 :   for(unsigned i=0; i<keys.size(); ++i) {
     503       10088 :     if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
     504             :   }
     505         876 :   if( nkeys>0 ) {
     506         702 :     if(ncompulsory>0) helpstr += "\nIn addition you may use the following options: \n\n";
     507             :     else helpstr += "\nThe following options are available\n\n";
     508        9656 :     for(unsigned i=0; i<keys.size(); ++i) {
     509       10954 :       if ( (types.find(keys[i])->second).isFlag() ) helpstr += getKeywordDocs( keys[i] ).c_str();
     510             :     }
     511             :   }
     512             :   nkeys=0;
     513       10964 :   for(unsigned i=0; i<keys.size(); ++i) {
     514       17132 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     515             :   }
     516         876 :   if( nkeys>0 ) {
     517        9412 :     for(unsigned i=0; i<keys.size(); ++i) {
     518       17484 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) helpstr += getKeywordDocs( keys[i] );
     519             :     }
     520             :     helpstr += "\n";
     521             :   }
     522         876 :   return helpstr;
     523             : }
     524             : 
     525           0 : void Keywords::print( Log& log ) const {
     526           0 :   log.printf("%s", getHelpString().c_str() );
     527           0 : }
     528             : 
     529           0 : void Keywords::print( FILE* out ) const {
     530           0 :   fprintf( out,"%s", getHelpString().c_str() );
     531           0 : }
     532             : 
     533           0 : std::string Keywords::getTooltip( const std::string& name ) const {
     534           0 :   std::size_t dd=name.find_first_of("0123456789"); std::string kname=name.substr(0,dd);
     535           0 :   if( !exists(kname) ) return "<b> could not find this keyword </b>";
     536           0 :   std::string mystring, docstr = documentation.find(kname)->second;
     537           0 :   if( types.find(kname)->second.isCompulsory() ) {
     538             :     mystring += "<b>compulsory keyword ";
     539           0 :     if( docstr.find("default")!=std::string::npos ) {
     540           0 :       std::size_t bra = docstr.find_first_of(")"); mystring += docstr.substr(0,bra+1); docstr = docstr.substr(bra+1);
     541             :     }
     542             :     mystring += "</b>\n";
     543             :   }
     544           0 :   std::vector<std::string> w=Tools::getWords( docstr ); unsigned nl=0;
     545           0 :   for(unsigned i=0; i<w.size(); ++i) {
     546           0 :     nl+=w[i].length() + 1;
     547           0 :     if( nl>80 ) { mystring += w[i] + "\n"; nl=0; }
     548           0 :     else { mystring += w[i] + " "; }
     549           0 :     if( w[i].find(".")!=std::string::npos ) break; // Only write up the the first dot
     550             :   }
     551             :   return mystring;
     552           0 : }
     553             : 
     554           0 : void Keywords::print_html_item( const std::string& key ) const {
     555             :   std::printf("<tr>\n");
     556             :   std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
     557             :   std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
     558             :   std::printf("</tr>\n");
     559           0 : }
     560             : 
     561      553733 : std::string Keywords::get( const unsigned k ) const {
     562      553733 :   plumed_assert( k<size() );
     563      553733 :   return keys[k];
     564             : }
     565             : 
     566       84004 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
     567       84004 :   if( booldefs.find(key)!=booldefs.end() ) {
     568       84004 :     def=booldefs.find(key)->second;
     569       84004 :     return true;
     570             :   } else {
     571             :     return false;
     572             :   }
     573             : }
     574             : 
     575       25325 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
     576       36645 :   plumed_assert( style(key,"compulsory") || style(key,"hidden") );
     577             : 
     578       25325 :   if( numdefs.find(key)!=numdefs.end() ) {
     579       19666 :     def=numdefs.find(key)->second;
     580       19666 :     return true;
     581             :   } else {
     582             :     return false;
     583             :   }
     584             : }
     585             : 
     586           0 : void Keywords::destroyData() {
     587           0 :   keys.clear(); reserved_keys.clear(); types.clear();
     588             :   allowmultiple.clear(); documentation.clear();
     589             :   booldefs.clear(); numdefs.clear(); atomtags.clear();
     590             :   ckey.clear(); cdocs.clear(); ckey.clear();
     591           0 : }
     592             : 
     593       33273 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
     594       33273 :   cstring = instr;
     595       33273 : }
     596             : 
     597      134054 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
     598      134054 :   plumed_assert( !outputComponentExists(name) );
     599      134054 :   plumed_massert( name!=".#!value", name + " is reserved for storing description of value" );
     600      134054 :   plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
     601             : 
     602      134054 :   std::size_t num2=name.find_first_of("_");
     603      134054 :   if( num2!=std::string::npos ) {
     604         650 :     char uu = '_'; plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
     605         650 :     plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
     606             :   }
     607      134054 :   if( key=="default" ) {
     608             :     cstring = "By default this Action calculates the following quantities. These quantities can "
     609             :               "be referenced elsewhere in the input by using this Action's label followed by a "
     610      100177 :               "dot and the name of the quantity required from the list below.";
     611             :   }
     612             : 
     613      134054 :   ckey.insert( std::pair<std::string,std::string>(name,key) );
     614      134054 :   cdocs.insert( std::pair<std::string,std::string>(name,descr) );
     615      134054 :   cnames.push_back(name);
     616      134054 : }
     617             : 
     618         108 : void Keywords::removeOutputComponent( const std::string& name ) {
     619             :   unsigned j=0;
     620             :   while(true) {
     621         762 :     for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
     622         216 :     if(j<cnames.size()) cnames.erase(cnames.begin()+j);
     623             :     else break;
     624             :   }
     625             :   cdocs.erase(name);
     626         108 : }
     627             : 
     628       55050 : void Keywords::setValueDescription( const std::string& descr ) {
     629      110100 :   if( !outputComponentExists(".#!value") ) {
     630       48063 :     ckey.insert( std::pair<std::string,std::string>(".#!value","default") );
     631       48063 :     cdocs.insert( std::pair<std::string,std::string>(".#!value",descr) );
     632       96126 :     cnames.push_back(".#!value");
     633       13974 :   } else cdocs[".#!value"] = descr;
     634       55050 : }
     635             : 
     636      301237 : bool Keywords::outputComponentExists( const std::string& name ) const {
     637      301237 :   if( cstring.find("customize")!=std::string::npos ) return true;
     638             : 
     639             :   std::string sname;
     640      296770 :   std::size_t num=name.find_first_of("-");
     641      296770 :   std::size_t num2=name.find_last_of("_");
     642             : 
     643      299284 :   if( num2!=std::string::npos ) sname=name.substr(num2);
     644      321241 :   else if( num!=std::string::npos ) sname=name.substr(0,num);
     645             :   else sname=name;
     646             : 
     647     1045571 :   for(unsigned i=0; i<cnames.size(); ++i) {
     648      862246 :     if( sname==cnames[i] ) return true;
     649             :   }
     650             :   return false;
     651             : }
     652             : 
     653       58621 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
     654       58621 :   return ckey.find(name)->second;
     655             : }
     656             : 
     657        6007 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
     658        6007 :   std::string checkname = name; std::size_t hyp=name.find_first_of("-");
     659        6009 :   if( hyp!=std::string::npos ) checkname = name.substr(0,hyp);
     660             : 
     661             :   bool found=false;
     662       21134 :   for(unsigned i=0; i<cnames.size(); ++i) {
     663       15127 :     if( checkname==cnames[i] ) found=true;
     664             :   }
     665        6007 :   if( !found ) {
     666           3 :     if( name==".#!value" ) return "the value calculated by this action";
     667           0 :     if( outputComponentExists( name ) ) plumed_merror("cannot find description for component " + name + " that allegedly exists. Gareth Tribello might know what the fuck that is about.");
     668           0 :     plumed_merror("could not find output component named " + name );
     669             :   }
     670        6004 :   return cdocs.find(checkname)->second;
     671             : }
     672             : 
     673           0 : void Keywords::removeComponent( const std::string& name ) {
     674             :   bool found=false;
     675             : 
     676             :   while(true) {
     677             :     unsigned j;
     678           0 :     for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
     679           0 :     if(j<cnames.size()) {
     680           0 :       cnames.erase(cnames.begin()+j);
     681             :       found=true;
     682             :     } else break;
     683           0 :   }
     684             :   // Delete documentation, type and so on from the description
     685             :   cdocs.erase(name); ckey.erase(name);
     686           0 :   plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
     687           0 : }
     688             : 
     689        5698 : std::vector<std::string> Keywords::getOutputComponents() const {
     690        5698 :   return cnames;
     691             : }
     692             : 
     693        5044 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
     694       10088 :   plumed_assert( exists( key ) ); return documentation.find(key)->second;
     695             : }
     696             : 
     697       76774 : void Keywords::needsAction( const std::string& name ) {
     698       76774 :   if( std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end() ) return;
     699       76127 :   neededActions.push_back( name );
     700             : }
     701             : 
     702         560 : const std::vector<std::string>& Keywords::getNeededKeywords() const {
     703         560 :   return neededActions;
     704             : }
     705             : 
     706       44105 : void Keywords::addActionNameSuffix( const std::string& suffix ) {
     707       44105 :   if( std::find(actionNameSuffixes.begin(), actionNameSuffixes.end(), suffix )!=actionNameSuffixes.end() ) return;
     708       44105 :   actionNameSuffixes.push_back( suffix );
     709             : }
     710             : 
     711       32198 : void Keywords::setDisplayName( const std::string& name ) {
     712       32198 :   thisactname = name;
     713       32198 : }
     714             : 
     715       69490 : std::string Keywords::getDisplayName() const {
     716       69490 :   return thisactname;
     717             : }
     718             : 
     719             : }

Generated by: LCOV version 1.16