LCOV - code coverage report
Current view: top level - core - ActionShortcut.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 146 156 93.6 %
Date: 2024-10-18 13:59:31 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2018-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 "ActionShortcut.h"
      23             : #include "PlumedMain.h"
      24             : #include "ActionWithValue.h"
      25             : #include "ActionRegister.h"
      26             : #include "ActionSet.h"
      27             : 
      28             : namespace PLMD {
      29             : 
      30       18476 : void ActionShortcut::registerKeywords( Keywords& keys ) {
      31       18476 :   Action::registerKeywords( keys );
      32       36952 :   keys.add("hidden","IS_SHORTCUT","hidden keyword to tell if actions are shortcuts so that example generator can provide expansions of shortcuts");
      33       36952 :   keys.add("hidden","HAS_VALUES","this is used in json output to determine those actions that have values");
      34       18476 : }
      35             : 
      36         233 : void ActionShortcut::readShortcutKeywords( const Keywords& keys, std::map<std::string,std::string>& keymap ) {
      37        2786 :   for(unsigned i=0; i<keys.size(); ++i) {
      38        2553 :     std::string t, keyname = keys.get(i);
      39        3481 :     if( keys.style( keyname, "optional") || keys.style( keyname, "compulsory") ) {
      40        1625 :       parse(keyname,t);
      41        1625 :       if( t.length()>0 ) {
      42         102 :         keymap.insert(std::pair<std::string,std::string>(keyname,t));
      43        1574 :       } else if( keys.numbered( keyname ) ) {
      44         659 :         for(unsigned i=1;; ++i) {
      45         674 :           std::string istr; Tools::convert( i, istr );
      46         674 :           if( !parseNumbered(keyname,i,t) ) break ;
      47          30 :           keymap.insert(std::pair<std::string,std::string>(keyname + istr,t));
      48          15 :         }
      49             :       }
      50        1856 :     } else if( keys.style( keyname, "flag") ) {
      51         928 :       bool found=false; parseFlag(keyname,found);
      52        1032 :       if( found ) keymap.insert(std::pair<std::string,std::string>(keyname,""));
      53           0 :     } else plumed_merror("shortcut keywords should be optional, compulsory or flags");
      54             :   }
      55         233 : }
      56             : 
      57       16112 : ActionShortcut::ActionShortcut(const ActionOptions&ao):
      58             :   Action(ao),
      59       16112 :   shortcutlabel(label)
      60             : {
      61       16112 :   std::string s; Tools::convert(plumed.getActionSet().size(),s);
      62       16112 :   if( shortcutlabel==("@" + s) ) {
      63           0 :     std::string t; Tools::convert(plumed.getActionSet().size(),t);
      64           0 :     shortcutlabel="@" + t;
      65       32224 :   } else label = ("@s" + s);
      66       16112 : }
      67             : 
      68       21703 : void ActionShortcut::readInputLine( const std::string& input, bool saveline ) {
      69       21703 :   std::vector<std::string> words=Tools::getWords(input); Tools::interpretLabel(words);
      70             :   // Check if this action name has been registered
      71       21703 :   bool founds=false, found = std::find(keywords.neededActions.begin(), keywords.neededActions.end(), words[0] )!=keywords.neededActions.end();
      72             :   // Check if we are just calling something like SUM_VECTOR using just SUM.
      73       36560 :   if( !found && words[0].find(getName())!=std::string::npos ) {
      74       19631 :     for(unsigned j=0 ; j<keywords.actionNameSuffixes.size(); ++j) {
      75       19631 :       if( (getName() + keywords.actionNameSuffixes[j])==words[0] ) { found=true; break; }
      76             :     }
      77             :     founds=true;
      78             :   }
      79       21703 :   if( found ) {
      80       21703 :     std::string f_input = input; if( !founds && saveline ) addToSavedInputLines( input );
      81       43406 :     if( keywords.exists("RESTART") ) {
      82           0 :       if( restart ) f_input += " RESTART=YES";
      83           0 :       if( !restart ) f_input += " RESTART=NO";
      84             :     }
      85       21703 :     plumed.readInputLine( f_input );
      86       21688 :     if( !founds ) {
      87             :       ActionWithValue* av=NULL;
      88       11758 :       for(auto pp=plumed.getActionSet().rbegin(); pp!=plumed.getActionSet().rend(); ++pp) {
      89       11758 :         av = pp->get()->castToActionWithValue();
      90       11758 :         if( !av ) continue ;
      91        6846 :         if( std::find(savedOutputs.begin(), savedOutputs.end(), av->getLabel() )!=savedOutputs.end() ) av=NULL;
      92             :         break;
      93             :       }
      94        6840 :       if( av ) {
      95        6840 :         std::string av_label = av->getLabel();
      96        6840 :         if( av_label == getShortcutLabel() && av->getNumberOfComponents()==1 ) {
      97        1163 :           savedOutputs.push_back( av_label );
      98        2326 :           plumed_massert( keywords.componentHasCorrectType(".#!value", (av->copyOutput(0))->getRank(), (av->copyOutput(0))->hasDerivatives() ), "documentation for type of value is incorrect");
      99             :         } else {
     100       38840 :           for(unsigned i=0; i<keywords.cnames.size(); ++i) {
     101       33163 :             if( av_label == getShortcutLabel() + "_" + keywords.cnames[i] ) {
     102         297 :               savedOutputs.push_back( av_label );
     103         297 :               plumed_massert( keywords.componentHasCorrectType(keywords.cnames[i], (av->copyOutput(0))->getRank(), (av->copyOutput(0))->hasDerivatives() ), "documentation for type of component " + keywords.cnames[i] + " is incorrect");
     104       65732 :             } else if( keywords.getOutputComponentFlag(keywords.cnames[i])!="default" ) {
     105       26935 :               std::string thisflag = keywords.getOutputComponentFlag(keywords.cnames[i]);
     106       54273 :               if( keywords.numbered(thisflag) && av_label.find(getShortcutLabel() + "_" + keywords.cnames[i])!=std::string::npos ) {
     107          30 :                 savedOutputs.push_back( av_label );
     108          30 :                 plumed_massert( keywords.componentHasCorrectType(keywords.cnames[i], (av->copyOutput(0))->getRank(), (av->copyOutput(0))->hasDerivatives() ), "documentation for type of component " + keywords.cnames[i] + " is incorrect");
     109             :               }
     110             :             }
     111             :           }
     112             :         }
     113             :       }
     114             :     } else {
     115       14842 :       ActionWithValue* av = plumed.getActionSet()[plumed.getActionSet().size()-1]->castToActionWithValue();
     116       14857 :       if( !av ) error("shortcut is using suffix but action created is not ActionWithValue");
     117       14842 :       Keywords thiskeys; actionRegister().getKeywords( av->getName(), thiskeys );
     118       29684 :       if( thiskeys.getDisplayName()!=getName() ) error("mismatch between display name of hidden action " + thiskeys.getDisplayName() + " and shortcut that creates it " + getName() );
     119       14842 :     }
     120           0 :   } else error("requirement for action " + words[0] + " should be registered in registerKeywords function for shortcut action using keys.useAction");
     121       21703 : }
     122             : 
     123           1 : void ActionShortcut::addCommentToShortcutOutput( const std::string& input ) {
     124           1 :   savedInputLines.push_back( input );
     125           1 : }
     126             : 
     127          37 : std::string ActionShortcut::getUpdateLimits() const {
     128          37 :   std::string f_input="";
     129          37 :   if( update_from!=std::numeric_limits<double>::max() ) {
     130           4 :     std::string ufrom; Tools::convert( update_from, ufrom ); f_input += " UPDATE_FROM=" + ufrom;
     131             :   }
     132          37 :   if( update_until!=std::numeric_limits<double>::max() ) {
     133           4 :     std::string util; Tools::convert( update_until, util ); f_input += " UPDATE_UNTIL=" + util;
     134             :   }
     135          37 :   return f_input;
     136             : }
     137             : 
     138        6561 : void ActionShortcut::addToSavedInputLines( const std::string& line ) {
     139        6561 :   std::vector<std::string> words = Tools::getWords(line); std::string actname;
     140        6561 :   if( words[0].find_first_of(":")!=std::string::npos) actname = words[1]; else actname = words[0];
     141        6561 :   if( !actionRegister().check(actname) ) error("found no action with name " + actname + " to create shortcut");
     142        6561 :   Keywords thiskeys; actionRegister().getKeywords( actname, thiskeys ); std::vector<std::string> numberedkeys;
     143       55070 :   for(unsigned i=0; i<thiskeys.size(); ++i ) {
     144       99923 :     if( thiskeys.numbered( thiskeys.getKeyword(i) ) ) numberedkeys.push_back( thiskeys.getKeyword(i) );
     145             :   }
     146        7879 :   if( numberedkeys.size()>0 && actname!="CONCATENATE" ) {
     147             :     std::string reducedline;
     148      167615 :     for(unsigned i=0; i<words.size(); ++i) {
     149             :       bool notnumbered=true;
     150      443346 :       for(unsigned j=0; j<numberedkeys.size(); ++j) {
     151      766400 :         if( words[i].find(numberedkeys[j])!=std::string::npos && words[i].substr(0,numberedkeys[j].length()+1)!=numberedkeys[j]+"=" ) { notnumbered=false; break; }
     152             :       }
     153      166471 :       if( notnumbered || words[i]==actname ) {
     154        4244 :         if( words[i].find(" ")!=std::string::npos) {
     155         104 :           std::size_t eq=words[i].find_first_of("=");
     156         208 :           reducedline += words[i].substr(0,eq) + "={" + words[i].substr(eq+1) + "} ";
     157        8280 :         } else reducedline += words[i] + " ";
     158             :       }
     159             :     }
     160        1144 :     std::vector<unsigned> ninstances( numberedkeys.size(), 0 );
     161        3875 :     for(unsigned j=0; j<numberedkeys.size(); ++j) {
     162        2731 :       for(unsigned i=1;; ++i) {
     163      164350 :         std::string num, val; Tools::convert(i, num);
     164      164350 :         bool found = Tools::parse(words, numberedkeys[j] + num, val );
     165      164350 :         if( !found) break ;
     166      162198 :         if( i<6 ) reducedline += numberedkeys[j] + num + "=" + val + " ";
     167      161040 :         else ninstances[j]++;
     168      161619 :       }
     169             :     }
     170             :     bool outputcomment=false;
     171        3753 :     for(unsigned j=0; j<numberedkeys.size(); ++j) {
     172        2683 :       if( ninstances[j]>0 ) { outputcomment=true; break; }
     173             :     }
     174        1144 :     if( outputcomment ) {
     175             :       reducedline += "    # Action input conctinues with ";
     176         258 :       for(unsigned  j=0; j<numberedkeys.size(); ++j) {
     177         184 :         std::string num; Tools::convert( ninstances[j], num );
     178         262 :         if( ninstances[j]>0 ) reducedline += num + " further " + numberedkeys[j] + "n keywords, ";
     179             :       }
     180          74 :       savedInputLines.push_back( reducedline );
     181        1070 :     } else savedInputLines.push_back( line );
     182        5417 :   } else savedInputLines.push_back( line );
     183       13122 : }
     184             : 
     185       74602 : const std::string & ActionShortcut::getShortcutLabel() const {
     186       74602 :   return shortcutlabel;
     187             : }
     188             : 
     189          18 : std::vector<std::string> ActionShortcut::getSavedInputLines() const {
     190          18 :   return savedInputLines;
     191             : }
     192             : 
     193          41 : std::vector<std::string> ActionShortcut::getSavedOutputs() const {
     194          41 :   return savedOutputs;
     195             : }
     196             : 
     197       14832 : std::string ActionShortcut::convertInputLineToString() {
     198             :   std::string output;
     199       66184 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     200       51352 :     if( (*p).find(" " )!=std::string::npos ) {
     201         405 :       std::size_t eq = (*p).find_first_of("=");
     202         810 :       output += " " + (*p).substr(0,eq) + "={" + (*p).substr(eq+1) + "}";
     203      101894 :     } else output += " " + (*p);
     204             :   }
     205       14832 :   line.resize(0); return output;
     206             : }
     207             : 
     208         613 : void ActionShortcut::interpretDataLabel( const std::string& mystr, Action* myuser, std::vector<Value*>& arg ) const {
     209         613 :   std::size_t dot=mystr.find_first_of('.'); std::string a=mystr.substr(0,dot); std::string name=mystr.substr(dot+1);
     210             :   // Retrieve the keywords for the shortcut
     211         613 :   Keywords skeys; actionRegister().getKeywords( getName(), skeys );
     212         613 :   std::vector<std::string> out_comps( skeys.getOutputComponents() );
     213             :   // Now get the output components
     214         613 :   if( name=="*" ) {
     215        2812 :     for(unsigned k=0; k<out_comps.size(); ++k) {
     216        2427 :       if( out_comps[k]=="" ) {
     217           0 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a );
     218           0 :         if( action ) {
     219           0 :           if( action->getNumberOfComponents()!=1 ) myuser->error("action named " + a + " has more than one component");
     220           0 :           arg.push_back(action->copyOutput(0));
     221             :         }
     222             :       } else {
     223        4854 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] );
     224        2427 :         if( action ) {
     225         234 :           if( action->getNumberOfComponents()!=1 ) myuser->error("action named " + a + "_" + out_comps[k] + " has more than one component");
     226         234 :           arg.push_back(action->copyOutput(0));
     227             :         } else {
     228        2193 :           for(unsigned j=1;; ++j) {
     229        4429 :             std::string numstr; Tools::convert( j, numstr );
     230        8858 :             ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] + "-" + numstr );
     231        4429 :             if( act ) {
     232         140 :               for(unsigned n=0; n<act->getNumberOfComponents(); ++n ) arg.push_back(act->copyOutput(n));
     233        4359 :             } else if( j>1 ) break;    // This ensures that * syntax works with moments, which normally start from 2
     234        2236 :           }
     235             :         }
     236             :       }
     237             :     }
     238             :   } else {
     239             :     // Check for an action that has action.component
     240         228 :     ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a );
     241         228 :     if( act && act->exists(mystr) ) return;
     242             :     // Get components that are actually actions
     243         231 :     for(unsigned k=0; k<out_comps.size(); ++k) {
     244         231 :       if(name.find_first_of(out_comps[k])!=std::string::npos ) {
     245         392 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + name );
     246         196 :         if( action ) arg.push_back(action->copyOutput(a+"_"+name));
     247             :         break;
     248             :       }
     249             :     }
     250             :   }
     251         613 : }
     252             : 
     253             : }

Generated by: LCOV version 1.16