LCOV - code coverage report
Current view: top level - tools - Keywords.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 223 418 53.3 %
Date: 2024-10-11 08:09:47 Functions: 27 37 73.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             : 
      27             : namespace PLMD {
      28             : 
      29      915339 : Keywords::KeyType::KeyType( const std::string& type ) {
      30      915339 :   if( type=="compulsory" ) {
      31      242031 :     style=compulsory;
      32      673308 :   } else if( type=="flag" ) {
      33      186749 :     style=flag;
      34      486559 :   } else if( type=="optional" ) {
      35      252231 :     style=optional;
      36      234328 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      37      121214 :     style=atoms;
      38      113114 :   } else if( type=="hidden" ) {
      39       54073 :     style=hidden;
      40       59041 :   } else if( type=="vessel" ) {
      41       59041 :     style=vessel;
      42             :   } else {
      43           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      44             :   }
      45      915339 : }
      46             : 
      47        3912 : void Keywords::KeyType::setStyle( const std::string& type ) {
      48        3912 :   if( type=="compulsory" ) {
      49          80 :     style=compulsory;
      50        3832 :   } else if( type=="flag" ) {
      51           0 :     style=flag;
      52        3832 :   } else if( type=="optional" ) {
      53          25 :     style=optional;
      54        3807 :   } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
      55         205 :     style=atoms;
      56        3602 :   } else if( type=="hidden" ) {
      57         129 :     style=hidden;
      58        3473 :   } else if( type=="vessel" ) {
      59        3473 :     style=vessel;
      60             :   } else {
      61           0 :     plumed_massert(false,"invalid keyword specifier " + type);
      62             :   }
      63        3912 : }
      64             : 
      65         682 : void Keywords::add( const Keywords& newkeys ) {
      66         682 :   newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs  );
      67         682 : }
      68             : 
      69         682 : 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,
      70             :                          std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums,
      71             :                          std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck,
      72             :                          std::map<std::string,std::string>& cd ) const {
      73         682 :   for(unsigned i=0; i<keys.size(); ++i) {
      74           0 :     std::string thiskey=keys[i];
      75           0 :     for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
      76           0 :     for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
      77           0 :     kk.push_back( thiskey );
      78           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
      79           0 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
      80           0 :     if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
      81           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
      82           0 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
      83           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
      84           0 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
      85           0 :     if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
      86           0 :     if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
      87             :   }
      88       12958 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
      89       12276 :     std::string thiskey=reserved_keys[i];
      90      108072 :     for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
      91      170280 :     for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
      92       12276 :     rk.push_back( thiskey );
      93           0 :     plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
      94       12276 :     tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
      95       12276 :     if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
      96           0 :     plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
      97       12276 :     am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
      98           0 :     plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
      99       24552 :     docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
     100           0 :     if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
     101           0 :     if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
     102             :   }
     103       12958 :   for(unsigned i=0; i<cnames.size(); ++i) {
     104       12276 :     std::string thisnam=cnames[i];
     105      116622 :     for(unsigned j=0; j<cnam.size(); ++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
     106       12276 :     cnam.push_back( thisnam );
     107           0 :     plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
     108       24552 :     ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
     109           0 :     plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
     110       24552 :     cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
     111             :   }
     112         682 : }
     113             : 
     114      112849 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
     115      112849 :   plumed_assert( !exists(k) && !reserved(k) );
     116      112849 :   std::string fd, lowkey=k;
     117             :   // Convert to lower case
     118      972044 :   std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
     119             : // Remove any underscore characters
     120             :   for(unsigned i=0;; ++i) {
     121      154817 :     std::size_t num=lowkey.find_first_of("_");
     122      154817 :     if( num==std::string::npos ) break;
     123       41968 :     lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
     124       41968 :   }
     125      112849 :   if( t=="vessel" ) {
     126      118082 :     fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
     127      111136 :     if(d.find("flag")==std::string::npos) fd += ".  You can use multiple instances of this keyword i.e. " +
     128      104190 :           k +"1, " + k + "2, " + k + "3...  The corresponding values are then "
     129      104190 :           "referenced using <em>label</em>."+ lowkey +"-1,  <em>label</em>." + lowkey +
     130      104190 :           "-2,  <em>label</em>." + lowkey + "-3...";
     131       59041 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     132      118082 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
     133       53808 :   } else if( t=="numbered" ) {
     134        5994 :     fd = d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     135        2997 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     136        5994 :     types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
     137             :   } else {
     138             :     fd = d;
     139       50811 :     if( t=="atoms" && isaction ) fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     140       50811 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     141      101622 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     142       52086 :     if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
     143             :   }
     144      225698 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     145      112849 :   reserved_keys.push_back(k);
     146      112849 : }
     147             : 
     148        1953 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
     149        1953 :   plumed_assert( !exists(k) && !reserved(k) );
     150             :   std::string defstr;
     151        1953 :   if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; }
     152        3906 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     153       24266 :   std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
     154        1953 :   fd=defstr + d;
     155        3906 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     156        1953 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     157           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     158        1953 :   reserved_keys.push_back(k);
     159        1953 : }
     160             : 
     161       14436 : void Keywords::use( const std::string & k ) {
     162       14436 :   plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
     163      179967 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     164      165531 :     if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] );
     165             :   }
     166       14436 : }
     167             : 
     168        3912 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
     169        3912 :   plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
     170        3912 :   (types.find(k)->second).setStyle(style);
     171        3912 :   if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true;
     172        4117 :   if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,style) );
     173        3912 : }
     174             : 
     175      426605 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
     176     1279815 :   plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
     177             :   std::string fd;
     178      426605 :   if( t=="numbered" ) {
     179        2742 :     fd=d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
     180        1371 :     allowmultiple.insert( std::pair<std::string,bool>(k,true) );
     181        2742 :     types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
     182             :   } else {
     183             :     fd=d;
     184      425234 :     allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     185      850468 :     types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
     186      545173 :     if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
     187             :   }
     188      442649 :   if( t=="atoms" && isaction ) fd = d + ".  For more information on how to specify lists of atoms see \\ref Group";
     189      853210 :   documentation.insert( std::pair<std::string,std::string>(k,fd) );
     190      426605 :   keys.push_back(k);
     191      426605 : }
     192             : 
     193      189136 : void Keywords::add( const std::string & t, const std::string & k, const std::string &  def, const std::string & d ) {
     194      378272 :   plumed_assert( !exists(k) && !reserved(k) &&  (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
     195      189136 :   types.insert(  std::pair<std::string,KeyType>(k, KeyType(t)) );
     196      378272 :   documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
     197      189136 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     198      378272 :   numdefs.insert( std::pair<std::string,std::string>(k,def) );
     199      189136 :   keys.push_back(k);
     200      189136 : }
     201             : 
     202      184796 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
     203      184796 :   plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
     204      184796 :   std::string defstr; plumed_massert( !def, "the second argument to addFlag must be false " + k );
     205             :   defstr="( default=off ) ";
     206      369592 :   types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
     207      369592 :   documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
     208      184796 :   allowmultiple.insert( std::pair<std::string,bool>(k,false) );
     209           0 :   booldefs.insert( std::pair<std::string,bool>(k,def) );
     210      184796 :   keys.push_back(k);
     211      184796 : }
     212             : 
     213        1438 : void Keywords::remove( const std::string & k ) {
     214             :   bool found=false; unsigned j=0, n=0;
     215             : 
     216             :   while(true) {
     217       14291 :     for(j=0; j<keys.size(); j++) if(keys[j]==k)break;
     218       33184 :     for(n=0; n<reserved_keys.size(); n++) if(reserved_keys[n]==k)break;
     219        2876 :     if(j<keys.size()) {
     220        1353 :       keys.erase(keys.begin()+j);
     221             :       found=true;
     222        1523 :     } else if(n<reserved_keys.size()) {
     223          85 :       reserved_keys.erase(reserved_keys.begin()+n);
     224             :       found=true;
     225             :     } else break;
     226             :   }
     227             :   // Delete documentation, type and so on from the description
     228             :   types.erase(k); documentation.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k);
     229        1438 :   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
     230        1438 : }
     231             : 
     232        8070 : bool Keywords::numbered( const std::string & k ) const {
     233       16140 :   if( style( k,"atoms") ) return true;
     234           0 :   plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
     235        6094 :   return allowmultiple.find(k)->second;
     236             : }
     237             : 
     238      727474 : bool Keywords::style( const std::string & k, const std::string & t ) const {
     239           0 :   plumed_massert( types.count(k), "Did not find keyword " + k );
     240             : 
     241      727474 :   if( (types.find(k)->second).toString()==t ) return true;
     242             :   return false;
     243             : }
     244             : 
     245      783765 : unsigned Keywords::size() const {
     246      783765 :   return keys.size();
     247             : }
     248             : 
     249        9262 : std::string Keywords::getKeyword( const unsigned i ) const {
     250        9262 :   plumed_assert( i<size() );
     251        9262 :   return keys[i];
     252             : }
     253             : 
     254     1160571 : bool Keywords::exists( const std::string & k ) const {
     255    12056720 :   for(unsigned i=0; i<keys.size(); ++i) {
     256    11096368 :     if( keys[i]==k ) return true;
     257             :   }
     258             :   return false;
     259             : }
     260             : 
     261      933368 : bool Keywords::reserved( const std::string & k ) const {
     262     2158698 :   for(unsigned i=0; i<reserved_keys.size(); ++i) {
     263     1243359 :     if( reserved_keys[i]==k ) return true;
     264             :   }
     265             :   return false;
     266             : }
     267             : 
     268           0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
     269             :   unsigned nkeys=0;
     270             :   std::printf("%s",actionname.c_str());
     271           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     272           0 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     273             :   }
     274           0 :   if( nkeys>0 ) {
     275           0 :     std::string prevtag="start";
     276           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     277           0 :       if( (types.find(keys[i])->second).isAtomList() ) {
     278           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     279           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break;
     280           0 :         if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) std::printf(" %s=<residue selection>", keys[i].c_str() );
     281             :         else std::printf(" %s=<atom selection>", keys[i].c_str() );
     282           0 :         prevtag=atomtags.find(keys[i])->second;
     283             :       }
     284             :     }
     285             :   }
     286             :   nkeys=0;
     287           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     288           0 :     if ( include_optional || \
     289           0 :          (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     290             :   }
     291           0 :   if( nkeys>0 ) {
     292           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     293           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) {
     294             :         std::string def;
     295           0 :         if( getDefaultValue( keys[i], def) ) {
     296             :           std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
     297             :         } else {
     298             :           std::printf(" %s=    ", keys[i].c_str() );
     299             :         }
     300           0 :       } else if (include_optional) {
     301             :         // TG no defaults for optional keywords?
     302             :         std::printf(" [%s]", keys[i].c_str() );
     303             :       }
     304             :     }
     305             :   }
     306             :   std::printf("\n");
     307           0 : }
     308             : 
     309         287 : void Keywords::print_vim() const {
     310        4426 :   for(unsigned i=0; i<keys.size(); ++i) {
     311        4139 :     if( (types.find(keys[i])->second).isFlag() ) {
     312             :       std::printf( ",flag:%s", keys[i].c_str() );
     313             :     } else {
     314        3209 :       if( allowmultiple.find(keys[i])->second ) std::printf(",numbered:%s",keys[i].c_str() );
     315             :       else std::printf(",option:%s",keys[i].c_str() );
     316             :     }
     317             :   }
     318         287 :   std::fprintf(stdout,"\n");
     319         287 :   print(stdout);
     320         287 : }
     321             : 
     322           0 : void Keywords::print_html() const {
     323             : 
     324             : // This is the part that outputs the details of the components
     325           0 :   if( cnames.size()>0 ) {
     326             :     unsigned ndef=0;
     327           0 :     for(unsigned i=0; i<cnames.size(); ++i) {
     328           0 :       if(ckey.find(cnames[i])->second=="default") ndef++;
     329             :     }
     330             : 
     331           0 :     if( ndef>0 ) {
     332           0 :       std::cout<<"\\par Description of components\n\n";
     333           0 :       std::cout<<cstring<<"\n\n";
     334           0 :       std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     335             :       std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
     336             :       unsigned nndef=0;
     337           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     338             :         //plumed_assert( ckey.find(cnames[i])->second=="default" );
     339           0 :         if( ckey.find(cnames[i])->second!="default" ) { nndef++; continue; }
     340             :         std::printf("<tr>\n");
     341             :         std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
     342             :         std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     343             :         std::printf("</tr>\n");
     344             :       }
     345           0 :       std::cout<<"</table>\n\n";
     346           0 :       if( nndef>0 ) {
     347           0 :         std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
     348           0 :         std::cout<<"\n\n";
     349           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     350             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     351           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     352           0 :           if( ckey.find(cnames[i])->second!="default") {
     353             :             std::printf("<tr>\n");
     354             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     355             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     356             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     357             :             std::printf("</tr>\n");
     358             :           }
     359             :         }
     360           0 :         std::cout<<"</table>\n\n";
     361             :       }
     362             :     } else {
     363             :       unsigned nregs=0;
     364           0 :       for(unsigned i=0; i<cnames.size(); ++i) {
     365           0 :         if( exists(ckey.find(cnames[i])->second) ) nregs++;
     366             :       }
     367           0 :       if( nregs>0 ) {
     368           0 :         std::cout<<"\\par Description of components\n\n";
     369           0 :         std::cout<<cstring<<"\n\n";
     370           0 :         std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     371             :         std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
     372           0 :         for(unsigned i=0; i<cnames.size(); ++i) {
     373           0 :           if( exists(ckey.find(cnames[i])->second) ) {
     374             :             std::printf("<tr>\n");
     375             :             std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
     376             :                         cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
     377             :             std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
     378             :             std::printf("</tr>\n");
     379             :           }
     380             :         }
     381           0 :         std::cout<<"</table>\n\n";
     382             :       }
     383             :     }
     384             :   }
     385             : 
     386             :   unsigned nkeys=0;
     387           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     388           0 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     389             :   }
     390           0 :   if( nkeys>0 ) {
     391           0 :     if(isaction && isatoms) std::cout<<"\\par The atoms involved can be specified using\n\n";
     392           0 :     else if(isaction) std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
     393           0 :     else std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
     394           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     395           0 :     std::string prevtag="start"; unsigned counter=0;
     396           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     397           0 :       if ( (types.find(keys[i])->second).isAtomList() ) {
     398           0 :         plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
     399           0 :         if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
     400           0 :           std::cout<<"</table>\n\n";
     401           0 :           if( isatoms ) std::cout<<"\\par Or alternatively by using\n\n";
     402           0 :           else if( counter==0 ) { std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n"; counter++; }
     403           0 :           else std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
     404           0 :           std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     405             :         }
     406           0 :         print_html_item( keys[i] );
     407           0 :         prevtag=atomtags.find(keys[i])->second;
     408             :       }
     409             :     }
     410           0 :     std::cout<<"</table>\n\n";
     411             :   }
     412             :   nkeys=0;
     413           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     414           0 :     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     415             :   }
     416           0 :   if( nkeys>0 ) {
     417           0 :     if(isaction) std::cout<< "\\par Compulsory keywords\n\n";
     418           0 :     else std::cout<<"\\par The following must be present\n\n";
     419           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     420           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     421           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] );
     422             :     }
     423           0 :     std::cout<<"</table>\n\n";
     424             :   }
     425             :   nkeys=0;
     426           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     427           0 :     if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     428             :   }
     429           0 :   if( nkeys>0 ) {
     430           0 :     if(isaction) std::cout<<"\\par Options\n\n";
     431           0 :     else std::cout<<"\\par The following options are available\n\n";
     432           0 :     std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
     433           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     434           0 :       if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] );
     435             :     }
     436           0 :     std::cout<<"\n";
     437             :   }
     438             :   nkeys=0;
     439           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     440           0 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     441             :   }
     442           0 :   if( nkeys>0 ) {
     443           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     444           0 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] );
     445             :     }
     446             :   }
     447           0 :   std::cout<<"</table>\n\n";
     448           0 : }
     449             : 
     450           0 : void Keywords::print_spelling() const {
     451           0 :   for(unsigned i=0; i<keys.size(); ++i) std::printf("%s\n", keys[i].c_str() );
     452           0 :   for(unsigned i=0; i<cnames.size(); ++i) std::printf("%s\n",cnames[i].c_str() );
     453           0 : }
     454             : 
     455         287 : void Keywords::print( FILE* out ) const {
     456             :   unsigned nkeys=0;
     457        4426 :   for(unsigned i=0; i<keys.size(); ++i) {
     458        4139 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     459             :   }
     460         287 :   if( nkeys>0 ) {
     461             :     std::fprintf(out,"The input trajectory can be in any of the following formats: \n\n");
     462        2386 :     for(unsigned i=0; i<keys.size(); ++i) {
     463        2260 :       if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], out );
     464             :     }
     465             :   }
     466             :   nkeys=0;
     467        4426 :   for(unsigned i=0; i<keys.size(); ++i) {
     468        4139 :     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     469             :   }
     470             :   unsigned ncompulsory=nkeys;
     471         287 :   if( nkeys>0 ) {
     472             :     std::fprintf(out,"\nThe following arguments are compulsory: \n\n");
     473        3616 :     for(unsigned i=0; i<keys.size(); ++i) {
     474        3388 :       if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
     475             :     }
     476             :   }
     477             :   nkeys=0;
     478        4426 :   for(unsigned i=0; i<keys.size(); ++i) {
     479        4139 :     if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
     480             :   }
     481         287 :   if( nkeys>0 ) {
     482         253 :     if(ncompulsory>0) std::fprintf( out,"\nIn addition you may use the following options: \n\n");
     483             :     else std::fprintf( out,"\nThe following options are available\n\n");
     484        4211 :     for(unsigned i=0; i<keys.size(); ++i) {
     485        3958 :       if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
     486             :     }
     487             :   }
     488             :   nkeys=0;
     489        4426 :   for(unsigned i=0; i<keys.size(); ++i) {
     490        7427 :     if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
     491             :   }
     492         287 :   if( nkeys>0 ) {
     493        3855 :     for(unsigned i=0; i<keys.size(); ++i) {
     494        6425 :       if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) printKeyword( keys[i], out );   //log.printKeyword( keys[i], documentation[i] );
     495             :     }
     496             :     std::fprintf(out,"\n");
     497             :   }
     498         287 : }
     499             : 
     500        3412 : void Keywords::printKeyword( const std::string& key, FILE* out ) const {
     501        3412 :   bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
     502        3412 :   std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
     503             :   std::fprintf(out,"%23s - ", key.c_str() );
     504        3412 :   unsigned nl=0; std::string blank=" ";
     505       72717 :   for(unsigned i=0; i<w.size(); ++i) {
     506       69598 :     nl+=w[i].length() + 1;
     507       69598 :     if( nl>60 ) {
     508             :       std::fprintf(out,"\n%23s   %s ", blank.c_str(), w[i].c_str() ); nl=0;
     509             :     } else {
     510             :       std::fprintf(out,"%s ", w[i].c_str() );
     511             :     }
     512       69598 :     if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
     513             :   }
     514             :   std::fprintf(out,"\n");
     515        3412 : }
     516             : 
     517           0 : void Keywords::print( Log& log ) const {
     518             :   unsigned nkeys=0;
     519           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     520           0 :     if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
     521             :   }
     522           0 :   if (nkeys>0 ) {
     523           0 :     log.printf( "The input for this keyword can be specified using one of the following \n\n");
     524           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     525           0 :       if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], log );   //log.printKeyword( keys[i], documentation[i] );
     526             :     }
     527             :   }
     528             :   nkeys=0;
     529           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     530           0 :     if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
     531             :   }
     532           0 :   if( nkeys>0 ) {
     533           0 :     log.printf( "\n The compulsory keywords for this action are: \n\n");
     534           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     535           0 :       if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], log );   //log.printKeyword( keys[i], documentation[i] );
     536             :     }
     537             :   }
     538             :   nkeys=0;
     539           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     540           0 :     if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
     541             :   }
     542           0 :   if( nkeys>0 ) {
     543           0 :     log.printf( "\n The following options are available: \n\n");
     544           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     545           0 :       if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], log );   //log.printKeyword( keys[i], documentation[i] );
     546             :     }
     547           0 :     log.printf("\n");
     548             :   }
     549             :   nkeys=0;
     550           0 :   for(unsigned i=0; i<keys.size(); ++i) {
     551           0 :     if ( (types.find(keys[i])->second).isOptional() ) nkeys++;
     552             :   }
     553           0 :   if( nkeys>0 ) {
     554           0 :     for(unsigned i=0; i<keys.size(); ++i) {
     555           0 :       if ( (types.find(keys[i])->second).isOptional() ) printKeyword( keys[i], log );   //log.printKeyword( keys[i], documentation[i] );
     556             :     }
     557           0 :     log.printf("\n");
     558             :   }
     559           0 : }
     560             : 
     561           0 : void Keywords::printKeyword( const std::string& key, Log& log ) const {
     562           0 :   bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
     563           0 :   std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
     564           0 :   log.printf("%23s - ", key.c_str() );
     565           0 :   unsigned nl=0; std::string blank=" ";
     566           0 :   for(unsigned i=0; i<w.size(); ++i) {
     567           0 :     nl+=w[i].length() + 1;
     568           0 :     if( nl>60 ) {
     569           0 :       log.printf("\n%23s   %s ", blank.c_str(), w[i].c_str() ); nl=0;
     570             :     } else {
     571           0 :       log.printf("%s ", w[i].c_str() );
     572             :     }
     573           0 :     if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
     574             :   }
     575           0 :   log.printf("\n");
     576           0 : }
     577             : 
     578           0 : std::string Keywords::getTooltip( const std::string& name ) const {
     579           0 :   std::size_t dd=name.find_first_of("0123456789"); std::string kname=name.substr(0,dd);
     580           0 :   if( !exists(kname) ) return "<b> could not find this keyword </b>";
     581           0 :   std::string mystring, docstr = documentation.find(kname)->second;
     582           0 :   if( types.find(kname)->second.isCompulsory() ) {
     583             :     mystring += "<b>compulsory keyword ";
     584           0 :     if( docstr.find("default")!=std::string::npos ) {
     585           0 :       std::size_t bra = docstr.find_first_of(")"); mystring += docstr.substr(0,bra+1); docstr = docstr.substr(bra+1);
     586             :     }
     587             :     mystring += "</b>\n";
     588             :   }
     589           0 :   std::vector<std::string> w=Tools::getWords( docstr ); unsigned nl=0;
     590           0 :   for(unsigned i=0; i<w.size(); ++i) {
     591           0 :     nl+=w[i].length() + 1;
     592           0 :     if( nl>80 ) { mystring += w[i] + "\n"; nl=0; }
     593           0 :     else { mystring += w[i] + " "; }
     594           0 :     if( w[i].find(".")!=std::string::npos ) break; // Only write up the the first dot
     595             :   }
     596             :   return mystring;
     597           0 : }
     598             : 
     599           0 : void Keywords::print_html_item( const std::string& key ) const {
     600             :   std::printf("<tr>\n");
     601             :   std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
     602             :   std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
     603             :   std::printf("</tr>\n");
     604           0 : }
     605             : 
     606      368197 : std::string Keywords::get( const unsigned k ) const {
     607      368197 :   plumed_assert( k<size() );
     608      368197 :   return keys[k];
     609             : }
     610             : 
     611       36577 : bool Keywords::getLogicalDefault( std::string key, bool& def ) const {
     612       36577 :   if( booldefs.find(key)!=booldefs.end() ) {
     613       36577 :     def=booldefs.find(key)->second;
     614       36577 :     return true;
     615             :   } else {
     616             :     return false;
     617             :   }
     618             : }
     619             : 
     620       10262 : bool Keywords::getDefaultValue( std::string key, std::string& def ) const {
     621       20702 :   plumed_assert( style(key,"compulsory") || style(key,"hidden") );
     622             : 
     623       10262 :   if( numdefs.find(key)!=numdefs.end() ) {
     624        5042 :     def=numdefs.find(key)->second;
     625        5042 :     return true;
     626             :   } else {
     627             :     return false;
     628             :   }
     629             : }
     630             : 
     631           0 : void Keywords::destroyData() {
     632           0 :   keys.clear(); reserved_keys.clear(); types.clear();
     633             :   allowmultiple.clear(); documentation.clear();
     634             :   booldefs.clear(); numdefs.clear(); atomtags.clear();
     635             :   ckey.clear(); cdocs.clear(); ckey.clear();
     636           0 : }
     637             : 
     638        6275 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
     639        6275 :   cstring = instr;
     640        6275 : }
     641             : 
     642       72441 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
     643       72441 :   plumed_assert( !outputComponentExists( name, false ) );
     644       72441 :   plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
     645             : 
     646       72441 :   std::size_t num2=name.find_first_of("_");
     647       72441 :   if( num2!=std::string::npos ) {
     648         298 :     char uu = '_'; plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
     649         298 :     plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
     650             :   }
     651             : 
     652      144882 :   ckey.insert( std::pair<std::string,std::string>(name,key) );
     653      144882 :   cdocs.insert( std::pair<std::string,std::string>(name,descr) );
     654       72441 :   cnames.push_back(name);
     655       72441 : }
     656             : 
     657      106111 : bool Keywords::outputComponentExists( const std::string& name, const bool& custom ) const {
     658      106111 :   if( custom && cstring.find("customize")!=std::string::npos ) return true;
     659             : 
     660             :   std::string sname;
     661      102652 :   std::size_t num=name.find_first_of("-");
     662      102652 :   std::size_t num2=name.find_last_of("_");
     663             : 
     664      104570 :   if( num2!=std::string::npos ) sname=name.substr(num2);
     665      126538 :   else if( num!=std::string::npos ) sname=name.substr(0,num);
     666             :   else sname=name;
     667             : 
     668      976400 :   for(unsigned i=0; i<cnames.size(); ++i) {
     669      903959 :     if( sname==cnames[i] ) return true;
     670             :   }
     671             :   return false;
     672             : }
     673             : 
     674           0 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
     675           0 :   if( cstring.find("customized")!=std::string::npos ) return "the label of this action is set by user in the input. See documentation above.";
     676             : 
     677             :   bool found=false;
     678           0 :   for(unsigned i=0; i<cnames.size(); ++i) {
     679           0 :     if( name==cnames[i] ) found=true;
     680             :   }
     681           0 :   if( !found ) plumed_merror("could not find output component named " + name );
     682           0 :   return cdocs.find(name)->second;
     683             : }
     684             : 
     685           0 : void Keywords::removeComponent( const std::string& name ) {
     686             :   bool found=false;
     687             : 
     688             :   while(true) {
     689             :     unsigned j;
     690           0 :     for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
     691           0 :     if(j<cnames.size()) {
     692           0 :       cnames.erase(cnames.begin()+j);
     693             :       found=true;
     694             :     } else break;
     695           0 :   }
     696             :   // Delete documentation, type and so on from the description
     697             :   cdocs.erase(name); ckey.erase(name);
     698           0 :   plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
     699           0 : }
     700             : 
     701             : }

Generated by: LCOV version 1.15