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

Generated by: LCOV version 1.16