diff --git a/src/cltools/Driver.cpp b/src/cltools/Driver.cpp index 5bd840348e..4a841d9f5f 100644 --- a/src/cltools/Driver.cpp +++ b/src/cltools/Driver.cpp @@ -27,7 +27,6 @@ #include "core/ActionWithValue.h" #include "core/ActionWithVirtualAtom.h" #include "core/ActionShortcut.h" -#include "core/ActionRegister.h" #include "tools/Communicator.h" #include "tools/Random.h" #include "tools/Pbc.h" @@ -788,14 +787,17 @@ int Driver::main(FILE* in,FILE*out,Communicator& pc) { } ActionWithValue* av=dynamic_cast(pp.get()); if( av && av->getNumberOfComponents()>0 ) { - Keywords keys; actionRegister().getKeywords( av->getName(), keys ); + Keywords keys; p.getKeywordsForAction( av->getName(), keys ); if( firsta ) { valuefile.printf(" \"%s\" : {\n \"action\" : \"%s\"", av->getLabel().c_str(), keys.getDisplayName().c_str() ); firsta=false; } else valuefile.printf(",\n \"%s\" : {\n \"action\" : \"%s\"", av->getLabel().c_str(), keys.getDisplayName().c_str() ); for(unsigned i=0; igetNumberOfComponents(); ++i) { - Value* myval = av->copyOutput(i); std::string compname = myval->getName(), description; std::size_t dot=compname.find("."); - if( dot!=std::string::npos ) { - std::string cname = compname.substr(dot+1); description = av->getOutputComponentDescription( cname, keys ); - } else description = keys.getOutputComponentDescription(".#!value"); + Value* myval = av->copyOutput(i); std::string compname = myval->getName(), description; + if( av->getLabel()==compname ) { + description = keys.getOutputComponentDescription(".#!value"); + } else { + std::size_t dot=compname.find(av->getLabel() + "."); std::string cname = compname.substr(dot + av->getLabel().length() + 1); + description = av->getOutputComponentDescription( cname, keys ); + } if( description.find("\\")!=std::string::npos ) error("found invalid backslash character in documentation for component " + compname + " in action " + av->getName() + " with label " + av->getLabel() ); valuefile.printf(",\n \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() ); } @@ -808,7 +810,7 @@ int Driver::main(FILE* in,FILE*out,Communicator& pc) { if( firsta ) { valuefile.printf(" \"shortcut_%s\" : {\n \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() ); firsta=false; } else valuefile.printf(",\n \"shortcut_%s\" : {\n \"action\" : \"%s\"", as->getShortcutLabel().c_str(), as->getName().c_str() ); - Keywords keys; actionRegister().getKeywords( as->getName(), keys ); + Keywords keys; p.getKeywordsForAction( as->getName(), keys ); for(unsigned i=0; i( cnames[i] ); if( !av2 ) plumed_merror("could not find value created by shortcut with name " + cnames[i] ); @@ -820,10 +822,13 @@ int Driver::main(FILE* in,FILE*out,Communicator& pc) { valuefile.printf(",\n \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() ); } else { for(unsigned j=0; jgetNumberOfComponents(); ++j) { - Value* myval = av2->copyOutput(j); std::string compname = myval->getName(), description; std::size_t dot=compname.find("."); - if( dot!=std::string::npos ) { - std::string cname = compname.substr(dot+1); description = av2->getOutputComponentDescription( cname, keys ); - } else plumed_merror("should not be outputting description of value from action when using shortcuts"); + Value* myval = av2->copyOutput(j); std::string compname = myval->getName(), description; + if( av2->getLabel()==compname ) { + plumed_merror("should not be outputting description of value from action when using shortcuts"); + } else { + std::size_t dot=compname.find(av2->getLabel() + "."); std::string cname = compname.substr(dot+av2->getLabel().length() + 1); + description = av2->getOutputComponentDescription( cname, keys ); + } if( description.find("\\")!=std::string::npos ) error("found invalid backslash character in documentation for component " + compname + " in action " + av2->getName() + " with label " + av2->getLabel() ); valuefile.printf(",\n \"%s\" : { \"type\": \"%s\", \"description\": \"%s\" }", myval->getName().c_str(), myval->getValueType().c_str(), description.c_str() ); } diff --git a/src/core/Action.cpp b/src/core/Action.cpp index f8f9084bca..27e3bb8272 100644 --- a/src/core/Action.cpp +++ b/src/core/Action.cpp @@ -97,7 +97,7 @@ Action::Action(const ActionOptions&ao): if(label.length()==0) { std::string s; Tools::convert(plumed.getActionSet().size()-plumed.getActionSet().select().size(),s); label="@"+s; - } + } else if ( label.find(".")!=std::string::npos ) warning("using full stop in an action label should be avaoided as . has a special meaning in PLUMED action labels"); if( plumed.getActionSet().selectWithLabel(label) ) error("label " + label + " has been already used"); if( !keywords.exists("NO_ACTION_LOG") ) log.printf(" with label %s\n",label.c_str()); if ( keywords.exists("UPDATE_FROM") ) parse("UPDATE_FROM",update_from); diff --git a/src/core/ActionRegister.cpp b/src/core/ActionRegister.cpp index 8dff07cf5f..9054effa76 100644 --- a/src/core/ActionRegister.cpp +++ b/src/core/ActionRegister.cpp @@ -93,4 +93,8 @@ bool ActionRegister::getKeywords(const std::string& action, Keywords& keys) { return false; } +void ActionRegister::getKeywords(const std::vector & images, const std::string& action, Keywords& keys) { + auto content=get(images,action); keys.thisactname = action; content.keys(keys); +} + } diff --git a/src/core/ActionRegister.h b/src/core/ActionRegister.h index 6af8d8374d..474505addc 100644 --- a/src/core/ActionRegister.h +++ b/src/core/ActionRegister.h @@ -64,6 +64,7 @@ class ActionRegister: bool printManual(const std::string& action, const bool& vimout, const bool& spellout); /// Retrieve a keywords object for a particular action bool getKeywords( const std::string& action, Keywords& keys ); + void getKeywords(const std::vector & images, const std::string& action, Keywords& keys); /// Print out a template command for an action bool printTemplate(const std::string& action, bool include_optional); std::vector getActionNames() const; diff --git a/src/core/ActionWithValue.cpp b/src/core/ActionWithValue.cpp index 44acb624b3..b708db9c61 100644 --- a/src/core/ActionWithValue.cpp +++ b/src/core/ActionWithValue.cpp @@ -170,7 +170,6 @@ void ActionWithValue::addComponentWithDerivatives( const std::string& name, cons std::string ActionWithValue::getOutputComponentDescription( const std::string& cname, const Keywords& keys ) const { std::size_t und=cname.find_last_of("_"); std::size_t hyph=cname.find_first_of("-"); - if( und!=std::string::npos && hyph!=std::string::npos ) plumed_merror("cannot use underscore and hyphen in name"); if( und!=std::string::npos ) return keys.getOutputComponentDescription(cname.substr(und)) + " This particular component measures this quantity for the input CV named " + cname.substr(0,und); if( hyph!=std::string::npos ) return keys.getOutputComponentDescription(cname.substr(0,hyph)) + " This is the " + cname.substr(hyph+1) + "th of these quantities"; plumed_massert( keys.outputComponentExists(cname), "component " + cname + " does not exist in " + keys.getDisplayName() + " if the component names are customizable then you should override this function" ); diff --git a/src/core/PlumedMain.cpp b/src/core/PlumedMain.cpp index b34a2ae78a..cdeba0472f 100644 --- a/src/core/PlumedMain.cpp +++ b/src/core/PlumedMain.cpp @@ -1488,6 +1488,10 @@ bool PlumedMain::parseOnlyMode() const { return doParseOnly; } +void PlumedMain::getKeywordsForAction( const std::string& action, Keywords& keys ) const { + actionRegister().getKeywords( dlloader.getHandles(), action, keys ); +} + #ifdef __PLUMED_HAS_PYTHON // This is here to stop cppcheck throwing an error #endif diff --git a/src/core/PlumedMain.h b/src/core/PlumedMain.h index 7c33c307b3..a50ba85fb7 100644 --- a/src/core/PlumedMain.h +++ b/src/core/PlumedMain.h @@ -68,6 +68,7 @@ class FileBase; class TypesafePtr; class IFile; class Units; +class Keywords; class DataPassingTools; /** @@ -523,6 +524,8 @@ class PlumedMain: void plumedQuantityToMD( const std::string& unit, const double& eng, const TypesafePtr & m) const ; /// Take a typesafe pointer from the MD code and convert it to a double double MDQuantityToPLUMED( const std::string& unit, const TypesafePtr & m) const ; +/// Get the keywords for a particular action + void getKeywordsForAction( const std::string& action, Keywords& keys ) const ; }; ///// diff --git a/src/multicolvar/XAngle.cpp b/src/multicolvar/XAngle.cpp index b567a866d3..63775f2b13 100644 --- a/src/multicolvar/XAngle.cpp +++ b/src/multicolvar/XAngle.cpp @@ -76,7 +76,7 @@ XAngle::XAngle(const ActionOptions& ao): ActionShortcut(ao) { // Create distances - std::string dline = getShortcutLabel() + ": DISTANCE COMPONENTS"; + std::string dline = getShortcutLabel() + "_dists: DISTANCE COMPONENTS"; for(unsigned i=1;; ++i) { std::string atstring; parseNumbered("ATOMS",i,atstring); if( atstring.length()==0 ) break; @@ -85,11 +85,11 @@ XAngle::XAngle(const ActionOptions& ao): } readInputLine( dline ); // Normalize the vectors - readInputLine( getShortcutLabel() + "_norm2: COMBINE ARG=" + getShortcutLabel() + ".x" + "," + getShortcutLabel() + ".y," + getShortcutLabel() + ".z POWERS=2,2,2 PERIODIC=NO"); + readInputLine( getShortcutLabel() + "_norm2: COMBINE ARG=" + getShortcutLabel() + "_dists.x" + "," + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_dists.z POWERS=2,2,2 PERIODIC=NO"); readInputLine( getShortcutLabel() + "_norm: CUSTOM ARG=" + getShortcutLabel() + "_norm2 FUNC=sqrt(x) PERIODIC=NO"); - readInputLine( getShortcutLabel() + "_norm_x: CUSTOM ARG=" + getShortcutLabel() + ".x," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); - readInputLine( getShortcutLabel() + "_norm_y: CUSTOM ARG=" + getShortcutLabel() + ".y," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); - readInputLine( getShortcutLabel() + "_norm_z: CUSTOM ARG=" + getShortcutLabel() + ".z," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); + readInputLine( getShortcutLabel() + "_norm_x: CUSTOM ARG=" + getShortcutLabel() + "_dists.x," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); + readInputLine( getShortcutLabel() + "_norm_y: CUSTOM ARG=" + getShortcutLabel() + "_dists.y," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); + readInputLine( getShortcutLabel() + "_norm_z: CUSTOM ARG=" + getShortcutLabel() + "_dists.z," + getShortcutLabel() + "_norm FUNC=x/y PERIODIC=NO"); // Now compute the angles with matheval if( getName()=="XANGLES" ) readInputLine( getShortcutLabel() + "_ang: CUSTOM FUNC=acos(x) PERIODIC=NO ARG=" + getShortcutLabel() + "_norm_x"); if( getName()=="YANGLES" ) readInputLine( getShortcutLabel() + "_ang: CUSTOM FUNC=acos(x) PERIODIC=NO ARG=" + getShortcutLabel() + "_norm_y");