LCOV - code coverage report
Current view: top level - tools - Keywords.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 271 458 59.2 %
Date: 2026-03-30 13:16:06 Functions: 32 41 78.0 %

          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     1222984 : Keywords::KeyType::KeyType( const std::string& type ) {
      31     1222984 :   if( type=="compulsory" ) {
      32      328711 :     style=compulsory;
      33      894273 :   } else if( type=="flag" ) {
      34      242955 :     style=flag;
      35      651318 :   } else if( type=="optional" ) {
      36      342211 :     style=optional;
      37      309107 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      38      157623 :     style=atoms;
      39      151484 :   } else if( type=="hidden" ) {
      40       73369 :     style=hidden;
      41       78115 :   } else if( type=="vessel" ) {
      42       78115 :     style=vessel;
      43             :   } else {
      44           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      45             :   }
      46     1222984 : }
      47             : 
      48        5295 : void Keywords::KeyType::setStyle( const std::string& type ) {
      49        5295 :   if( type=="compulsory" ) {
      50         123 :     style=compulsory;
      51        5172 :   } else if( type=="flag" ) {
      52           0 :     style=flag;
      53        5172 :   } else if( type=="optional" ) {
      54          40 :     style=optional;
      55        5132 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      56         348 :     style=atoms;
      57        4784 :   } else if( type=="hidden" ) {
      58         189 :     style=hidden;
      59        4595 :   } else if( type=="vessel" ) {
      60        4595 :     style=vessel;
      61             :   } else {
      62           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      63             :   }
      64        5295 : }
      65             : 
      66      875721 : std::string Keywords::getStyle( const std::string & k ) const {
      67           0 :   plumed_massert( types.count(k), "Did not find keyword " + k );
      68      875721 :   return (types.find(k)->second).toString();
      69             : }
      70             : 
      71        1040 : void Keywords::add( const Keywords& newkeys ) {
      72        1040 :   newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs  );
      73        1040 : }
      74             : 
      75        1040 : 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        1040 :   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       19760 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     105       18720 :     std::string thiskey=reserved_keys[i];
     106      185706 :     for(unsigned j=0; j<kk.size(); ++j) {
     107      166986 :       plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
     108             :     }
     109      259542 :     for(unsigned j=0; j<rk.size(); ++j) {
     110      240822 :       plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
     111             :     }
     112       18720 :     rk.push_back( thiskey );
     113           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
     114       18720 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
     115       18720 :     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       18720 :     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       37440 :     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       19760 :   for(unsigned i=0; i<cnames.size(); ++i) {
     130       18720 :     std::string thisnam=cnames[i];
     131      177840 :     for(unsigned j=0; j<cnam.size(); ++j) {
     132      159120 :       plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
     133             :     }
     134       18720 :     cnam.push_back( thisnam );
     135           0 :     plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
     136       37440 :     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       37440 :     cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
     139             :   }
     140        1040 : }
     141             : 
     142      138524 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
     143      138524 :   plumed_assert( !exists(k) && !reserved(k) );
     144      138524 :   std::string fd, lowkey=k;
     145             :   // Convert to lower case
     146      138524 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
     147     1029202 :     return std::tolower(c);
     148             :   });
     149             : // Remove any underscore characters
     150             :   for(unsigned i=0;; ++i) {
     151      186816 :     std::size_t num=lowkey.find_first_of("_");
     152      186816 :     if( num==std::string::npos ) {
     153             :       break;
     154             :     }
     155       48292 :     lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
     156       48292 :   }
     157      138524 :   if( t=="vessel" ) {
     158      156230 :     fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
     159       78115 :     if(d.find("flag")==std::string::npos)
     160      137850 :       fd += ".  You can use multiple instances of this keyword i.e. " +
     161      137850 :             k +"1, " + k + "2, " + k + "3...  The corresponding values are then "
     162      137850 :             "referenced using <em>label</em>."+ lowkey +"-1,  <em>label</em>." + lowkey +
     163      137850 :             "-2,  <em>label</em>." + lowkey + "-3...";
     164       78115 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     165      156230 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
     166       60409 :   } else if( t=="numbered" ) {
     167        7006 :     fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     168        3503 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     169        7006 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
     170             :   } else {
     171             :     fd = d;
     172       56906 :     if( t=="atoms" && isaction ) {
     173           0 :       fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     174             :     }
     175       56906 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     176      113812 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     177       56906 :     if( (types.find(k)->second).isAtomList() ) {
     178        3906 :       atomtags.insert( std::pair<std::string,std::string>(k,t) );
     179             :     }
     180             :   }
     181      138524 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     182      138524 :   reserved_keys.push_back(k);
     183      138524 : }
     184             : 
     185        2464 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
     186        2464 :   plumed_assert( !exists(k) && !reserved(k) );
     187             :   std::string defstr;
     188        2464 :   if( def ) {
     189             :     defstr="( default=on ) ";
     190             :   } else {
     191             :     defstr="( default=off ) ";
     192             :   }
     193        4928 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     194        2464 :   std::string fd,lowkey=k;
     195        2464 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
     196       26925 :     return std::tolower(c);
     197             :   });
     198        2464 :   fd=defstr + d;
     199        4928 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     200        2464 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     201           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     202        2464 :   reserved_keys.push_back(k);
     203        2464 : }
     204             : 
     205       17719 : void Keywords::use( const std::string & k ) {
     206       17719 :   plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
     207      237781 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     208      220062 :     if(reserved_keys[i]==k) {
     209       17719 :       keys.push_back( reserved_keys[i] );
     210             :     }
     211             :   }
     212       17719 : }
     213             : 
     214        5295 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
     215        5295 :   plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
     216        5295 :   (types.find(k)->second).setStyle(style);
     217        5295 :   if( (types.find(k)->second).isVessel() ) {
     218        4595 :     allowmultiple[k]=true;
     219             :   }
     220        5295 :   if( (types.find(k)->second).isAtomList() ) {
     221         696 :     atomtags.insert( std::pair<std::string,std::string>(k,style) );
     222             :   }
     223        5295 : }
     224             : 
     225      586519 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
     226     1759557 :   plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
     227             :   std::string fd;
     228      586519 :   if( t=="numbered" ) {
     229        3630 :     fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     230        1815 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     231        3630 :     types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
     232             :   } else {
     233             :     fd=d;
     234      584704 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     235     1169408 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     236      584704 :     if( (types.find(k)->second).isAtomList() ) {
     237      311340 :       atomtags.insert( std::pair<std::string,std::string>(k,t) );
     238             :     }
     239             :   }
     240      586519 :   if( t=="atoms" && isaction ) {
     241       37570 :     fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     242             :   }
     243      586519 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     244      586519 :   keys.push_back(k);
     245      586519 : }
     246             : 
     247      254986 : void Keywords::add( const std::string & t, const std::string & k, const std::string &  def, const std::string & d ) {
     248      509972 :   plumed_assert( !exists(k) && !reserved(k) &&  (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
     249      254986 :   types.insert(  std::pair<std::string,KeyType>(k, KeyType(t)) );
     250      509972 :   documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
     251      254986 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     252      254986 :   numdefs.insert( std::pair<std::string,std::string>(k,def) );
     253      254986 :   keys.push_back(k);
     254      254986 : }
     255             : 
     256      240491 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
     257      240491 :   plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
     258             :   std::string defstr;
     259      240491 :   plumed_massert( !def, "the second argument to addFlag must be false " + k );
     260             :   defstr="( default=off ) ";
     261      480982 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     262      480982 :   documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
     263      240491 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     264           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     265      240491 :   keys.push_back(k);
     266      240491 : }
     267             : 
     268        1894 : void Keywords::remove( const std::string & k ) {
     269             :   bool found=false;
     270             :   unsigned j=0, n=0;
     271             : 
     272             :   while(true) {
     273       22014 :     for(j=0; j<keys.size(); j++)
     274       20008 :       if(keys[j]==k) {
     275             :         break;
     276             :       }
     277       46612 :     for(n=0; n<reserved_keys.size(); n++)
     278       42936 :       if(reserved_keys[n]==k) {
     279             :         break;
     280             :       }
     281        3788 :     if(j<keys.size()) {
     282        1782 :       keys.erase(keys.begin()+j);
     283             :       found=true;
     284        2006 :     } else if(n<reserved_keys.size()) {
     285         112 :       reserved_keys.erase(reserved_keys.begin()+n);
     286             :       found=true;
     287             :     } else {
     288             :       break;
     289             :     }
     290             :   }
     291             :   // Delete documentation, type and so on from the description
     292             :   types.erase(k);
     293             :   documentation.erase(k);
     294             :   allowmultiple.erase(k);
     295             :   booldefs.erase(k);
     296             :   numdefs.erase(k);
     297        1894 :   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
     298        1894 : }
     299             : 
     300       18555 : bool Keywords::numbered( const std::string & k ) const {
     301       37110 :   if( style( k,"atoms") ) {
     302             :     return true;
     303             :   }
     304           0 :   plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
     305       15505 :   return allowmultiple.find(k)->second;
     306             : }
     307             : 
     308      866731 : bool Keywords::style( const std::string & k, const std::string & t ) const {
     309      866731 :   if( getStyle(k)==t ) {
     310      222896 :     return true;
     311             :   }
     312             :   return false;
     313             : }
     314             : 
     315      990301 : unsigned Keywords::size() const {
     316      990301 :   return keys.size();
     317             : }
     318             : 
     319       46111 : std::string Keywords::getKeyword( const unsigned i ) const {
     320       46111 :   plumed_assert( i<size() );
     321       46111 :   return keys[i];
     322             : }
     323             : 
     324     1516414 : bool Keywords::exists( const std::string & k ) const {
     325    16443546 :   for(unsigned i=0; i<keys.size(); ++i) {
     326    15173336 :     if( keys[i]==k ) {
     327             :       return true;
     328             :     }
     329             :   }
     330             :   return false;
     331             : }
     332             : 
     333     1245466 : bool Keywords::reserved( const std::string & k ) const {
     334     2881641 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     335     1658657 :     if( reserved_keys[i]==k ) {
     336             :       return true;
     337             :     }
     338             :   }
     339             :   return false;
     340             : }
     341             : 
     342           0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
     343             :   unsigned nkeys=0;
     344             :   std::printf("%s",actionname.c_str());
     345           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     346           0 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     347           0 :       nkeys++;
     348             :     }
     349             :   }
     350           0 :   if( nkeys>0 ) {
     351           0 :     std::string prevtag="start";
     352           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     353           0 :       if( (types.find(keys[i])->second).isAtomList() ) {
     354           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     355           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) {
     356             :           break;
     357             :         }
     358           0 :         if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) {
     359             :           std::printf(" %s=<residue selection>", keys[i].c_str() );
     360             :         } else {
     361             :           std::printf(" %s=<atom selection>", keys[i].c_str() );
     362             :         }
     363           0 :         prevtag=atomtags.find(keys[i])->second;
     364             :       }
     365             :     }
     366             :   }
     367             :   nkeys=0;
     368           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     369           0 :     if ( include_optional || \
     370             :          (types.find(keys[i])->second).isCompulsory() ) {
     371           0 :       nkeys++;
     372             :     }
     373             :   }
     374           0 :   if( nkeys>0 ) {
     375           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     376           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     377             :         std::string def;
     378           0 :         if( getDefaultValue( keys[i], def) ) {
     379             :           std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
     380             :         } else {
     381             :           std::printf(" %s=    ", keys[i].c_str() );
     382             :         }
     383           0 :       } else if (include_optional) {
     384             :         // TG no defaults for optional keywords?
     385             :         std::printf(" [%s]", keys[i].c_str() );
     386             :       }
     387             :     }
     388             :   }
     389             :   std::printf("\n");
     390             :   std::flush(std::cout);
     391           0 : }
     392             : 
     393         584 : void Keywords::print_vim() const {
     394        9574 :   for(unsigned i=0; i<keys.size(); ++i) {
     395        8990 :     if( (types.find(keys[i])->second).isFlag() ) {
     396             :       std::printf( ",flag:%s", keys[i].c_str() );
     397             :     } else {
     398        7088 :       if( allowmultiple.find(keys[i])->second ) {
     399             :         std::printf(",numbered:%s",keys[i].c_str() );
     400             :       } else {
     401             :         std::printf(",option:%s",keys[i].c_str() );
     402             :       }
     403             :     }
     404             :   }
     405         584 :   std::fprintf(stdout, "\n%s", getHelpString().c_str() );
     406         584 : }
     407             : 
     408           0 : void Keywords::print_html() const {
     409             : 
     410             : // This is the part that outputs the details of the components
     411           0 :   if( cnames.size()>0 ) {
     412             :     unsigned ndef=0;
     413           0 :     for(unsigned i=0; i<cnames.size(); ++i) {
     414           0 :       if(ckey.find(cnames[i])->second=="default") {
     415           0 :         ndef++;
     416             :       }
     417             :     }
     418             : 
     419           0 :     if( ndef>0 ) {
     420           0 :       std::cout<<"\\par Description of components\n\n";
     421           0 :       std::cout<<cstring<<"\n\n";
     422           0 :       std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     423             :       std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
     424             :       unsigned nndef=0;
     425           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     426             :         //plumed_assert( ckey.find(cnames[i])->second=="default" );
     427           0 :         if( ckey.find(cnames[i])->second!="default" ) {
     428           0 :           nndef++;
     429           0 :           continue;
     430             :         }
     431             :         std::printf("<tr>\n");
     432             :         std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
     433             :         std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     434             :         std::printf("</tr>\n");
     435             :       }
     436           0 :       std::cout<<"</table>\n\n";
     437           0 :       if( nndef>0 ) {
     438           0 :         std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
     439           0 :         std::cout<<"\n\n";
     440           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     441             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     442           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     443           0 :           if( ckey.find(cnames[i])->second!="default") {
     444             :             std::printf("<tr>\n");
     445             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     446             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     447             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     448             :             std::printf("</tr>\n");
     449             :           }
     450             :         }
     451           0 :         std::cout<<"</table>\n\n";
     452             :       }
     453             :     } else {
     454             :       unsigned nregs=0;
     455           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     456           0 :         if( exists(ckey.find(cnames[i])->second) ) {
     457           0 :           nregs++;
     458             :         }
     459             :       }
     460           0 :       if( nregs>0 ) {
     461           0 :         std::cout<<"\\par Description of components\n\n";
     462           0 :         std::cout<<cstring<<"\n\n";
     463           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     464             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     465           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     466           0 :           if( exists(ckey.find(cnames[i])->second) ) {
     467             :             std::printf("<tr>\n");
     468             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     469             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     470             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     471             :             std::printf("</tr>\n");
     472             :           }
     473             :         }
     474           0 :         std::cout<<"</table>\n\n";
     475             :       }
     476             :     }
     477             :   }
     478             : 
     479             :   unsigned nkeys=0;
     480           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     481           0 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     482           0 :       nkeys++;
     483             :     }
     484             :   }
     485           0 :   if( nkeys>0 ) {
     486           0 :     if(isaction && isatoms) {
     487           0 :       std::cout<<"\\par The atoms involved can be specified using\n\n";
     488           0 :     } else if(isaction) {
     489           0 :       std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
     490             :     } else {
     491           0 :       std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     492             :     }
     493           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     494           0 :     std::string prevtag="start";
     495             :     unsigned counter=0;
     496           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     497           0 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     498           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     499           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
     500           0 :           std::cout<<"</table>\n\n";
     501           0 :           if( isatoms ) {
     502           0 :             std::cout<<"\\par Or alternatively by using\n\n";
     503           0 :           } else if( counter==0 ) {
     504           0 :             std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n";
     505           0 :             counter++;
     506             :           } else {
     507           0 :             std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
     508             :           }
     509           0 :           std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     510             :         }
     511           0 :         print_html_item( keys[i] );
     512           0 :         prevtag=atomtags.find(keys[i])->second;
     513             :       }
     514             :     }
     515           0 :     std::cout<<"</table>\n\n";
     516             :   }
     517             :   nkeys=0;
     518           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     519           0 :     if ( (types.find(keys[i])->second).isCompulsory() ) {
     520           0 :       nkeys++;
     521             :     }
     522             :   }
     523           0 :   if( nkeys>0 ) {
     524           0 :     if(isaction) {
     525           0 :       std::cout<< "\\par Compulsory keywords\n\n";
     526             :     } else {
     527           0 :       std::cout<<"\\par The following must be present\n\n";
     528             :     }
     529           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     530           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     531           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     532           0 :         print_html_item( keys[i] );
     533             :       }
     534             :     }
     535           0 :     std::cout<<"</table>\n\n";
     536             :   }
     537             :   nkeys=0;
     538           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     539           0 :     if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     540           0 :       nkeys++;
     541             :     }
     542             :   }
     543           0 :   if( nkeys>0 ) {
     544           0 :     if(isaction) {
     545           0 :       std::cout<<"\\par Options\n\n";
     546             :     } else {
     547           0 :       std::cout<<"\\par The following options are available\n\n";
     548             :     }
     549           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     550           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     551           0 :       if ( (types.find(keys[i])->second).isFlag() ) {
     552           0 :         print_html_item( keys[i] );
     553             :       }
     554             :     }
     555           0 :     std::cout<<"\n";
     556             :   }
     557             :   nkeys=0;
     558           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     559           0 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     560           0 :       nkeys++;
     561             :     }
     562             :   }
     563           0 :   if( nkeys>0 ) {
     564           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     565           0 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     566           0 :         print_html_item( keys[i] );
     567             :       }
     568             :     }
     569             :   }
     570           0 :   std::cout<<"</table>\n\n";
     571           0 : }
     572             : 
     573           0 : void Keywords::print_spelling() const {
     574           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     575             :     std::printf("%s\n", keys[i].c_str() );
     576             :   }
     577           0 :   for(unsigned i=0; i<cnames.size(); ++i) {
     578             :     std::printf("%s\n",cnames[i].c_str() );
     579             :   }
     580           0 : }
     581             : 
     582       14164 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
     583       14164 :   bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
     584       14164 :   std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
     585       14164 :   std::stringstream sstr;
     586       14164 :   sstr<<std::setw(23)<<key<<" - ";
     587             :   unsigned nl=0;
     588       14164 :   std::string blank=" ";
     589      300460 :   for(unsigned i=0; i<w.size(); ++i) {
     590      287372 :     nl+=w[i].length() + 1;
     591      287372 :     if( nl>60 ) {
     592       66336 :       sstr<<"\n"<<std::setw(23)<<blank<<"   "<<w[i]<<" ";
     593             :       nl=0;
     594             :     } else {
     595      265260 :       sstr<<w[i]<<" ";
     596             :     }
     597      287372 :     if( killdot && w[i].find(".")!=std::string::npos ) {
     598             :       break;  // If there is latex only write up to first dot
     599             :     }
     600             :   }
     601       14164 :   sstr<<"\n";
     602       14164 :   return sstr.str();
     603       14164 : }
     604             : 
     605        1168 : std::string Keywords::getHelpString() const {
     606             :   std::string helpstr;
     607             :   unsigned nkeys=0;
     608       19148 :   for(unsigned i=0; i<keys.size(); ++i) {
     609       17980 :     if ( (types.find(keys[i])->second).isAtomList() ) {
     610        1080 :       nkeys++;
     611             :     }
     612             :   }
     613        1168 :   if( nkeys>0 ) {
     614             :     helpstr += "The input trajectory can be in any of the following formats: \n\n";
     615       10540 :     for(unsigned i=0; i<keys.size(); ++i) {
     616       10020 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     617        2160 :         helpstr += getKeywordDocs( keys[i] );
     618             :       }
     619             :     }
     620             :   }
     621             :   nkeys=0;
     622       19148 :   for(unsigned i=0; i<keys.size(); ++i) {
     623       17980 :     if ( (types.find(keys[i])->second).isCompulsory() ) {
     624        3516 :       nkeys++;
     625             :     }
     626             :   }
     627             :   unsigned ncompulsory=nkeys;
     628        1168 :   if( nkeys>0 ) {
     629             :     helpstr += "\nThe following arguments are compulsory: \n\n";
     630       15684 :     for(unsigned i=0; i<keys.size(); ++i) {
     631       14756 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     632        7032 :         helpstr += getKeywordDocs( keys[i] );
     633             :       }
     634             :     }
     635             :   }
     636             :   nkeys=0;
     637       19148 :   for(unsigned i=0; i<keys.size(); ++i) {
     638       17980 :     if ( (types.find(keys[i])->second).isFlag() ) {
     639        3804 :       nkeys++;
     640             :     }
     641             :   }
     642        1168 :   if( nkeys>0 ) {
     643        1036 :     if(ncompulsory>0) {
     644             :       helpstr += "\nIn addition you may use the following options: \n\n";
     645             :     } else {
     646             :       helpstr += "\nThe following options are available\n\n";
     647             :     }
     648       18288 :     for(unsigned i=0; i<keys.size(); ++i) {
     649       17252 :       if ( (types.find(keys[i])->second).isFlag() ) {
     650        7608 :         helpstr += getKeywordDocs( keys[i] ).c_str();
     651             :       }
     652             :     }
     653             :   }
     654             :   nkeys=0;
     655       19148 :   for(unsigned i=0; i<keys.size(); ++i) {
     656       32304 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     657        5764 :       nkeys++;
     658             :     }
     659             :   }
     660        1168 :   if( nkeys>0 ) {
     661       16672 :     for(unsigned i=0; i<keys.size(); ++i) {
     662       27912 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
     663       11528 :         helpstr += getKeywordDocs( keys[i] );
     664             :       }
     665             :     }
     666             :     helpstr += "\n";
     667             :   }
     668        1168 :   return helpstr;
     669             : }
     670             : 
     671           0 : void Keywords::print( Log& log ) const {
     672           0 :   log.printf("%s", getHelpString().c_str() );
     673           0 : }
     674             : 
     675           0 : void Keywords::print( FILE* out ) const {
     676           0 :   fprintf( out,"%s", getHelpString().c_str() );
     677           0 : }
     678             : 
     679           0 : std::string Keywords::getTooltip( const std::string& name ) const {
     680           0 :   std::size_t dd=name.find_first_of("0123456789");
     681           0 :   std::string kname=name.substr(0,dd);
     682           0 :   if( !exists(kname) ) {
     683           0 :     return "<b> could not find this keyword </b>";
     684             :   }
     685           0 :   std::string mystring, docstr = documentation.find(kname)->second;
     686           0 :   if( types.find(kname)->second.isCompulsory() ) {
     687             :     mystring += "<b>compulsory keyword ";
     688           0 :     if( docstr.find("default")!=std::string::npos ) {
     689           0 :       std::size_t bra = docstr.find_first_of(")");
     690           0 :       mystring += docstr.substr(0,bra+1);
     691           0 :       docstr = docstr.substr(bra+1);
     692             :     }
     693             :     mystring += "</b>\n";
     694             :   }
     695           0 :   std::vector<std::string> w=Tools::getWords( docstr );
     696             :   unsigned nl=0;
     697           0 :   for(unsigned i=0; i<w.size(); ++i) {
     698           0 :     nl+=w[i].length() + 1;
     699           0 :     if( nl>80 ) {
     700           0 :       mystring += w[i] + "\n";
     701             :       nl=0;
     702             :     } else {
     703           0 :       mystring += w[i] + " ";
     704             :     }
     705           0 :     if( w[i].find(".")!=std::string::npos ) {
     706             :       break;  // Only write up the the first dot
     707             :     }
     708             :   }
     709             :   return mystring;
     710           0 : }
     711             : 
     712           0 : void Keywords::print_html_item( const std::string& key ) const {
     713             :   std::printf("<tr>\n");
     714             :   std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
     715             :   std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
     716             :   std::printf("</tr>\n");
     717           0 : }
     718             : 
     719      440378 : std::string Keywords::get( const unsigned k ) const {
     720      440378 :   plumed_assert( k<size() );
     721      440378 :   return keys[k];
     722             : }
     723             : 
     724       37428 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
     725       37428 :   if( booldefs.find(key)!=booldefs.end() ) {
     726       37428 :     def=booldefs.find(key)->second;
     727       37428 :     return true;
     728             :   } else {
     729             :     return false;
     730             :   }
     731             : }
     732             : 
     733       11708 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
     734       22934 :   plumed_assert( style(key,"compulsory") || style(key,"hidden") );
     735             : 
     736       11708 :   if( numdefs.find(key)!=numdefs.end() ) {
     737        6095 :     def=numdefs.find(key)->second;
     738        6095 :     return true;
     739             :   } else {
     740             :     return false;
     741             :   }
     742             : }
     743             : 
     744           0 : void Keywords::destroyData() {
     745           0 :   keys.clear();
     746           0 :   reserved_keys.clear();
     747             :   types.clear();
     748             :   allowmultiple.clear();
     749             :   documentation.clear();
     750             :   booldefs.clear();
     751             :   numdefs.clear();
     752             :   atomtags.clear();
     753             :   ckey.clear();
     754             :   cdocs.clear();
     755             :   ckey.clear();
     756           0 : }
     757             : 
     758        7796 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
     759        7796 :   cstring = instr;
     760        7796 : }
     761             : 
     762       94752 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
     763       94752 :   plumed_assert( !outputComponentExists( name, false ) );
     764       94752 :   plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
     765             : 
     766       94752 :   std::size_t num2=name.find_first_of("_");
     767       94752 :   if( num2!=std::string::npos ) {
     768         373 :     char uu = '_';
     769         373 :     plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
     770         373 :     plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
     771             :   }
     772             : 
     773       94752 :   ckey.insert( std::pair<std::string,std::string>(name,key) );
     774       94752 :   cdocs.insert( std::pair<std::string,std::string>(name,descr) );
     775       94752 :   cnames.push_back(name);
     776       94752 : }
     777             : 
     778      129139 : bool Keywords::outputComponentExists( const std::string& name, const bool& custom ) const {
     779      129139 :   if( custom && cstring.find("customize")!=std::string::npos ) {
     780             :     return true;
     781             :   }
     782             : 
     783             :   std::string sname;
     784      125678 :   std::size_t num=name.find_first_of("-");
     785      125678 :   std::size_t num2=name.find_last_of("_");
     786             : 
     787      125678 :   if( num2!=std::string::npos ) {
     788        4088 :     sname=name.substr(num2);
     789      123634 :   } else if( num!=std::string::npos ) {
     790       52380 :     sname=name.substr(0,num);
     791             :   } else {
     792             :     sname=name;
     793             :   }
     794             : 
     795     1187643 :   for(unsigned i=0; i<cnames.size(); ++i) {
     796     1092891 :     if( sname==cnames[i] ) {
     797             :       return true;
     798             :     }
     799             :   }
     800             :   return false;
     801             : }
     802             : 
     803        9046 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
     804        9046 :   return ckey.find(name)->second;
     805             : }
     806             : 
     807        4796 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
     808        4796 :   if( cstring.find("customized")!=std::string::npos ) {
     809         112 :     return "the label of this action is set by user in the input. See documentation above.";
     810             :   }
     811             : 
     812             :   bool found=false;
     813       84276 :   for(unsigned i=0; i<cnames.size(); ++i) {
     814       79592 :     if( name==cnames[i] ) {
     815             :       found=true;
     816             :     }
     817             :   }
     818        4684 :   if( !found ) {
     819           0 :     plumed_merror("could not find output component named " + name );
     820             :   }
     821        4684 :   return cdocs.find(name)->second;
     822             : }
     823             : 
     824           0 : void Keywords::removeComponent( const std::string& name ) {
     825             :   bool found=false;
     826             : 
     827             :   while(true) {
     828             :     unsigned j;
     829           0 :     for(j=0; j<cnames.size(); j++)
     830           0 :       if(cnames[j]==name) {
     831             :         break;
     832             :       }
     833           0 :     if(j<cnames.size()) {
     834           0 :       cnames.erase(cnames.begin()+j);
     835             :       found=true;
     836             :     } else {
     837             :       break;
     838             :     }
     839           0 :   }
     840             :   // Delete documentation, type and so on from the description
     841             :   cdocs.erase(name);
     842             :   ckey.erase(name);
     843           0 :   plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
     844           0 : }
     845             : 
     846         444 : std::vector<std::string> Keywords::getOutputComponents() const {
     847         444 :   return cnames;
     848             : }
     849             : 
     850        8990 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
     851        8990 :   plumed_assert( exists( key ) );
     852        8990 :   return documentation.find(key)->second;
     853             : }
     854             : 
     855             : }

Generated by: LCOV version 1.16