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 : #include "Keywords.h"
23 : #include "Log.h"
24 : #include "Tools.h"
25 : #include <iostream>
26 : #include <iomanip>
27 :
28 : namespace PLMD {
29 :
30 2139914 : Keywords::KeyType::KeyType( const std::string& type ) {
31 2139914 : if( type=="compulsory" ) {
32 568180 : style=compulsory;
33 1571734 : } else if( type=="flag" ) {
34 448371 : style=flag;
35 1123363 : } else if( type=="optional" ) {
36 679287 : style=optional;
37 444076 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
38 219224 : style=atoms;
39 224852 : } else if( type=="hidden" ) {
40 224852 : style=hidden;
41 0 : } else if( type=="vessel" ) {
42 0 : style=vessel;
43 : } else {
44 0 : plumed_massert(false,"invalid keyword specifier " + type);
45 : }
46 2139914 : }
47 :
48 922 : void Keywords::KeyType::setStyle( const std::string& type ) {
49 922 : if( type=="compulsory" ) {
50 435 : style=compulsory;
51 487 : } else if( type=="flag" ) {
52 0 : style=flag;
53 487 : } else if( type=="optional" ) {
54 25 : style=optional;
55 462 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
56 462 : style=atoms;
57 0 : } else if( type=="hidden" ) {
58 0 : style=hidden;
59 0 : } else if( type=="vessel" ) {
60 0 : style=vessel;
61 : } else {
62 0 : plumed_massert(false,"invalid keyword specifier " + type);
63 : }
64 922 : }
65 :
66 1818345 : std::string Keywords::getStyle( const std::string & k ) const {
67 0 : plumed_massert( types.count(k), "Did not find keyword " + k );
68 1818345 : return (types.find(k)->second).toString();
69 : }
70 :
71 0 : void Keywords::add( const Keywords& newkeys ) {
72 0 : newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs );
73 0 : }
74 :
75 0 : void Keywords::copyData( std::vector<std::string>& kk, std::vector<std::string>& rk, std::map<std::string,KeyType>& tt, std::map<std::string,bool>& am,
76 : std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums,
77 : std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck,
78 : std::map<std::string,std::string>& cd ) const {
79 0 : for(unsigned i=0; i<keys.size(); ++i) {
80 0 : std::string thiskey=keys[i];
81 0 : for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
82 0 : for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
83 0 : kk.push_back( thiskey );
84 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
85 0 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
86 0 : if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
87 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
88 0 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
89 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
90 0 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
91 0 : if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
92 0 : if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
93 : }
94 0 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
95 0 : std::string thiskey=reserved_keys[i];
96 0 : for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
97 0 : for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
98 0 : rk.push_back( thiskey );
99 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
100 0 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
101 0 : if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
102 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
103 0 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
104 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
105 0 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
106 0 : if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
107 0 : if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
108 : }
109 0 : for(unsigned i=0; i<cnames.size(); ++i) {
110 0 : std::string thisnam=cnames[i];
111 0 : for(unsigned j=0; j<cnam.size(); ++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
112 0 : cnam.push_back( thisnam );
113 0 : plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
114 0 : ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
115 0 : plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
116 0 : cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
117 : }
118 0 : }
119 :
120 261099 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
121 261099 : plumed_assert( !exists(k) && !reserved(k) );
122 261099 : std::string fd, lowkey=k;
123 : // Convert to lower case
124 2721375 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
125 : // Remove any underscore characters
126 : for(unsigned i=0;; ++i) {
127 412315 : std::size_t num=lowkey.find_first_of("_");
128 412315 : if( num==std::string::npos ) break;
129 151216 : lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
130 151216 : }
131 261099 : if( t=="vessel" ) {
132 0 : fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
133 0 : if(d.find("flag")==std::string::npos) fd += ". You can use multiple instances of this keyword i.e. " +
134 0 : k +"1, " + k + "2, " + k + "3... The corresponding values are then "
135 0 : "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey +
136 0 : "-2, <em>label</em>." + lowkey + "-3...";
137 0 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
138 0 : types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
139 261099 : } else if( t=="numbered" ) {
140 35876 : fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
141 17938 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
142 35876 : types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
143 : } else {
144 : fd = d;
145 244160 : if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
146 243161 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
147 486322 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
148 244160 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
149 : }
150 261099 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
151 261099 : reserved_keys.push_back(k);
152 261099 : }
153 :
154 1322 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
155 1322 : plumed_assert( !exists(k) && !reserved(k) );
156 : std::string defstr;
157 1322 : if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; }
158 2644 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
159 19563 : std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
160 1322 : fd=defstr + d;
161 2644 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
162 1322 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
163 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
164 1322 : reserved_keys.push_back(k);
165 1322 : }
166 :
167 44231 : void Keywords::use( const std::string & k ) {
168 44231 : plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
169 260528 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
170 216297 : if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] );
171 : }
172 44231 : }
173 :
174 7453 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
175 7453 : plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
176 7453 : if( style=="numbered" ) { allowmultiple[k]=true; return; }
177 922 : (types.find(k)->second).setStyle(style);
178 922 : if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true;
179 1384 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,style) );
180 : }
181 :
182 993228 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
183 2979684 : plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
184 : std::string fd;
185 993228 : if( t=="numbered" ) {
186 39480 : fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
187 19740 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
188 39480 : types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
189 : } else {
190 : fd=d;
191 973488 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
192 1946976 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
193 1191713 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
194 : }
195 1041410 : if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
196 993228 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
197 993228 : keys.push_back(k);
198 993228 : }
199 :
200 437216 : void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) {
201 874753 : plumed_assert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
202 437216 : types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) );
203 874432 : documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
204 437216 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
205 437216 : numdefs.insert( std::pair<std::string,std::string>(k,def) );
206 437216 : keys.push_back(k);
207 437216 : }
208 :
209 447049 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
210 447049 : plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
211 447049 : std::string defstr; plumed_massert( !def, "the second argument to addFlag must be false " + k );
212 : defstr="( default=off ) ";
213 894098 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
214 894098 : documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
215 447049 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
216 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
217 447049 : keys.push_back(k);
218 447049 : }
219 :
220 13978 : void Keywords::remove( const std::string & k ) {
221 : bool found=false; unsigned j=0, n=0;
222 :
223 : while(true) {
224 140421 : for(j=0; j<keys.size(); j++) if(keys[j]==k)break;
225 119600 : for(n=0; n<reserved_keys.size(); n++) if(reserved_keys[n]==k)break;
226 28955 : if(j<keys.size()) {
227 13783 : keys.erase(keys.begin()+j);
228 : found=true;
229 15172 : } else if(n<reserved_keys.size()) {
230 1194 : reserved_keys.erase(reserved_keys.begin()+n);
231 : found=true;
232 : } else break;
233 : }
234 : // Delete documentation, type and so on from the description
235 : types.erase(k); documentation.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k);
236 : // Remove any output comonents that this keyword creates
237 27781 : for(const auto& dkey : ckey ) {
238 13803 : if( dkey.second==k ) removeOutputComponent( dkey.first );
239 : }
240 13978 : plumed_massert(found,"You are trying to forbid " + k + " a keyword that isn't there"); // You have tried to forbid a keyword that isn't there
241 13978 : }
242 :
243 291825 : bool Keywords::numbered( const std::string & k ) const {
244 583650 : if( style( k,"atoms") ) return true;
245 0 : plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
246 247963 : return allowmultiple.find(k)->second;
247 : }
248 :
249 1813301 : bool Keywords::style( const std::string & k, const std::string & t ) const {
250 1813301 : if( getStyle(k)==t ) return true;
251 : return false;
252 : }
253 :
254 1302062 : unsigned Keywords::size() const {
255 1302062 : return keys.size();
256 : }
257 :
258 76929 : std::string Keywords::getKeyword( const unsigned i ) const {
259 76929 : plumed_assert( i<size() );
260 76929 : return keys[i];
261 : }
262 :
263 3276102 : bool Keywords::exists( const std::string & k ) const {
264 28660313 : for(unsigned i=0; i<keys.size(); ++i) {
265 26169449 : if( keys[i]==k ) return true;
266 : }
267 : return false;
268 : }
269 :
270 2184145 : bool Keywords::reserved( const std::string & k ) const {
271 4509454 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
272 2369540 : if( reserved_keys[i]==k ) return true;
273 : }
274 : return false;
275 : }
276 :
277 0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
278 : unsigned nkeys=0;
279 : std::printf("%s",actionname.c_str());
280 0 : for(unsigned i=0; i<keys.size(); ++i) {
281 0 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
282 : }
283 0 : if( nkeys>0 ) {
284 0 : std::string prevtag="start";
285 0 : for(unsigned i=0; i<keys.size(); ++i) {
286 0 : if( (types.find(keys[i])->second).isAtomList() ) {
287 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
288 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break;
289 0 : if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) std::printf(" %s=<residue selection>", keys[i].c_str() );
290 : else std::printf(" %s=<atom selection>", keys[i].c_str() );
291 0 : prevtag=atomtags.find(keys[i])->second;
292 : }
293 : }
294 : }
295 : nkeys=0;
296 0 : for(unsigned i=0; i<keys.size(); ++i) {
297 0 : if ( include_optional || \
298 0 : (types.find(keys[i])->second).isCompulsory() ) nkeys++;
299 : }
300 0 : if( nkeys>0 ) {
301 0 : for(unsigned i=0; i<keys.size(); ++i) {
302 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
303 : std::string def;
304 0 : if( getDefaultValue( keys[i], def) ) {
305 : std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
306 : } else {
307 : std::printf(" %s= ", keys[i].c_str() );
308 : }
309 0 : } else if (include_optional) {
310 : // TG no defaults for optional keywords?
311 : std::printf(" [%s]", keys[i].c_str() );
312 : }
313 : }
314 : }
315 : std::printf("\n");
316 : std::flush(std::cout);
317 0 : }
318 :
319 438 : void Keywords::print_vim() const {
320 5482 : for(unsigned i=0; i<keys.size(); ++i) {
321 5044 : if( (types.find(keys[i])->second).isFlag() ) {
322 : std::printf( ",flag:%s", keys[i].c_str() );
323 : } else {
324 4044 : if( allowmultiple.find(keys[i])->second ) std::printf(",numbered:%s",keys[i].c_str() );
325 : else std::printf(",option:%s",keys[i].c_str() );
326 : }
327 : }
328 438 : std::fprintf(stdout, "\n%s", getHelpString().c_str() );
329 438 : }
330 :
331 0 : void Keywords::print_html() const {
332 :
333 : // This is the part that outputs the details of the components
334 0 : if( cnames.size()>0 ) {
335 : unsigned ndef=0;
336 0 : for(unsigned i=0; i<cnames.size(); ++i) {
337 0 : if(ckey.find(cnames[i])->second=="default") ndef++;
338 : }
339 :
340 0 : if( ndef>0 ) {
341 0 : std::cout<<"\\par Description of components\n\n";
342 0 : std::cout<<cstring<<"\n\n";
343 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
344 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
345 : unsigned nndef=0;
346 0 : for(unsigned i=0; i<cnames.size(); ++i) {
347 : //plumed_assert( ckey.find(cnames[i])->second=="default" );
348 0 : if( ckey.find(cnames[i])->second!="default" ) { nndef++; continue; }
349 : std::printf("<tr>\n");
350 : std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
351 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
352 : std::printf("</tr>\n");
353 : }
354 0 : std::cout<<"</table>\n\n";
355 0 : if( nndef>0 ) {
356 0 : std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
357 0 : std::cout<<"\n\n";
358 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
359 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
360 0 : for(unsigned i=0; i<cnames.size(); ++i) {
361 0 : if( ckey.find(cnames[i])->second!="default") {
362 : std::printf("<tr>\n");
363 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
364 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
365 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
366 : std::printf("</tr>\n");
367 : }
368 : }
369 0 : std::cout<<"</table>\n\n";
370 : }
371 : } else {
372 : unsigned nregs=0;
373 0 : for(unsigned i=0; i<cnames.size(); ++i) {
374 0 : if( exists(ckey.find(cnames[i])->second) ) nregs++;
375 : }
376 0 : if( nregs>0 ) {
377 0 : std::cout<<"\\par Description of components\n\n";
378 0 : std::cout<<cstring<<"\n\n";
379 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
380 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
381 0 : for(unsigned i=0; i<cnames.size(); ++i) {
382 0 : if( exists(ckey.find(cnames[i])->second) ) {
383 : std::printf("<tr>\n");
384 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
385 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
386 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
387 : std::printf("</tr>\n");
388 : }
389 : }
390 0 : std::cout<<"</table>\n\n";
391 : }
392 : }
393 : }
394 :
395 : unsigned nkeys=0;
396 0 : for(unsigned i=0; i<keys.size(); ++i) {
397 0 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
398 : }
399 0 : if( nkeys>0 ) {
400 0 : if(isaction && isatoms) std::cout<<"\\par The atoms involved can be specified using\n\n";
401 0 : else if(isaction) std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
402 0 : else std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
403 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
404 0 : std::string prevtag="start"; unsigned counter=0;
405 0 : for(unsigned i=0; i<keys.size(); ++i) {
406 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
407 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
408 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
409 0 : std::cout<<"</table>\n\n";
410 0 : if( isatoms ) std::cout<<"\\par Or alternatively by using\n\n";
411 0 : else if( counter==0 ) { std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n"; counter++; }
412 0 : else std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
413 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
414 : }
415 0 : print_html_item( keys[i] );
416 0 : prevtag=atomtags.find(keys[i])->second;
417 : }
418 : }
419 0 : std::cout<<"</table>\n\n";
420 : }
421 : nkeys=0;
422 0 : for(unsigned i=0; i<keys.size(); ++i) {
423 0 : if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
424 : }
425 0 : if( nkeys>0 ) {
426 0 : if(isaction) std::cout<< "\\par Compulsory keywords\n\n";
427 0 : else std::cout<<"\\par The following must be present\n\n";
428 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
429 0 : for(unsigned i=0; i<keys.size(); ++i) {
430 0 : if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] );
431 : }
432 0 : std::cout<<"</table>\n\n";
433 : }
434 : nkeys=0;
435 0 : for(unsigned i=0; i<keys.size(); ++i) {
436 0 : if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
437 : }
438 0 : if( nkeys>0 ) {
439 0 : if(isaction) std::cout<<"\\par Options\n\n";
440 0 : else std::cout<<"\\par The following options are available\n\n";
441 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
442 0 : for(unsigned i=0; i<keys.size(); ++i) {
443 0 : if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] );
444 : }
445 0 : std::cout<<"\n";
446 : }
447 : nkeys=0;
448 0 : for(unsigned i=0; i<keys.size(); ++i) {
449 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
450 : }
451 0 : if( nkeys>0 ) {
452 0 : for(unsigned i=0; i<keys.size(); ++i) {
453 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] );
454 : }
455 : }
456 0 : std::cout<<"</table>\n\n";
457 0 : }
458 :
459 0 : void Keywords::print_spelling() const {
460 0 : for(unsigned i=0; i<keys.size(); ++i) std::printf("%s\n", keys[i].c_str() );
461 0 : for(unsigned i=0; i<cnames.size(); ++i) std::printf("%s\n",cnames[i].c_str() );
462 0 : }
463 :
464 7956 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
465 7956 : bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
466 7956 : std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
467 15912 : std::stringstream sstr; sstr<<std::setw(23)<<key<<" - ";
468 7956 : unsigned nl=0; std::string blank=" ";
469 190534 : for(unsigned i=0; i<w.size(); ++i) {
470 183064 : nl+=w[i].length() + 1;
471 183064 : if( nl>60 ) {
472 39774 : sstr<<"\n"<<std::setw(23)<<blank<<" "<<w[i]<<" "; nl=0;
473 169806 : } else sstr<<w[i]<<" ";
474 183064 : if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
475 : }
476 15912 : sstr<<"\n"; return sstr.str();
477 7956 : }
478 :
479 876 : std::string Keywords::getHelpString() const {
480 : std::string helpstr; unsigned nkeys=0;
481 10964 : for(unsigned i=0; i<keys.size(); ++i) {
482 10088 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
483 : }
484 876 : if( nkeys>0 ) {
485 : helpstr += "The input trajectory can be in any of the following formats: \n\n";
486 5124 : for(unsigned i=0; i<keys.size(); ++i) {
487 5480 : if ( (types.find(keys[i])->second).isAtomList() ) helpstr += getKeywordDocs( keys[i] );
488 : }
489 : }
490 : nkeys=0;
491 10964 : for(unsigned i=0; i<keys.size(); ++i) {
492 10088 : if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
493 : }
494 : unsigned ncompulsory=nkeys;
495 876 : if( nkeys>0 ) {
496 : helpstr += "\nThe following arguments are compulsory: \n\n";
497 8884 : for(unsigned i=0; i<keys.size(); ++i) {
498 10468 : if ( (types.find(keys[i])->second).isCompulsory() ) helpstr += getKeywordDocs( keys[i] );
499 : }
500 : }
501 : nkeys=0;
502 10964 : for(unsigned i=0; i<keys.size(); ++i) {
503 10088 : if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
504 : }
505 876 : if( nkeys>0 ) {
506 702 : if(ncompulsory>0) helpstr += "\nIn addition you may use the following options: \n\n";
507 : else helpstr += "\nThe following options are available\n\n";
508 9656 : for(unsigned i=0; i<keys.size(); ++i) {
509 10954 : if ( (types.find(keys[i])->second).isFlag() ) helpstr += getKeywordDocs( keys[i] ).c_str();
510 : }
511 : }
512 : nkeys=0;
513 10964 : for(unsigned i=0; i<keys.size(); ++i) {
514 17132 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
515 : }
516 876 : if( nkeys>0 ) {
517 9412 : for(unsigned i=0; i<keys.size(); ++i) {
518 17484 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) helpstr += getKeywordDocs( keys[i] );
519 : }
520 : helpstr += "\n";
521 : }
522 876 : return helpstr;
523 : }
524 :
525 0 : void Keywords::print( Log& log ) const {
526 0 : log.printf("%s", getHelpString().c_str() );
527 0 : }
528 :
529 0 : void Keywords::print( FILE* out ) const {
530 0 : fprintf( out,"%s", getHelpString().c_str() );
531 0 : }
532 :
533 0 : std::string Keywords::getTooltip( const std::string& name ) const {
534 0 : std::size_t dd=name.find_first_of("0123456789"); std::string kname=name.substr(0,dd);
535 0 : if( !exists(kname) ) return "<b> could not find this keyword </b>";
536 0 : std::string mystring, docstr = documentation.find(kname)->second;
537 0 : if( types.find(kname)->second.isCompulsory() ) {
538 : mystring += "<b>compulsory keyword ";
539 0 : if( docstr.find("default")!=std::string::npos ) {
540 0 : std::size_t bra = docstr.find_first_of(")"); mystring += docstr.substr(0,bra+1); docstr = docstr.substr(bra+1);
541 : }
542 : mystring += "</b>\n";
543 : }
544 0 : std::vector<std::string> w=Tools::getWords( docstr ); unsigned nl=0;
545 0 : for(unsigned i=0; i<w.size(); ++i) {
546 0 : nl+=w[i].length() + 1;
547 0 : if( nl>80 ) { mystring += w[i] + "\n"; nl=0; }
548 0 : else { mystring += w[i] + " "; }
549 0 : if( w[i].find(".")!=std::string::npos ) break; // Only write up the the first dot
550 : }
551 : return mystring;
552 0 : }
553 :
554 0 : void Keywords::print_html_item( const std::string& key ) const {
555 : std::printf("<tr>\n");
556 : std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
557 : std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
558 : std::printf("</tr>\n");
559 0 : }
560 :
561 553733 : std::string Keywords::get( const unsigned k ) const {
562 553733 : plumed_assert( k<size() );
563 553733 : return keys[k];
564 : }
565 :
566 84004 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
567 84004 : if( booldefs.find(key)!=booldefs.end() ) {
568 84004 : def=booldefs.find(key)->second;
569 84004 : return true;
570 : } else {
571 : return false;
572 : }
573 : }
574 :
575 25325 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
576 36645 : plumed_assert( style(key,"compulsory") || style(key,"hidden") );
577 :
578 25325 : if( numdefs.find(key)!=numdefs.end() ) {
579 19666 : def=numdefs.find(key)->second;
580 19666 : return true;
581 : } else {
582 : return false;
583 : }
584 : }
585 :
586 0 : void Keywords::destroyData() {
587 0 : keys.clear(); reserved_keys.clear(); types.clear();
588 : allowmultiple.clear(); documentation.clear();
589 : booldefs.clear(); numdefs.clear(); atomtags.clear();
590 : ckey.clear(); cdocs.clear(); ckey.clear();
591 0 : }
592 :
593 33273 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
594 33273 : cstring = instr;
595 33273 : }
596 :
597 134054 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
598 134054 : plumed_assert( !outputComponentExists(name) );
599 134054 : plumed_massert( name!=".#!value", name + " is reserved for storing description of value" );
600 134054 : plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
601 :
602 134054 : std::size_t num2=name.find_first_of("_");
603 134054 : if( num2!=std::string::npos ) {
604 650 : char uu = '_'; plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
605 650 : plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
606 : }
607 134054 : if( key=="default" ) {
608 : cstring = "By default this Action calculates the following quantities. These quantities can "
609 : "be referenced elsewhere in the input by using this Action's label followed by a "
610 100177 : "dot and the name of the quantity required from the list below.";
611 : }
612 :
613 134054 : ckey.insert( std::pair<std::string,std::string>(name,key) );
614 134054 : cdocs.insert( std::pair<std::string,std::string>(name,descr) );
615 134054 : cnames.push_back(name);
616 134054 : }
617 :
618 108 : void Keywords::removeOutputComponent( const std::string& name ) {
619 : unsigned j=0;
620 : while(true) {
621 762 : for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
622 216 : if(j<cnames.size()) cnames.erase(cnames.begin()+j);
623 : else break;
624 : }
625 : cdocs.erase(name);
626 108 : }
627 :
628 55050 : void Keywords::setValueDescription( const std::string& descr ) {
629 110100 : if( !outputComponentExists(".#!value") ) {
630 48063 : ckey.insert( std::pair<std::string,std::string>(".#!value","default") );
631 48063 : cdocs.insert( std::pair<std::string,std::string>(".#!value",descr) );
632 96126 : cnames.push_back(".#!value");
633 13974 : } else cdocs[".#!value"] = descr;
634 55050 : }
635 :
636 301237 : bool Keywords::outputComponentExists( const std::string& name ) const {
637 301237 : if( cstring.find("customize")!=std::string::npos ) return true;
638 :
639 : std::string sname;
640 296770 : std::size_t num=name.find_first_of("-");
641 296770 : std::size_t num2=name.find_last_of("_");
642 :
643 299284 : if( num2!=std::string::npos ) sname=name.substr(num2);
644 321241 : else if( num!=std::string::npos ) sname=name.substr(0,num);
645 : else sname=name;
646 :
647 1045571 : for(unsigned i=0; i<cnames.size(); ++i) {
648 862246 : if( sname==cnames[i] ) return true;
649 : }
650 : return false;
651 : }
652 :
653 58621 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
654 58621 : return ckey.find(name)->second;
655 : }
656 :
657 6007 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
658 6007 : std::string checkname = name; std::size_t hyp=name.find_first_of("-");
659 6009 : if( hyp!=std::string::npos ) checkname = name.substr(0,hyp);
660 :
661 : bool found=false;
662 21134 : for(unsigned i=0; i<cnames.size(); ++i) {
663 15127 : if( checkname==cnames[i] ) found=true;
664 : }
665 6007 : if( !found ) {
666 3 : if( name==".#!value" ) return "the value calculated by this action";
667 0 : if( outputComponentExists( name ) ) plumed_merror("cannot find description for component " + name + " that allegedly exists. Gareth Tribello might know what the fuck that is about.");
668 0 : plumed_merror("could not find output component named " + name );
669 : }
670 6004 : return cdocs.find(checkname)->second;
671 : }
672 :
673 0 : void Keywords::removeComponent( const std::string& name ) {
674 : bool found=false;
675 :
676 : while(true) {
677 : unsigned j;
678 0 : for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
679 0 : if(j<cnames.size()) {
680 0 : cnames.erase(cnames.begin()+j);
681 : found=true;
682 : } else break;
683 0 : }
684 : // Delete documentation, type and so on from the description
685 : cdocs.erase(name); ckey.erase(name);
686 0 : plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
687 0 : }
688 :
689 5698 : std::vector<std::string> Keywords::getOutputComponents() const {
690 5698 : return cnames;
691 : }
692 :
693 5044 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
694 10088 : plumed_assert( exists( key ) ); return documentation.find(key)->second;
695 : }
696 :
697 76774 : void Keywords::needsAction( const std::string& name ) {
698 76774 : if( std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end() ) return;
699 76127 : neededActions.push_back( name );
700 : }
701 :
702 560 : const std::vector<std::string>& Keywords::getNeededKeywords() const {
703 560 : return neededActions;
704 : }
705 :
706 44105 : void Keywords::addActionNameSuffix( const std::string& suffix ) {
707 44105 : if( std::find(actionNameSuffixes.begin(), actionNameSuffixes.end(), suffix )!=actionNameSuffixes.end() ) return;
708 44105 : actionNameSuffixes.push_back( suffix );
709 : }
710 :
711 32198 : void Keywords::setDisplayName( const std::string& name ) {
712 32198 : thisactname = name;
713 32198 : }
714 :
715 69490 : std::string Keywords::getDisplayName() const {
716 69490 : return thisactname;
717 : }
718 :
719 : }
|