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 18477 : void ActionShortcut::registerKeywords( Keywords& keys ) { 31 18477 : Action::registerKeywords( keys ); 32 36954 : keys.add("hidden","IS_SHORTCUT","hidden keyword to tell if actions are shortcuts so that example generator can provide expansions of shortcuts"); 33 36954 : keys.add("hidden","HAS_VALUES","this is used in json output to determine those actions that have values"); 34 18477 : } 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() ) savedOutputs.push_back( av_label ); 97 : else { 98 36025 : for(unsigned i=0; i<keywords.cnames.size(); ++i) { 99 30392 : if( av_label == getShortcutLabel() + "_" + keywords.cnames[i] ) savedOutputs.push_back( av_label ); 100 60190 : else if( keywords.getOutputComponentFlag(keywords.cnames[i])!="default" ) { 101 26388 : std::string thisflag = keywords.getOutputComponentFlag(keywords.cnames[i]); 102 53378 : if( keywords.numbered(thisflag) && av_label.find(getShortcutLabel() + "_" + keywords.cnames[i])!=std::string::npos ) savedOutputs.push_back( av_label ); 103 : } 104 : } 105 : } 106 : } 107 : } else { 108 14842 : ActionWithValue* av = plumed.getActionSet()[plumed.getActionSet().size()-1]->castToActionWithValue(); 109 14857 : if( !av ) error("shortcut is using suffix but action created is not ActionWithValue"); 110 14842 : Keywords thiskeys; actionRegister().getKeywords( av->getName(), thiskeys ); 111 29684 : if( thiskeys.getDisplayName()!=getName() ) error("mismatch between display name of hidden action " + thiskeys.getDisplayName() + " and shortcut that creates it " + getName() ); 112 14842 : } 113 0 : } else error("requirement for action " + words[0] + " should be registered in registerKeywords function for shortcut action using keys.useAction"); 114 21703 : } 115 : 116 1 : void ActionShortcut::addCommentToShortcutOutput( const std::string& input ) { 117 1 : savedInputLines.push_back( input ); 118 1 : } 119 : 120 37 : std::string ActionShortcut::getUpdateLimits() const { 121 37 : std::string f_input=""; 122 37 : if( update_from!=std::numeric_limits<double>::max() ) { 123 4 : std::string ufrom; Tools::convert( update_from, ufrom ); f_input += " UPDATE_FROM=" + ufrom; 124 : } 125 37 : if( update_until!=std::numeric_limits<double>::max() ) { 126 4 : std::string util; Tools::convert( update_until, util ); f_input += " UPDATE_UNTIL=" + util; 127 : } 128 37 : return f_input; 129 : } 130 : 131 6561 : void ActionShortcut::addToSavedInputLines( const std::string& line ) { 132 6561 : std::vector<std::string> words = Tools::getWords(line); std::string actname; 133 6561 : if( words[0].find_first_of(":")!=std::string::npos) actname = words[1]; else actname = words[0]; 134 6561 : if( !actionRegister().check(actname) ) error("found no action with name " + actname + " to create shortcut"); 135 6561 : Keywords thiskeys; actionRegister().getKeywords( actname, thiskeys ); std::vector<std::string> numberedkeys; 136 55560 : for(unsigned i=0; i<thiskeys.size(); ++i ) { 137 105752 : if( thiskeys.numbered( thiskeys.getKeyword(i) ) ) numberedkeys.push_back( thiskeys.getKeyword(i) ); 138 : } 139 12046 : if( numberedkeys.size()>0 && actname!="CONCATENATE" ) { 140 : std::string reducedline; 141 190250 : for(unsigned i=0; i<words.size(); ++i) { 142 : bool notnumbered=true; 143 481887 : for(unsigned j=0; j<numberedkeys.size(); ++j) { 144 800495 : if( words[i].find(numberedkeys[j])!=std::string::npos && words[i].substr(0,numberedkeys[j].length()+1)!=numberedkeys[j]+"=" ) { notnumbered=false; break; } 145 : } 146 184939 : if( notnumbered || words[i]==actname ) { 147 22711 : if( words[i].find(" ")!=std::string::npos) { 148 244 : std::size_t eq=words[i].find_first_of("="); 149 488 : reducedline += words[i].substr(0,eq) + "={" + words[i].substr(eq+1) + "} "; 150 44934 : } else reducedline += words[i] + " "; 151 : } 152 : } 153 5311 : std::vector<unsigned> ninstances( numberedkeys.size(), 0 ); 154 12717 : for(unsigned j=0; j<numberedkeys.size(); ++j) { 155 7406 : for(unsigned i=1;; ++i) { 156 169025 : std::string num, val; Tools::convert(i, num); 157 169025 : bool found = Tools::parse(words, numberedkeys[j] + num, val ); 158 169025 : if( !found) break ; 159 162198 : if( i<6 ) reducedline += numberedkeys[j] + num + "=" + val + " "; 160 161040 : else ninstances[j]++; 161 161619 : } 162 : } 163 : bool outputcomment=false; 164 12595 : for(unsigned j=0; j<numberedkeys.size(); ++j) { 165 7358 : if( ninstances[j]>0 ) { outputcomment=true; break; } 166 : } 167 5311 : if( outputcomment ) { 168 : reducedline += " # Action input conctinues with "; 169 258 : for(unsigned j=0; j<numberedkeys.size(); ++j) { 170 184 : std::string num; Tools::convert( ninstances[j], num ); 171 262 : if( ninstances[j]>0 ) reducedline += num + " further " + numberedkeys[j] + "n keywords, "; 172 : } 173 : } 174 5311 : savedInputLines.push_back( reducedline ); 175 1250 : } else savedInputLines.push_back( line ); 176 13122 : } 177 : 178 71745 : const std::string & ActionShortcut::getShortcutLabel() const { 179 71745 : return shortcutlabel; 180 : } 181 : 182 18 : std::vector<std::string> ActionShortcut::getSavedInputLines() const { 183 18 : return savedInputLines; 184 : } 185 : 186 41 : std::vector<std::string> ActionShortcut::getSavedOutputs() const { 187 41 : return savedOutputs; 188 : } 189 : 190 14832 : std::string ActionShortcut::convertInputLineToString() { 191 : std::string output; 192 66184 : for(auto p=line.begin(); p!=line.end(); ++p) { 193 51352 : if( (*p).find(" " )!=std::string::npos ) { 194 405 : std::size_t eq = (*p).find_first_of("="); 195 810 : output += " " + (*p).substr(0,eq) + "={" + (*p).substr(eq+1) + "}"; 196 101894 : } else output += " " + (*p); 197 : } 198 14832 : line.resize(0); return output; 199 : } 200 : 201 613 : void ActionShortcut::interpretDataLabel( const std::string& mystr, Action* myuser, std::vector<Value*>& arg ) const { 202 613 : std::size_t dot=mystr.find_first_of('.'); std::string a=mystr.substr(0,dot); std::string name=mystr.substr(dot+1); 203 : // Retrieve the keywords for the shortcut 204 613 : Keywords skeys; actionRegister().getKeywords( getName(), skeys ); 205 613 : std::vector<std::string> out_comps( skeys.getOutputComponents() ); 206 : // Now get the output components 207 613 : if( name=="*" ) { 208 2613 : for(unsigned k=0; k<out_comps.size(); ++k) { 209 2228 : if( out_comps[k]=="" ) { 210 0 : ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a ); 211 0 : if( action ) { 212 0 : if( action->getNumberOfComponents()!=1 ) myuser->error("action named " + a + " has more than one component"); 213 0 : arg.push_back(action->copyOutput(0)); 214 : } 215 : } else { 216 4456 : ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] ); 217 2228 : if( action ) { 218 234 : if( action->getNumberOfComponents()!=1 ) myuser->error("action named " + a + "_" + out_comps[k] + " has more than one component"); 219 234 : arg.push_back(action->copyOutput(0)); 220 : } else { 221 1994 : for(unsigned j=1;; ++j) { 222 4031 : std::string numstr; Tools::convert( j, numstr ); 223 8062 : ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + out_comps[k] + "-" + numstr ); 224 4031 : if( act ) { 225 140 : for(unsigned n=0; n<act->getNumberOfComponents(); ++n ) arg.push_back(act->copyOutput(n)); 226 3961 : } else if( j>1 ) break; // This ensures that * syntax works with moments, which normally start from 2 227 2037 : } 228 : } 229 : } 230 : } 231 : } else { 232 : // Check for an action that has action.component 233 228 : ActionWithValue* act=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a ); 234 228 : if( act && act->exists(mystr) ) return; 235 : // Get components that are actually actions 236 231 : for(unsigned k=0; k<out_comps.size(); ++k) { 237 231 : if(name.find_first_of(out_comps[k])!=std::string::npos ) { 238 392 : ActionWithValue* action=plumed.getActionSet().selectWithLabel<ActionWithValue*>( a + "_" + name ); 239 196 : if( action ) arg.push_back(action->copyOutput(a+"_"+name)); 240 : break; 241 : } 242 : } 243 : } 244 613 : } 245 : 246 : }