LCOV - code coverage report
Current view: top level - core - ActionShortcut.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 157 177 88.7 %
Date: 2025-04-08 21:11:17 Functions: 11 13 84.6 %

          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       18194 : void ActionShortcut::registerKeywords( Keywords& keys ) {
      31       18194 :   Action::registerKeywords( keys );
      32       18194 :   keys.add("hidden","IS_SHORTCUT","hidden keyword to tell if actions are shortcuts so that example generator can provide expansions of shortcuts");
      33       18194 :   keys.add("hidden","HAS_VALUES","this is used in json output to determine those actions that have values");
      34       18194 : }
      35             : 
      36         233 : void ActionShortcut::readShortcutKeywords( const Keywords& keys, std::map<std::string,std::string>& keymap ) {
      37        2786 :   for (auto& keyname:keys.getKeys()) {
      38             :     std::string t;
      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             :           std::string istr;
      46         674 :           Tools::convert( i, istr );
      47         674 :           if( !parseNumbered(keyname,i,t) ) {
      48             :             break ;
      49             :           }
      50          30 :           keymap.insert(std::pair<std::string,std::string>(keyname + istr,t));
      51          15 :         }
      52             :       }
      53        1856 :     } else if( keys.style( keyname, "flag") ) {
      54         928 :       bool found=false;
      55         928 :       parseFlag(keyname,found);
      56         928 :       if( found ) {
      57         208 :         keymap.insert(std::pair<std::string,std::string>(keyname,""));
      58             :       }
      59             :     } else {
      60           0 :       plumed_merror("shortcut keywords should be optional, compulsory or flags");
      61             :     }
      62             :   }
      63         233 : }
      64             : 
      65       15836 : ActionShortcut::ActionShortcut(const ActionOptions&ao):
      66             :   Action(ao),
      67       15836 :   shortcutlabel(label) {
      68             :   std::string s;
      69       15836 :   Tools::convert(plumed.getActionSet().size(),s);
      70       15836 :   if( shortcutlabel==("@" + s) ) {
      71             :     std::string t;
      72           0 :     Tools::convert(plumed.getActionSet().size(),t);
      73           0 :     shortcutlabel="@" + t;
      74             :   } else {
      75       31672 :     label = ("@s" + s);
      76             :   }
      77       15836 : }
      78             : 
      79       21141 : void ActionShortcut::readInputLine( const std::string& input, bool saveline ) {
      80       21141 :   std::vector<std::string> words=Tools::getWords(input);
      81       21141 :   Tools::interpretLabel(words);
      82             :   // Check if this action name has been registered
      83             :   bool founds=false;
      84       21141 :   bool found = keywords.isActionNeeded(words[0]);
      85             :   // Check if we are just calling something like SUM_VECTOR using just SUM.
      86       21141 :   if( !found && words[0].find(getName())!=std::string::npos ) {
      87       14575 :     found =keywords.isActionSuffixed(words[0],getName());
      88             :     founds=true;
      89             :   }
      90       21141 :   if( found ) {
      91       21141 :     if( !founds && saveline ) {
      92        6566 :       addToSavedInputLines( input );
      93             :     }
      94       21141 :     if( keywords.exists("RESTART") ) {
      95           0 :       if( restart ) {
      96           0 :         words.push_back("RESTART=YES");
      97             :       }
      98           0 :       if( !restart ) {
      99           0 :         words.push_back("RESTART=NO");
     100             :       }
     101             :     }
     102       21141 :     plumed.readInputWords( words, false);
     103       21126 :     if( !founds ) {
     104             :       ActionWithValue* av=NULL;
     105       11191 :       for(auto pp=plumed.getActionSet().rbegin(); pp!=plumed.getActionSet().rend(); ++pp) {
     106       11191 :         av = pp->get()->castToActionWithValue();
     107       11191 :         if( !av ) {
     108             :           continue ;
     109             :         }
     110        6566 :         if( std::find(savedOutputs.begin(), savedOutputs.end(), av->getLabel() )!=savedOutputs.end() ) {
     111             :           av=NULL;
     112             :         }
     113             :         break;
     114             :       }
     115        6560 :       if( av ) {
     116        6560 :         std::string av_label = av->getLabel();
     117        6560 :         if( av_label == getShortcutLabel() && av->getNumberOfComponents()==1 ) {
     118        1169 :           savedOutputs.push_back( av_label );
     119        2338 :           plumed_massert( keywords.componentHasCorrectType(".#!value",
     120             :                           (av->copyOutput(0))->getRank(), (av->copyOutput(0))->hasDerivatives() ),
     121             :                           "documentation for type of value is incorrect");
     122             :         } else {
     123       34502 :           for(const auto& cname: keywords.getOutputComponents()) {
     124       29111 :             if( av_label == getShortcutLabel() + "_" + cname ) {
     125         303 :               savedOutputs.push_back( av_label );
     126         303 :               plumed_massert( keywords.componentHasCorrectType(cname,
     127             :                               (av->copyOutput(0))->getRank(),
     128             :                               (av->copyOutput(0))->hasDerivatives() ),
     129             :                               "documentation for type of component " + cname + " is incorrect");
     130       57616 :             } else if( keywords.getOutputComponentFlag(cname)!="default" ) {
     131       23139 :               std::string thisflag = keywords.getOutputComponentFlag(cname);
     132       46973 :               if( keywords.numbered(thisflag) && av_label.find(getShortcutLabel() + "_" + cname)!=std::string::npos ) {
     133          30 :                 savedOutputs.push_back( av_label );
     134          30 :                 plumed_massert( keywords.componentHasCorrectType(cname,
     135             :                                 (av->copyOutput(0))->getRank(),
     136             :                                 (av->copyOutput(0))->hasDerivatives() ),
     137             :                                 "documentation for type of component " + cname + " is incorrect");
     138             :               }
     139             :             }
     140             :           }
     141             :         }
     142             :       }
     143             :     } else {
     144       14560 :       ActionWithValue* av = plumed.getActionSet()[plumed.getActionSet().size()-1]->castToActionWithValue();
     145       14560 :       if( !av ) {
     146           0 :         error("shortcut is using suffix but action created is not ActionWithValue");
     147             :       }
     148       14560 :       Keywords thiskeys;
     149       14560 :       actionRegister().getKeywords( av->getName(), thiskeys );
     150       29120 :       if( thiskeys.getDisplayName()!=getName() ) {
     151           0 :         error("mismatch between display name of hidden action " + thiskeys.getDisplayName() + " and shortcut that creates it " + getName() );
     152             :       }
     153       14560 :     }
     154             :   } else {
     155           0 :     error("requirement for action " + words[0] + " should be registered in registerKeywords function for shortcut action using keys.useAction");
     156             :   }
     157       21141 : }
     158             : 
     159           0 : void ActionShortcut::addCommentToShortcutOutput( const std::string& input ) {
     160           0 :   savedInputLines.push_back( input );
     161           0 : }
     162             : 
     163          37 : std::string ActionShortcut::getUpdateLimits() const {
     164          37 :   std::string f_input="";
     165          37 :   if( update_from!=std::numeric_limits<double>::max() ) {
     166             :     std::string ufrom;
     167           2 :     Tools::convert( update_from, ufrom );
     168           4 :     f_input += " UPDATE_FROM=" + ufrom;
     169             :   }
     170          37 :   if( update_until!=std::numeric_limits<double>::max() ) {
     171             :     std::string util;
     172           2 :     Tools::convert( update_until, util );
     173           4 :     f_input += " UPDATE_UNTIL=" + util;
     174             :   }
     175          37 :   return f_input;
     176             : }
     177             : 
     178        6566 : void ActionShortcut::addToSavedInputLines( const std::string& line ) {
     179        6566 :   std::vector<std::string> words = Tools::getWords(line);
     180             :   std::string actname;
     181        6566 :   if( words[0].find_first_of(":")!=std::string::npos) {
     182             :     actname = words[1];
     183             :   } else {
     184             :     actname = words[0];
     185             :   }
     186        6566 :   if( !actionRegister().check(actname) ) {
     187           0 :     error("found no action with name " + actname + " to create shortcut");
     188             :   }
     189        6566 :   Keywords thiskeys;
     190        6566 :   actionRegister().getKeywords( actname, thiskeys );
     191             :   std::vector<std::string> numberedkeys;
     192       55354 :   for (auto& keyname: thiskeys.getKeys()) {
     193       48788 :     if( thiskeys.numbered( keyname ) ) {
     194        3050 :       numberedkeys.push_back( keyname );
     195             :     }
     196             :   }
     197        7883 :   if( numberedkeys.size()>0 && actname!="CONCATENATE" ) {
     198             :     std::string reducedline;
     199      195238 :     for(unsigned i=0; i<words.size(); ++i) {
     200             :       bool notnumbered=true;
     201      527144 :       for(unsigned j=0; j<numberedkeys.size(); ++j) {
     202      905416 :         if( words[i].find(numberedkeys[j])!=std::string::npos && words[i].substr(0,numberedkeys[j].length()+1)!=numberedkeys[j]+"=" ) {
     203             :           notnumbered=false;
     204             :           break;
     205             :         }
     206             :       }
     207      194095 :       if( notnumbered || words[i]==actname ) {
     208        4259 :         if( words[i].find(" ")!=std::string::npos) {
     209         104 :           std::size_t eq=words[i].find_first_of("=");
     210         208 :           reducedline += words[i].substr(0,eq) + "={" + words[i].substr(eq+1) + "} ";
     211             :         } else {
     212        8310 :           reducedline += words[i] + " ";
     213             :         }
     214             :       }
     215             :     }
     216        1143 :     std::vector<unsigned> ninstances( numberedkeys.size(), 0 );
     217        4019 :     for(unsigned j=0; j<numberedkeys.size(); ++j) {
     218        2876 :       for(unsigned i=1;; ++i) {
     219             :         std::string num, val;
     220      192098 :         Tools::convert(i, num);
     221      192098 :         bool found = Tools::parse(words, numberedkeys[j] + num, val );
     222      192098 :         if( !found) {
     223             :           break ;
     224             :         }
     225      189222 :         if( i<6 ) {
     226        1236 :           reducedline += numberedkeys[j] + num + "=" + val + " ";
     227             :         } else {
     228      188604 :           ninstances[j]++;
     229             :         }
     230      189222 :       }
     231             :     }
     232             :     bool outputcomment=false;
     233        3885 :     for(unsigned j=0; j<numberedkeys.size(); ++j) {
     234        2822 :       if( ninstances[j]>0 ) {
     235             :         outputcomment=true;
     236             :         break;
     237             :       }
     238             :     }
     239        1143 :     if( outputcomment ) {
     240             :       reducedline += "    # Action input conctinues with ";
     241         288 :       for(unsigned  j=0; j<numberedkeys.size(); ++j) {
     242             :         std::string num;
     243         208 :         Tools::convert( ninstances[j], num );
     244         208 :         if( ninstances[j]>0 ) {
     245         168 :           reducedline += num + " further " + numberedkeys[j] + "n keywords, ";
     246             :         }
     247             :       }
     248          80 :       savedInputLines.push_back( reducedline );
     249             :     } else {
     250        1063 :       savedInputLines.push_back( line );
     251             :     }
     252             :   } else {
     253        5423 :     savedInputLines.push_back( line );
     254             :   }
     255       13132 : }
     256             : 
     257       68545 : const std::string & ActionShortcut::getShortcutLabel() const {
     258       68545 :   return shortcutlabel;
     259             : }
     260             : 
     261          18 : std::vector<std::string> ActionShortcut::getSavedInputLines() const {
     262          18 :   return savedInputLines;
     263             : }
     264             : 
     265          41 : std::vector<std::string> ActionShortcut::getSavedOutputs() const {
     266          41 :   return savedOutputs;
     267             : }
     268             : 
     269       14549 : std::string ActionShortcut::convertInputLineToString() {
     270             :   std::string output;
     271       65607 :   for(auto p=line.begin(); p!=line.end(); ++p) {
     272       51058 :     if( (*p).find(" " )!=std::string::npos ) {
     273         411 :       std::size_t eq = (*p).find_first_of("=");
     274         822 :       output += " " + (*p).substr(0,eq) + "={" + (*p).substr(eq+1) + "}";
     275             :     } else {
     276      101294 :       output += " " + (*p);
     277             :     }
     278             :   }
     279       14549 :   line.resize(0);
     280       14549 :   return output;
     281             : }
     282             : 
     283         641 : void ActionShortcut::interpretDataLabel( const std::string& mystr, Action* myuser, std::vector<Value*>& arg ) const {
     284             :   std::size_t dot=mystr.find_first_of('.');
     285         641 :   std::string a=mystr.substr(0,dot);
     286         641 :   std::string name=mystr.substr(dot+1);
     287             :   // Retrieve the keywords for the shortcut
     288         641 :   Keywords skeys;
     289         641 :   actionRegister().getKeywords( getName(), skeys );
     290         641 :   std::vector<std::string> out_comps( skeys.getOutputComponents() );
     291             :   // Now get the output components
     292         641 :   if( name=="*" ) {
     293        2908 :     for(unsigned k=0; k<out_comps.size(); ++k) {
     294        2499 :       if( out_comps[k]=="" ) {
     295           0 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a );
     296           0 :         if( action ) {
     297           0 :           if( action->getNumberOfComponents()!=1 ) {
     298           0 :             myuser->error("action named " + a + " has more than one component");
     299             :           }
     300           0 :           arg.push_back(action->copyOutput(0));
     301             :         }
     302             :       } else {
     303        4998 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] );
     304        2499 :         if( action ) {
     305         258 :           if( action->getNumberOfComponents()!=1 ) {
     306           0 :             myuser->error("action named " + a + "_" + out_comps[k] + " has more than one component");
     307             :           }
     308         258 :           arg.push_back(action->copyOutput(0));
     309             :         } else {
     310        2241 :           for(unsigned j=1;; ++j) {
     311             :             std::string numstr;
     312        4525 :             Tools::convert( j, numstr );
     313        9050 :             ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] + "-" + numstr );
     314        4525 :             if( act ) {
     315         140 :               for(unsigned n=0; n<act->getNumberOfComponents(); ++n ) {
     316          70 :                 arg.push_back(act->copyOutput(n));
     317             :               }
     318        4455 :             } else if( j>1 ) {
     319             :               break;  // This ensures that * syntax works with moments, which normally start from 2
     320             :             }
     321        2284 :           }
     322             :         }
     323             :       }
     324             :     }
     325             :   } else {
     326             :     // Check for an action that has action.component
     327         232 :     ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a );
     328         232 :     if( act && act->exists(mystr) ) {
     329             :       return;
     330             :     }
     331             :     // Get components that are actually actions
     332         235 :     for(unsigned k=0; k<out_comps.size(); ++k) {
     333         235 :       if(name.find_first_of(out_comps[k])!=std::string::npos ) {
     334         400 :         ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + name );
     335         200 :         if( action ) {
     336          88 :           arg.push_back(action->copyOutput(a+"_"+name));
     337             :         }
     338             :         break;
     339             :       }
     340             :     }
     341             :   }
     342         641 : }
     343             : 
     344             : }

Generated by: LCOV version 1.16