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 2167718 : Keywords::KeyType::KeyType( const std::string& type ) {
31 2167718 : if( type=="compulsory" ) {
32 580669 : style=compulsory;
33 1587049 : } else if( type=="flag" ) {
34 453060 : style=flag;
35 1133989 : } else if( type=="optional" ) {
36 685586 : style=optional;
37 448403 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
38 222403 : style=atoms;
39 226000 : } else if( type=="hidden" ) {
40 226000 : 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 2167718 : }
47 :
48 987 : void Keywords::KeyType::setStyle( const std::string& type ) {
49 987 : if( type=="compulsory" ) {
50 439 : style=compulsory;
51 548 : } else if( type=="flag" ) {
52 0 : style=flag;
53 548 : } else if( type=="optional" ) {
54 25 : style=optional;
55 523 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
56 523 : 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 987 : }
65 :
66 1890167 : std::string Keywords::getStyle( const std::string & k ) const {
67 0 : plumed_massert( types.count(k), "Did not find keyword " + k );
68 1890167 : 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) {
82 0 : plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
83 : }
84 0 : for(unsigned j=0; j<rk.size(); ++j) {
85 0 : plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
86 : }
87 0 : kk.push_back( thiskey );
88 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
89 0 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
90 0 : if( (types.find(thiskey)->second).isAtomList() ) {
91 0 : atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
92 : }
93 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
94 0 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
95 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
96 0 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
97 : if( booldefs.count( thiskey ) ) {
98 0 : bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
99 : }
100 : if( numdefs.count( thiskey ) ) {
101 0 : nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
102 : }
103 : }
104 0 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
105 0 : std::string thiskey=reserved_keys[i];
106 0 : for(unsigned j=0; j<kk.size(); ++j) {
107 0 : plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
108 : }
109 0 : for(unsigned j=0; j<rk.size(); ++j) {
110 0 : plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
111 : }
112 0 : rk.push_back( thiskey );
113 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
114 0 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
115 0 : if( (types.find(thiskey)->second).isAtomList() ) {
116 0 : atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
117 : }
118 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
119 0 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
120 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
121 0 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
122 : if( booldefs.count( thiskey ) ) {
123 0 : bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
124 : }
125 : if( numdefs.count( thiskey ) ) {
126 0 : nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
127 : }
128 : }
129 0 : for(unsigned i=0; i<cnames.size(); ++i) {
130 0 : std::string thisnam=cnames[i];
131 0 : for(unsigned j=0; j<cnam.size(); ++j) {
132 0 : plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
133 : }
134 0 : cnam.push_back( thisnam );
135 0 : plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
136 0 : ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
137 0 : plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
138 0 : cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
139 : }
140 0 : }
141 :
142 260331 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
143 260331 : plumed_assert( !exists(k) && !reserved(k) );
144 260331 : std::string fd, lowkey=k;
145 : // Convert to lower case
146 260331 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
147 2450991 : return std::tolower(c);
148 : });
149 : // Remove any underscore characters
150 : for(unsigned i=0;; ++i) {
151 410845 : std::size_t num=lowkey.find_first_of("_");
152 410845 : if( num==std::string::npos ) {
153 : break;
154 : }
155 150514 : lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
156 150514 : }
157 260331 : if( t=="vessel" ) {
158 0 : fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
159 0 : if(d.find("flag")==std::string::npos)
160 0 : fd += ". You can use multiple instances of this keyword i.e. " +
161 0 : k +"1, " + k + "2, " + k + "3... The corresponding values are then "
162 0 : "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey +
163 0 : "-2, <em>label</em>." + lowkey + "-3...";
164 0 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
165 0 : types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
166 260331 : } else if( t=="numbered" ) {
167 36290 : fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
168 18145 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
169 36290 : types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
170 : } else {
171 : fd = d;
172 242186 : if( t=="atoms" && isaction ) {
173 1998 : fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
174 : }
175 242186 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
176 484372 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
177 242186 : if( (types.find(k)->second).isAtomList() ) {
178 1998 : atomtags.insert( std::pair<std::string,std::string>(k,t) );
179 : }
180 : }
181 260331 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
182 260331 : reserved_keys.push_back(k);
183 260331 : }
184 :
185 1322 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
186 1322 : plumed_assert( !exists(k) && !reserved(k) );
187 : std::string defstr;
188 1322 : if( def ) {
189 : defstr="( default=on ) ";
190 : } else {
191 : defstr="( default=off ) ";
192 : }
193 2644 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
194 1322 : std::string fd,lowkey=k;
195 1322 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
196 18241 : return std::tolower(c);
197 : });
198 1322 : fd=defstr + d;
199 2644 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
200 1322 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
201 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
202 1322 : reserved_keys.push_back(k);
203 1322 : }
204 :
205 44637 : void Keywords::use( const std::string & k ) {
206 44637 : plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
207 262586 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
208 217949 : if(reserved_keys[i]==k) {
209 44637 : keys.push_back( reserved_keys[i] );
210 : }
211 : }
212 44637 : }
213 :
214 7522 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
215 7522 : plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
216 7522 : if( style=="numbered" ) {
217 6535 : allowmultiple[k]=true;
218 6535 : return;
219 : }
220 987 : (types.find(k)->second).setStyle(style);
221 987 : if( (types.find(k)->second).isVessel() ) {
222 0 : allowmultiple[k]=true;
223 : }
224 987 : if( (types.find(k)->second).isAtomList() ) {
225 1046 : atomtags.insert( std::pair<std::string,std::string>(k,style) );
226 : }
227 : }
228 :
229 1007012 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
230 3021036 : plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
231 : std::string fd;
232 1007012 : if( t=="numbered" ) {
233 40188 : fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
234 20094 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
235 40188 : types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
236 : } else {
237 : fd=d;
238 986918 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
239 1973836 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
240 986918 : if( (types.find(k)->second).isAtomList() ) {
241 442808 : atomtags.insert( std::pair<std::string,std::string>(k,t) );
242 : }
243 : }
244 1007012 : if( t=="atoms" && isaction ) {
245 95296 : fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
246 : }
247 1007012 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
248 1007012 : keys.push_back(k);
249 1007012 : }
250 :
251 447315 : void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) {
252 894952 : plumed_assert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
253 447315 : types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) );
254 894630 : documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
255 447315 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
256 447315 : numdefs.insert( std::pair<std::string,std::string>(k,def) );
257 447315 : keys.push_back(k);
258 447315 : }
259 :
260 451738 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
261 451738 : plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
262 : std::string defstr;
263 451738 : plumed_massert( !def, "the second argument to addFlag must be false " + k );
264 : defstr="( default=off ) ";
265 903476 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
266 903476 : documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
267 451738 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
268 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
269 451738 : keys.push_back(k);
270 451738 : }
271 :
272 14282 : void Keywords::remove( const std::string & k ) {
273 : bool found=false;
274 : unsigned j=0, n=0;
275 :
276 : while(true) {
277 146059 : for(j=0; j<keys.size(); j++)
278 130583 : if(keys[j]==k) {
279 : break;
280 : }
281 122440 : for(n=0; n<reserved_keys.size(); n++)
282 95070 : if(reserved_keys[n]==k) {
283 : break;
284 : }
285 29563 : if(j<keys.size()) {
286 14087 : keys.erase(keys.begin()+j);
287 : found=true;
288 15476 : } else if(n<reserved_keys.size()) {
289 1194 : reserved_keys.erase(reserved_keys.begin()+n);
290 : found=true;
291 : } else {
292 : break;
293 : }
294 : }
295 : // Delete documentation, type and so on from the description
296 : types.erase(k);
297 : documentation.erase(k);
298 : allowmultiple.erase(k);
299 : booldefs.erase(k);
300 : numdefs.erase(k);
301 : // Remove any output comonents that this keyword creates
302 28505 : for(const auto& dkey : ckey ) {
303 14223 : if( dkey.second==k ) {
304 108 : removeOutputComponent( dkey.first );
305 : }
306 : }
307 14282 : 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
308 14282 : }
309 :
310 317731 : bool Keywords::numbered( const std::string & k ) const {
311 635462 : if( style( k,"atoms") ) {
312 : return true;
313 : }
314 0 : plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
315 273317 : return allowmultiple.find(k)->second;
316 : }
317 :
318 1885104 : bool Keywords::style( const std::string & k, const std::string & t ) const {
319 1885104 : if( getStyle(k)==t ) {
320 419808 : return true;
321 : }
322 : return false;
323 : }
324 :
325 1332388 : unsigned Keywords::size() const {
326 1332388 : return keys.size();
327 : }
328 :
329 77185 : std::string Keywords::getKeyword( const unsigned i ) const {
330 77185 : plumed_assert( i<size() );
331 77185 : return keys[i];
332 : }
333 :
334 3335446 : bool Keywords::exists( const std::string & k ) const {
335 29343177 : for(unsigned i=0; i<keys.size(); ++i) {
336 26827539 : if( keys[i]==k ) {
337 : return true;
338 : }
339 : }
340 : return false;
341 : }
342 :
343 2212355 : bool Keywords::reserved( const std::string & k ) const {
344 4541072 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
345 2373354 : if( reserved_keys[i]==k ) {
346 : return true;
347 : }
348 : }
349 : return false;
350 : }
351 :
352 0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
353 : unsigned nkeys=0;
354 : std::printf("%s",actionname.c_str());
355 0 : for(unsigned i=0; i<keys.size(); ++i) {
356 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
357 0 : nkeys++;
358 : }
359 : }
360 0 : if( nkeys>0 ) {
361 0 : std::string prevtag="start";
362 0 : for(unsigned i=0; i<keys.size(); ++i) {
363 0 : if( (types.find(keys[i])->second).isAtomList() ) {
364 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
365 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) {
366 : break;
367 : }
368 0 : if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) {
369 : std::printf(" %s=<residue selection>", keys[i].c_str() );
370 : } else {
371 : std::printf(" %s=<atom selection>", keys[i].c_str() );
372 : }
373 0 : prevtag=atomtags.find(keys[i])->second;
374 : }
375 : }
376 : }
377 : nkeys=0;
378 0 : for(unsigned i=0; i<keys.size(); ++i) {
379 0 : if ( include_optional || \
380 : (types.find(keys[i])->second).isCompulsory() ) {
381 0 : nkeys++;
382 : }
383 : }
384 0 : if( nkeys>0 ) {
385 0 : for(unsigned i=0; i<keys.size(); ++i) {
386 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
387 : std::string def;
388 0 : if( getDefaultValue( keys[i], def) ) {
389 : std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
390 : } else {
391 : std::printf(" %s= ", keys[i].c_str() );
392 : }
393 0 : } else if (include_optional) {
394 : // TG no defaults for optional keywords?
395 : std::printf(" [%s]", keys[i].c_str() );
396 : }
397 : }
398 : }
399 : std::printf("\n");
400 : std::flush(std::cout);
401 0 : }
402 :
403 439 : void Keywords::print_vim() const {
404 5502 : for(unsigned i=0; i<keys.size(); ++i) {
405 5063 : if( (types.find(keys[i])->second).isFlag() ) {
406 : std::printf( ",flag:%s", keys[i].c_str() );
407 : } else {
408 4061 : if( allowmultiple.find(keys[i])->second ) {
409 : std::printf(",numbered:%s",keys[i].c_str() );
410 : } else {
411 : std::printf(",option:%s",keys[i].c_str() );
412 : }
413 : }
414 : }
415 439 : std::fprintf(stdout, "\n%s", getHelpString().c_str() );
416 439 : }
417 :
418 0 : void Keywords::print_html() const {
419 :
420 : // This is the part that outputs the details of the components
421 0 : if( cnames.size()>0 ) {
422 : unsigned ndef=0;
423 0 : for(unsigned i=0; i<cnames.size(); ++i) {
424 0 : if(ckey.find(cnames[i])->second=="default") {
425 0 : ndef++;
426 : }
427 : }
428 :
429 0 : if( ndef>0 ) {
430 0 : std::cout<<"\\par Description of components\n\n";
431 0 : std::cout<<cstring<<"\n\n";
432 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
433 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
434 : unsigned nndef=0;
435 0 : for(unsigned i=0; i<cnames.size(); ++i) {
436 : //plumed_assert( ckey.find(cnames[i])->second=="default" );
437 0 : if( ckey.find(cnames[i])->second!="default" ) {
438 0 : nndef++;
439 0 : continue;
440 : }
441 : std::printf("<tr>\n");
442 : std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
443 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
444 : std::printf("</tr>\n");
445 : }
446 0 : std::cout<<"</table>\n\n";
447 0 : if( nndef>0 ) {
448 0 : std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
449 0 : std::cout<<"\n\n";
450 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
451 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
452 0 : for(unsigned i=0; i<cnames.size(); ++i) {
453 0 : if( ckey.find(cnames[i])->second!="default") {
454 : std::printf("<tr>\n");
455 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
456 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
457 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
458 : std::printf("</tr>\n");
459 : }
460 : }
461 0 : std::cout<<"</table>\n\n";
462 : }
463 : } else {
464 : unsigned nregs=0;
465 0 : for(unsigned i=0; i<cnames.size(); ++i) {
466 0 : if( exists(ckey.find(cnames[i])->second) ) {
467 0 : nregs++;
468 : }
469 : }
470 0 : if( nregs>0 ) {
471 0 : std::cout<<"\\par Description of components\n\n";
472 0 : std::cout<<cstring<<"\n\n";
473 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
474 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
475 0 : for(unsigned i=0; i<cnames.size(); ++i) {
476 0 : if( exists(ckey.find(cnames[i])->second) ) {
477 : std::printf("<tr>\n");
478 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
479 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
480 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
481 : std::printf("</tr>\n");
482 : }
483 : }
484 0 : std::cout<<"</table>\n\n";
485 : }
486 : }
487 : }
488 :
489 : unsigned nkeys=0;
490 0 : for(unsigned i=0; i<keys.size(); ++i) {
491 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
492 0 : nkeys++;
493 : }
494 : }
495 0 : if( nkeys>0 ) {
496 0 : if(isaction && isatoms) {
497 0 : std::cout<<"\\par The atoms involved can be specified using\n\n";
498 0 : } else if(isaction) {
499 0 : std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
500 : } else {
501 0 : std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
502 : }
503 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
504 0 : std::string prevtag="start";
505 : unsigned counter=0;
506 0 : for(unsigned i=0; i<keys.size(); ++i) {
507 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
508 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
509 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
510 0 : std::cout<<"</table>\n\n";
511 0 : if( isatoms ) {
512 0 : std::cout<<"\\par Or alternatively by using\n\n";
513 0 : } else if( counter==0 ) {
514 0 : std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n";
515 0 : counter++;
516 : } else {
517 0 : std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
518 : }
519 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
520 : }
521 0 : print_html_item( keys[i] );
522 0 : prevtag=atomtags.find(keys[i])->second;
523 : }
524 : }
525 0 : std::cout<<"</table>\n\n";
526 : }
527 : nkeys=0;
528 0 : for(unsigned i=0; i<keys.size(); ++i) {
529 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
530 0 : nkeys++;
531 : }
532 : }
533 0 : if( nkeys>0 ) {
534 0 : if(isaction) {
535 0 : std::cout<< "\\par Compulsory keywords\n\n";
536 : } else {
537 0 : std::cout<<"\\par The following must be present\n\n";
538 : }
539 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
540 0 : for(unsigned i=0; i<keys.size(); ++i) {
541 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
542 0 : print_html_item( keys[i] );
543 : }
544 : }
545 0 : std::cout<<"</table>\n\n";
546 : }
547 : nkeys=0;
548 0 : for(unsigned i=0; i<keys.size(); ++i) {
549 0 : if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
550 0 : nkeys++;
551 : }
552 : }
553 0 : if( nkeys>0 ) {
554 0 : if(isaction) {
555 0 : std::cout<<"\\par Options\n\n";
556 : } else {
557 0 : std::cout<<"\\par The following options are available\n\n";
558 : }
559 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
560 0 : for(unsigned i=0; i<keys.size(); ++i) {
561 0 : if ( (types.find(keys[i])->second).isFlag() ) {
562 0 : print_html_item( keys[i] );
563 : }
564 : }
565 0 : std::cout<<"\n";
566 : }
567 : nkeys=0;
568 0 : for(unsigned i=0; i<keys.size(); ++i) {
569 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
570 0 : nkeys++;
571 : }
572 : }
573 0 : if( nkeys>0 ) {
574 0 : for(unsigned i=0; i<keys.size(); ++i) {
575 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
576 0 : print_html_item( keys[i] );
577 : }
578 : }
579 : }
580 0 : std::cout<<"</table>\n\n";
581 0 : }
582 :
583 0 : void Keywords::print_spelling() const {
584 0 : for(unsigned i=0; i<keys.size(); ++i) {
585 : std::printf("%s\n", keys[i].c_str() );
586 : }
587 0 : for(unsigned i=0; i<cnames.size(); ++i) {
588 : std::printf("%s\n",cnames[i].c_str() );
589 : }
590 0 : }
591 :
592 7990 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
593 7990 : bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
594 7990 : std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
595 7990 : std::stringstream sstr;
596 7990 : sstr<<std::setw(23)<<key<<" - ";
597 : unsigned nl=0;
598 7990 : std::string blank=" ";
599 190988 : for(unsigned i=0; i<w.size(); ++i) {
600 183484 : nl+=w[i].length() + 1;
601 183484 : if( nl>60 ) {
602 39858 : sstr<<"\n"<<std::setw(23)<<blank<<" "<<w[i]<<" ";
603 : nl=0;
604 : } else {
605 170198 : sstr<<w[i]<<" ";
606 : }
607 183484 : if( killdot && w[i].find(".")!=std::string::npos ) {
608 : break; // If there is latex only write up to first dot
609 : }
610 : }
611 7990 : sstr<<"\n";
612 7990 : return sstr.str();
613 7990 : }
614 :
615 878 : std::string Keywords::getHelpString() const {
616 : std::string helpstr;
617 : unsigned nkeys=0;
618 11004 : for(unsigned i=0; i<keys.size(); ++i) {
619 10126 : if ( (types.find(keys[i])->second).isAtomList() ) {
620 670 : nkeys++;
621 : }
622 : }
623 878 : if( nkeys>0 ) {
624 : helpstr += "The input trajectory can be in any of the following formats: \n\n";
625 5160 : for(unsigned i=0; i<keys.size(); ++i) {
626 4846 : if ( (types.find(keys[i])->second).isAtomList() ) {
627 1340 : helpstr += getKeywordDocs( keys[i] );
628 : }
629 : }
630 : }
631 : nkeys=0;
632 11004 : for(unsigned i=0; i<keys.size(); ++i) {
633 10126 : if ( (types.find(keys[i])->second).isCompulsory() ) {
634 2250 : nkeys++;
635 : }
636 : }
637 : unsigned ncompulsory=nkeys;
638 878 : if( nkeys>0 ) {
639 : helpstr += "\nThe following arguments are compulsory: \n\n";
640 8924 : for(unsigned i=0; i<keys.size(); ++i) {
641 8262 : if ( (types.find(keys[i])->second).isCompulsory() ) {
642 4500 : helpstr += getKeywordDocs( keys[i] );
643 : }
644 : }
645 : }
646 : nkeys=0;
647 11004 : for(unsigned i=0; i<keys.size(); ++i) {
648 10126 : if ( (types.find(keys[i])->second).isFlag() ) {
649 2004 : nkeys++;
650 : }
651 : }
652 878 : if( nkeys>0 ) {
653 704 : if(ncompulsory>0) {
654 : helpstr += "\nIn addition you may use the following options: \n\n";
655 : } else {
656 : helpstr += "\nThe following options are available\n\n";
657 : }
658 9696 : for(unsigned i=0; i<keys.size(); ++i) {
659 8992 : if ( (types.find(keys[i])->second).isFlag() ) {
660 4008 : helpstr += getKeywordDocs( keys[i] ).c_str();
661 : }
662 : }
663 : }
664 : nkeys=0;
665 11004 : for(unsigned i=0; i<keys.size(); ++i) {
666 17186 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
667 3066 : nkeys++;
668 : }
669 : }
670 878 : if( nkeys>0 ) {
671 9452 : for(unsigned i=0; i<keys.size(); ++i) {
672 14494 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
673 6132 : helpstr += getKeywordDocs( keys[i] );
674 : }
675 : }
676 : helpstr += "\n";
677 : }
678 878 : return helpstr;
679 : }
680 :
681 0 : void Keywords::print( Log& log ) const {
682 0 : log.printf("%s", getHelpString().c_str() );
683 0 : }
684 :
685 0 : void Keywords::print( FILE* out ) const {
686 0 : fprintf( out,"%s", getHelpString().c_str() );
687 0 : }
688 :
689 0 : std::string Keywords::getTooltip( const std::string& name ) const {
690 0 : std::size_t dd=name.find_first_of("0123456789");
691 0 : std::string kname=name.substr(0,dd);
692 0 : if( !exists(kname) ) {
693 0 : return "<b> could not find this keyword </b>";
694 : }
695 0 : std::string mystring, docstr = documentation.find(kname)->second;
696 0 : if( types.find(kname)->second.isCompulsory() ) {
697 : mystring += "<b>compulsory keyword ";
698 0 : if( docstr.find("default")!=std::string::npos ) {
699 0 : std::size_t bra = docstr.find_first_of(")");
700 0 : mystring += docstr.substr(0,bra+1);
701 0 : docstr = docstr.substr(bra+1);
702 : }
703 : mystring += "</b>\n";
704 : }
705 0 : std::vector<std::string> w=Tools::getWords( docstr );
706 : unsigned nl=0;
707 0 : for(unsigned i=0; i<w.size(); ++i) {
708 0 : nl+=w[i].length() + 1;
709 0 : if( nl>80 ) {
710 0 : mystring += w[i] + "\n";
711 : nl=0;
712 : } else {
713 0 : mystring += w[i] + " ";
714 : }
715 0 : if( w[i].find(".")!=std::string::npos ) {
716 : break; // Only write up the the first dot
717 : }
718 : }
719 : return mystring;
720 0 : }
721 :
722 0 : void Keywords::print_html_item( const std::string& key ) const {
723 : std::printf("<tr>\n");
724 : std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
725 : std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
726 : std::printf("</tr>\n");
727 0 : }
728 :
729 568609 : std::string Keywords::get( const unsigned k ) const {
730 568609 : plumed_assert( k<size() );
731 568609 : return keys[k];
732 : }
733 :
734 83665 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
735 83665 : if( booldefs.find(key)!=booldefs.end() ) {
736 83665 : def=booldefs.find(key)->second;
737 83665 : return true;
738 : } else {
739 : return false;
740 : }
741 : }
742 :
743 26103 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
744 37783 : plumed_assert( style(key,"compulsory") || style(key,"hidden") );
745 :
746 26103 : if( numdefs.find(key)!=numdefs.end() ) {
747 20264 : def=numdefs.find(key)->second;
748 20264 : return true;
749 : } else {
750 : return false;
751 : }
752 : }
753 :
754 0 : void Keywords::destroyData() {
755 0 : keys.clear();
756 0 : reserved_keys.clear();
757 : types.clear();
758 : allowmultiple.clear();
759 : documentation.clear();
760 : booldefs.clear();
761 : numdefs.clear();
762 : atomtags.clear();
763 : ckey.clear();
764 : cdocs.clear();
765 : ckey.clear();
766 0 : }
767 :
768 33634 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
769 33634 : cstring = instr;
770 33634 : }
771 :
772 131915 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
773 131915 : plumed_assert( !outputComponentExists(name) );
774 131915 : plumed_massert( name!=".#!value", name + " is reserved for storing description of value" );
775 131915 : plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
776 :
777 131915 : std::size_t num2=name.find_first_of("_");
778 131915 : if( num2!=std::string::npos ) {
779 662 : char uu = '_';
780 662 : plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
781 662 : plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
782 : }
783 131915 : if( key=="default" ) {
784 : cstring = "By default this Action calculates the following quantities. These quantities can "
785 : "be referenced elsewhere in the input by using this Action's label followed by a "
786 97671 : "dot and the name of the quantity required from the list below.";
787 : }
788 :
789 131915 : ckey.insert( std::pair<std::string,std::string>(name,key) );
790 131915 : cdocs.insert( std::pair<std::string,std::string>(name,descr) );
791 131915 : cnames.push_back(name);
792 131915 : }
793 :
794 108 : void Keywords::removeOutputComponent( const std::string& name ) {
795 : unsigned j=0;
796 : while(true) {
797 762 : for(j=0; j<cnames.size(); j++)
798 654 : if(cnames[j]==name) {
799 : break;
800 : }
801 216 : if(j<cnames.size()) {
802 108 : cnames.erase(cnames.begin()+j);
803 : } else {
804 : break;
805 : }
806 : }
807 : cdocs.erase(name);
808 108 : }
809 :
810 55090 : void Keywords::setValueDescription( const std::string& descr ) {
811 110180 : if( !outputComponentExists(".#!value") ) {
812 48065 : ckey.insert( std::pair<std::string,std::string>(".#!value","default") );
813 48065 : cdocs.insert( std::pair<std::string,std::string>(".#!value",descr) );
814 96130 : cnames.push_back(".#!value");
815 : } else {
816 14050 : cdocs[".#!value"] = descr;
817 : }
818 55090 : }
819 :
820 298396 : bool Keywords::outputComponentExists( const std::string& name ) const {
821 298396 : if( cstring.find("customize")!=std::string::npos ) {
822 : return true;
823 : }
824 :
825 : std::string sname;
826 293929 : std::size_t num=name.find_first_of("-");
827 293929 : std::size_t num2=name.find_last_of("_");
828 :
829 293929 : if( num2!=std::string::npos ) {
830 5076 : sname=name.substr(num2);
831 291391 : } else if( num!=std::string::npos ) {
832 54492 : sname=name.substr(0,num);
833 : } else {
834 : sname=name;
835 : }
836 :
837 1041001 : for(unsigned i=0; i<cnames.size(); ++i) {
838 859806 : if( sname==cnames[i] ) {
839 : return true;
840 : }
841 : }
842 : return false;
843 : }
844 :
845 51055 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
846 51055 : return ckey.find(name)->second;
847 : }
848 :
849 6020 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
850 6020 : std::string checkname = name;
851 6020 : std::size_t hyp=name.find_first_of("-");
852 6020 : if( hyp!=std::string::npos ) {
853 4 : checkname = name.substr(0,hyp);
854 : }
855 :
856 : bool found=false;
857 21160 : for(unsigned i=0; i<cnames.size(); ++i) {
858 15140 : if( checkname==cnames[i] ) {
859 : found=true;
860 : }
861 : }
862 6020 : if( !found ) {
863 3 : if( name==".#!value" ) {
864 3 : return "the value calculated by this action";
865 : }
866 0 : if( outputComponentExists( name ) ) {
867 0 : plumed_merror("cannot find description for component " + name + " that allegedly exists. Gareth Tribello might know what the fuck that is about.");
868 : }
869 0 : plumed_merror("could not find output component named " + name );
870 : }
871 6017 : return cdocs.find(checkname)->second;
872 : }
873 :
874 0 : void Keywords::removeComponent( const std::string& name ) {
875 : bool found=false;
876 :
877 : while(true) {
878 : unsigned j;
879 0 : for(j=0; j<cnames.size(); j++)
880 0 : if(cnames[j]==name) {
881 : break;
882 : }
883 0 : if(j<cnames.size()) {
884 0 : cnames.erase(cnames.begin()+j);
885 : found=true;
886 : } else {
887 : break;
888 : }
889 0 : }
890 : // Delete documentation, type and so on from the description
891 : cdocs.erase(name);
892 : ckey.erase(name);
893 0 : plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
894 0 : }
895 :
896 5750 : std::vector<std::string> Keywords::getOutputComponents() const {
897 5750 : return cnames;
898 : }
899 :
900 5063 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
901 5063 : plumed_assert( exists( key ) );
902 5063 : return documentation.find(key)->second;
903 : }
904 :
905 74854 : void Keywords::needsAction( const std::string& name ) {
906 74854 : if( std::find(neededActions.begin(), neededActions.end(), name )!=neededActions.end() ) {
907 : return;
908 : }
909 74207 : neededActions.push_back( name );
910 : }
911 :
912 561 : const std::vector<std::string>& Keywords::getNeededKeywords() const {
913 561 : return neededActions;
914 : }
915 :
916 43961 : void Keywords::addActionNameSuffix( const std::string& suffix ) {
917 43961 : if( std::find(actionNameSuffixes.begin(), actionNameSuffixes.end(), suffix )!=actionNameSuffixes.end() ) {
918 : return;
919 : }
920 43961 : actionNameSuffixes.push_back( suffix );
921 : }
922 :
923 31668 : void Keywords::setDisplayName( const std::string& name ) {
924 31668 : thisactname = name;
925 31668 : }
926 :
927 68808 : std::string Keywords::getDisplayName() const {
928 68808 : return thisactname;
929 : }
930 :
931 : }
|