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 : #ifndef __PLUMED_tools_Keywords_h
23 : #define __PLUMED_tools_Keywords_h
24 : #include <vector>
25 : #include <string>
26 : #include <string_view>
27 : #include <map>
28 : #include <variant>
29 :
30 : #include "Exception.h"
31 : #include "BitmaskEnum.h"
32 :
33 : namespace PLMD {
34 :
35 : class Log;
36 :
37 : /// This class holds the keywords and their documentation
38 : class Keywords {
39 : /// This class lets me pass keyword types easily
40 : struct KeyType {
41 : enum class keyStyle {hidden,compulsory,flag,optional,atoms,deprecated,unknown};
42 : keyStyle style;
43 : static keyStyle keyStyleFromString(std::string_view type );
44 : explicit KeyType( keyStyle type );
45 : explicit KeyType( std::string_view type );
46 : void setStyle( std::string_view type );
47 : bool isCompulsory() const {
48 652407 : return (style==keyStyle::compulsory);
49 : }
50 : bool isFlag() const {
51 1559010 : return (style==keyStyle::flag);
52 : }
53 : bool isOptional() const {
54 39377 : return (style==keyStyle::optional);
55 : }
56 : bool isAtomList() const {
57 1864438 : return (style==keyStyle::atoms);
58 : }
59 : bool isHidden() const {
60 : return (style==keyStyle::hidden);
61 : }
62 : bool isDeprecated() const {
63 656184 : return (style==keyStyle::deprecated);
64 : }
65 3004702 : std::string toString() const {
66 : //if you add a style and you forget to update this function the compiler will refuse to compile
67 3004702 : switch(style) {
68 : case keyStyle::compulsory:
69 215439 : return "compulsory";
70 : case keyStyle::optional:
71 845838 : return "optional";
72 : case keyStyle::atoms:
73 980885 : return "atoms";
74 : case keyStyle::flag:
75 730374 : return "flag";
76 : case keyStyle::hidden:
77 181380 : return "hidden";
78 : case keyStyle::deprecated:
79 50786 : return "deprecated";
80 0 : default:
81 0 : plumed_massert(false,"unknown keyword type");
82 : }
83 : return "unknown";
84 : }
85 : };
86 :
87 : public:
88 : enum class argType {scalar=1,vector=1<<2,matrix=1<<3,grid=1<<4};
89 : enum class componentType {scalar=1,vector=1<<2,matrix=1<<3,grid=1<<4,atoms=1<<5,atom=1<<6};
90 : private:
91 : /// Is this an action or driver (this bool affects what style==atoms does in print)
92 : bool isaction=true;
93 : /// This allows us to overwrite the behavior of the atoms type in analysis actions
94 : bool isatoms=true;
95 : /// The name of the action that has this set of keywords
96 : std::string thisactname;
97 : /// The action to use in place of this deprecated action
98 : std::string replaceaction="none";
99 :
100 : struct keyInfo {
101 : /// Whether the keyword is compulsory, optional...
102 : KeyType type{KeyType::keyStyle::unknown};
103 : /// The documentation for the keyword
104 : std::string docstring;
105 : /// The default values (if there are default values) for compulsory keywords or flags
106 : std::variant<std::monostate,std::string,bool> defaultValue;
107 : ///The type of the argument if this keywords accepts arguments
108 : std::variant<std::monostate,argType>argument_type;
109 : /// The tags for atoms - we use this so the manual can differentiate between different ways of specifying atoms
110 : std::string atomtag;//no noeed for optional, since the type will state if this is needed
111 : ///This stores any action documentation that we should link to
112 : std::string linkaction;
113 : ///This stores any pages of doucmentation that we should link to
114 : std::string linkpage;
115 : /// For a deprecated keyword: the keyword that replaces it (empty if there is none)
116 : std::string replacement;
117 : /// Do we allow stuff like key1, key2 etc
118 : bool allowmultiple;
119 : keyInfo();
120 : //these functions are not needed (this is a struct), but are useful in constructing the key
121 : keyInfo& setType(KeyType t);
122 : keyInfo& setDocString(std::string_view d);
123 : keyInfo& setDefaultValue(std::string_view d);
124 : keyInfo& setDefaultFlag(bool a);
125 : keyInfo& setArgumentType(argType a);
126 : keyInfo& setAllowMultiple(bool a);
127 : keyInfo& setLinkedAction(std::string_view a);
128 : keyInfo& setLinkedPage(std::string_view p);
129 : bool isArgument() const;
130 : };
131 : ///Add o reserve a new keyword (internal tool)
132 : void addOrReserve( std::string_view keytype, std::string_view key, std::string_view docstring, bool reserve );
133 : //std::less<void> make some magic and makes find and [] work with string_view
134 : /// Stores the keywords along with their settings
135 : std::map<std::string,keyInfo,std::less<void>> keywords;
136 : /// The names of the allowed keywords, in order of declaration
137 : std::vector<std::string> keys;
138 : /// The names of the reserved keywords, in order of declaration
139 : std::vector<std::string> reserved_keys;
140 : struct component {
141 : /// The keyword that turns on this component
142 : std::string key;
143 : /// The documentation for the component
144 : std::string docstring;
145 : /// The type of the component
146 : componentType type;
147 : component();
148 : //these functions are not needed (this is a struct), but are useful in constructing the component
149 : component& setKey(std::string_view k);
150 : component& setDocstring(std::string_view d);
151 : component& setType(componentType t);
152 : };
153 : //the "exists component" is stored in the map keys
154 : std::map<std::string,component,std::less<void>> components;
155 : /// The string that should be printed out to describe how the components work for this particular action
156 : std::string cstring;
157 : /// The names of all the possible components for an action, in order of their (first) declaration
158 : std::vector<std::string> cnames;
159 : /// The list of actions that are needed by this action
160 : std::vector<std::string> neededActions;
161 : /// List of suffixes that can be used with this action
162 : std::vector<std::string> actionNameSuffixes;
163 : /// List of doi's that should appear in the manual
164 : std::vector<std::string> doilist;
165 : /// Print the documentation for the named keyword in html
166 : void print_html_item( const std::string& ) const;
167 : public:
168 : /// Constructor
169 246081 : Keywords() {}
170 : ///
171 : void isDriver() {
172 14642 : isaction=false;
173 : }
174 : ///
175 : void isAnalysis() {
176 : isatoms=false;
177 : }
178 : /// find out whether flag key is on or off by default.
179 : bool getLogicalDefault(const std::string & key, bool& def ) const ;
180 : /// Get the value of the default for the keyword named key
181 : bool getDefaultValue(const std::string & key, std::string& def ) const ;
182 : /// Return the number of defined keywords
183 : unsigned size() const;
184 : /// Check if numbered keywords are allowed for this action
185 : bool numbered( const std::string & k ) const;
186 : /// Get the ordered list of active keywords (not the reserved ones)
187 : const std::vector<std::string>& getKeys() const {
188 : return keys;
189 : }
190 : //Get the ordered list of arguments
191 : std::vector<std::string> getArgumentKeys() const;
192 : /// Return the ith keyword
193 : std::string getKeyword( const unsigned i ) const;
194 : /// Get the documentation for a particular keyword
195 : std::string getKeywordDocs( const std::string& key ) const;
196 : /// Print the documentation to the log file (used by PLMD::Action::error)
197 : void print( Log& log ) const ;
198 : /// Print the documentation to a file (use by PLUMED::CLTool::readCommandLineArgs)
199 : void print( FILE* out ) const ;
200 : /// Get the help string
201 : std::string getHelpString() const ;
202 : /// Print a file containing the list of keywords for a particular action (used for spell checking)
203 : void print_spelling() const ;
204 : /// Reserve a keyword
205 : void reserve( std::string_view keytype, std::string_view key, std::string_view docstring );
206 : /// Reserve a flag
207 : void reserveFlag( const std::string & key, bool defaultValue, const std::string & docstring );
208 : /// Use one of the reserved keywords
209 : void use( std::string_view k );
210 : /// append the data from another Keywords object (**only** keywords, reserved keywords and components)
211 : void add( const Keywords& keys );
212 : /// Add a new keyword of type t with name k and description d
213 : void add( std::string_view keytype, std::string_view key, std::string_view docstring );
214 : /// Add a keyword that was used in older versions of the code and that has now been replaced
215 : void addDeprecatedKeyword( std::string_view key, const std::string& replacement );
216 : /// Add a flag that was used in older versions of the code that has now been replaced
217 : void addDeprecatedFlag( const std::string& key, const std::string& replacement );
218 : /// Add a new compulsory keyword (t must equal compulsory) with name k, default value def and description d
219 : void add( std::string_view keytype, std::string_view key, std::string_view defaultValue, std::string_view docstring );
220 : /// Add a falg with name k that is by default on if def is true and off if def is false. d should provide a description of the flag
221 : void addFlag(std::string_view key, bool defaultValue, std::string_view docstring);
222 : /// Remove the keyword with name k
223 : void remove( const std::string & k );
224 : /// Check if there is a keyword with name k
225 : bool exists( std::string_view k ) const ;
226 : /// Check the keyword k has been reserved
227 : bool reserved( std::string_view k ) const ;
228 : /// Get the type for the keyword with string k
229 : std::string getStyle(const std::string & k ) const ;
230 : /// The keyword that replaces the deprecated keyword k (empty if k is not deprecated or has no replacement)
231 : std::string getDeprecatedReplacement( std::string_view k ) const ;
232 : /// Check if the keyword with name k has style t
233 : bool style( const std::string & k, const std::string & t ) const ;
234 : /// Print an html version of the documentation
235 : void print_html() const ;
236 : /// Print keywords in form readable by vim
237 : void print_vim() const ;
238 : /// Print the template version for the documentation
239 : void print_template( const std::string& actionname, bool include_optional) const ;
240 : /// Change part of the style of a keyword
241 : ///
242 : /// The standard usecase for this method is creating a compulsory or an atom(s) numbered keyword.
243 : /// For example:
244 : /// @code{.cpp}
245 : /// keys.add("numbered","ATOMS","the atoms involved in each of the contacts you wish to calculate. "
246 : /// "Keywords like ATOMS1, ATOMS2, ATOMS3,... should be listed and one contact will be "
247 : /// "calculated for each ATOM keyword you specify.");
248 : /// keys.reset_style("ATOMS","atoms");
249 : /// keys.add("numbered","SWITCH","The switching functions to use for each of the contacts in your map. "
250 : /// "You can either specify a global switching function using SWITCH or one "
251 : /// "switching function for each contact. Details of the various switching "
252 : /// "functions you can use are provided on \\ref switchingfunction.");
253 : /// keys.reset_style("SWITCH","compulsory");
254 : /// @endcode
255 : /// @note Note that some option of the selected keyword may not change. In particular:
256 : /// - A numbered keyword will change the style but the keyInfo::allowmultiple
257 : /// will remain set to `true`
258 : /// - An eventual keyInfo::atomtag will not be changed unless the style is set to
259 : /// an atomlist
260 : void reset_style( const std::string & k, const std::string & style );
261 : /// Clear everything from the keywords object.
262 : /// Not actually needed if your Keywords object is going out of scope.
263 : void destroyData();
264 : /// Set the text that introduces how the components for this action are introduced
265 : void setComponentsIntroduction( const std::string& instr );
266 : /// Add the description of the value
267 : void setValueDescription( const std::string& type, const std::string& descr );
268 : /// @todo prepend[[deprecated("Please specify the data type for the argument from scalar/vector/matrix/grid with the Keywords::argType enum")]]
269 : void setValueDescription( componentType type, const std::string& descr );
270 : /// Add a potential component which can be output by this particular action
271 : [[deprecated("Use addOutputComponent with four argument and specify valid types for value from scalar/vector/matrix/grid")]]
272 : void addOutputComponent( const std::string& name, const std::string& key, const std::string& descr );
273 : /// @todo prepend[[deprecated("Please specify the data type for the argument from scalar/vector/matrix/grid with the Keywords::argType enum")]]
274 : void addOutputComponent( const std::string& name, const std::string& key, const std::string& type, const std::string& descr );
275 : /// Add a potential component which can be output by this particular action
276 : void addOutputComponent( const std::string& name, const std::string& key, componentType type, const std::string& descr );
277 : /// Remove a component that can be output by this particular action
278 : void removeOutputComponent( const std::string& name );
279 : /// Has a component with this name been added?
280 : bool outputComponentExists( const std::string& name ) const ;
281 : /// Check that type for component has been documented correctly
282 : bool componentHasCorrectType( const std::string& name, const std::size_t& rank, const bool& hasderiv ) const ;
283 : /// Create the documentation for a keyword that reads arguments
284 : /// @todo prepend [[deprecated("Please specify the data type for the argument from scalar/vector/matrix/grid with the Keywords::argType enum")]]
285 : void addInputKeyword( const std::string & keyType, const std::string & key, const std::string & dataType, const std::string & docstring );
286 : /// Create the documentation for a keyword that reads arguments
287 : void addInputKeyword( const std::string & keyType, const std::string & key, argType dataType, const std::string & docstring );
288 : /// Create the documentation for a keyword that reads arguments
289 : /// @todo prepend[[deprecated("Please specify the data type for the argument from scalar/vector/matrix/grid with the Keywords::argType enum")]]
290 : void addInputKeyword( const std::string & keyType, const std::string & key, const std::string & dataType, const std::string& defaultValue, const std::string & docstring );
291 : /// Create the documentation for a keyword that reads arguments
292 : void addInputKeyword( const std::string & keyType, const std::string & key, argType dataType, const std::string& defaultValue, const std::string & docstring );
293 : /// Check that a value of this rank (with or without derivatives) is accepted by at least one of the keywords that read arguments
294 : bool checkArgumentType( const std::size_t& rank, const bool& hasderiv ) const ;
295 : /// Get the valid types that can be used as argument for this keyword
296 : std::string getArgumentType( const std::string& name ) const ;
297 : /// Get the flag that forces thie named component to be calculated
298 : std::string getOutputComponentFlag( const std::string& name ) const ;
299 : /// Get the type for the named output component
300 : std::string getOutputComponentType( const std::string& name ) const ;
301 : /// Get the description of the named component
302 : std::string getOutputComponentDescription( const std::string& name ) const ;
303 : /// Get the full ordered list of output components
304 : const std::vector<std::string>& getOutputComponents() const {
305 4395 : return cnames;
306 : }
307 : /// Get the description of a particular keyword
308 : std::string getKeywordDescription( const std::string& name ) const ;
309 : /// Get the description of a particular keyword
310 : std::string getTooltip( const std::string& name ) const ;
311 : /// Note that another actions is required to create this shortcut
312 : void needsAction( const std::string& name );
313 : /// Check if the requested action is in the list of the needed actions
314 : bool isActionNeeded( std::string_view name ) const ;
315 : /// Add a suffix to the list of possible action name suffixes
316 : void addActionNameSuffix( const std::string& suffix );
317 : /** @brief checks that name is a composition of basename and one of the possible suffixes
318 :
319 : Cycles on the registered suffixed and return true if the combination
320 : `basename+suffix` equals to the passed name
321 : */
322 : bool isActionSuffixed( std::string_view name, std::string_view basename) const ;
323 : /// Get the list of keywords that are needed by this action
324 : const std::vector<std::string>& getNeededKeywords() const ;
325 : /// Return the name of the action that has this set of keywords
326 : std::string getDisplayName() const ;
327 : /// Set the display name
328 : void setDisplayName( const std::string& name );
329 : /// Get the action that should be used to replace this one if action has been deprecated
330 : std::string getReplacementAction() const ;
331 : /// Note that this action has been deprecated
332 : void setDeprecated( const std::string& name );
333 : /// Add a DOI to the list in the manual page for this action
334 : void addDOI( const std::string& doi );
335 : /// Get the list of DOI
336 : const std::vector<std::string>& getDOIList() const ;
337 : /// Create a link to this action in the documentation for it
338 : void linkActionInDocs( const std::string& k, const std::string& action );
339 : /// Create a link to this page in the documentation for a keyword
340 : void addLinkInDocForFlag( const std::string& k, const std::string& page );
341 : /// Get any actions that are linked to this keyword
342 : std::string getLinkedActions( const std::string& key ) const ;
343 : /// Get any pages that are linked to this keyword
344 : std::string getLinkedPages( const std::string& key ) const ;
345 : };
346 :
347 : //the following templates specializations make the bitmask enum work with the
348 : // bitwise operators `|`, `&` and the "valid" function (valid converts to bool the result of a "mask operation")
349 : template<>
350 : struct enum_traits::BitmaskEnum< Keywords::componentType > {
351 : static constexpr bool has_valid = true;
352 : static constexpr bool has_bit_or = true;
353 : static constexpr bool has_bit_and = true;
354 : };
355 :
356 : template<>
357 : struct enum_traits::BitmaskEnum< Keywords::argType > {
358 : static constexpr bool has_valid = true;
359 : static constexpr bool has_bit_or = true;
360 : static constexpr bool has_bit_and = true;
361 : };
362 :
363 : std::string toString(Keywords::argType at);
364 : /**
365 : * Converts a string to the corresponding Keywords::argType.
366 : *
367 : * @param str The string to convert.
368 : * @return The Keywords::argType corresponding to the string.
369 : * @throws std::invalid_argument If the string does not match any enum value.
370 : */
371 : Keywords::argType stoat(std::string_view str);
372 : std::string toString(Keywords::componentType at);
373 :
374 : /**
375 : * Converts a string to the corresponding Keywords::componentType.
376 : * @param str The string to convert.
377 : * @return The Keywords::componentType corresponding to the string.
378 : * @throws std::invalid_argument if the string does not match any enum value.
379 : */
380 : Keywords::componentType stoct(std::string_view str) ;
381 :
382 : } // namespace PLMD
383 :
384 : #endif
|