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 1222984 : Keywords::KeyType::KeyType( const std::string& type ) {
31 1222984 : if( type=="compulsory" ) {
32 328711 : style=compulsory;
33 894273 : } else if( type=="flag" ) {
34 242955 : style=flag;
35 651318 : } else if( type=="optional" ) {
36 342211 : style=optional;
37 309107 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
38 157623 : style=atoms;
39 151484 : } else if( type=="hidden" ) {
40 73369 : style=hidden;
41 78115 : } else if( type=="vessel" ) {
42 78115 : style=vessel;
43 : } else {
44 0 : plumed_massert(false,"invalid keyword specifier " + type);
45 : }
46 1222984 : }
47 :
48 5295 : void Keywords::KeyType::setStyle( const std::string& type ) {
49 5295 : if( type=="compulsory" ) {
50 123 : style=compulsory;
51 5172 : } else if( type=="flag" ) {
52 0 : style=flag;
53 5172 : } else if( type=="optional" ) {
54 40 : style=optional;
55 5132 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
56 348 : style=atoms;
57 4784 : } else if( type=="hidden" ) {
58 189 : style=hidden;
59 4595 : } else if( type=="vessel" ) {
60 4595 : style=vessel;
61 : } else {
62 0 : plumed_massert(false,"invalid keyword specifier " + type);
63 : }
64 5295 : }
65 :
66 875721 : std::string Keywords::getStyle( const std::string & k ) const {
67 0 : plumed_massert( types.count(k), "Did not find keyword " + k );
68 875721 : return (types.find(k)->second).toString();
69 : }
70 :
71 1040 : void Keywords::add( const Keywords& newkeys ) {
72 1040 : newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs );
73 1040 : }
74 :
75 1040 : 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 1040 : 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 19760 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
105 18720 : std::string thiskey=reserved_keys[i];
106 185706 : for(unsigned j=0; j<kk.size(); ++j) {
107 166986 : plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
108 : }
109 259542 : for(unsigned j=0; j<rk.size(); ++j) {
110 240822 : plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
111 : }
112 18720 : rk.push_back( thiskey );
113 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
114 18720 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
115 18720 : 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 18720 : 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 37440 : 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 19760 : for(unsigned i=0; i<cnames.size(); ++i) {
130 18720 : std::string thisnam=cnames[i];
131 177840 : for(unsigned j=0; j<cnam.size(); ++j) {
132 159120 : plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
133 : }
134 18720 : cnam.push_back( thisnam );
135 0 : plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
136 37440 : 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 37440 : cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
139 : }
140 1040 : }
141 :
142 138524 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
143 138524 : plumed_assert( !exists(k) && !reserved(k) );
144 138524 : std::string fd, lowkey=k;
145 : // Convert to lower case
146 138524 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
147 1029202 : return std::tolower(c);
148 : });
149 : // Remove any underscore characters
150 : for(unsigned i=0;; ++i) {
151 186816 : std::size_t num=lowkey.find_first_of("_");
152 186816 : if( num==std::string::npos ) {
153 : break;
154 : }
155 48292 : lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
156 48292 : }
157 138524 : if( t=="vessel" ) {
158 156230 : fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
159 78115 : if(d.find("flag")==std::string::npos)
160 137850 : fd += ". You can use multiple instances of this keyword i.e. " +
161 137850 : k +"1, " + k + "2, " + k + "3... The corresponding values are then "
162 137850 : "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey +
163 137850 : "-2, <em>label</em>." + lowkey + "-3...";
164 78115 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
165 156230 : types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
166 60409 : } else if( t=="numbered" ) {
167 7006 : fd = d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
168 3503 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
169 7006 : types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
170 : } else {
171 : fd = d;
172 56906 : if( t=="atoms" && isaction ) {
173 0 : fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
174 : }
175 56906 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
176 113812 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
177 56906 : if( (types.find(k)->second).isAtomList() ) {
178 3906 : atomtags.insert( std::pair<std::string,std::string>(k,t) );
179 : }
180 : }
181 138524 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
182 138524 : reserved_keys.push_back(k);
183 138524 : }
184 :
185 2464 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
186 2464 : plumed_assert( !exists(k) && !reserved(k) );
187 : std::string defstr;
188 2464 : if( def ) {
189 : defstr="( default=on ) ";
190 : } else {
191 : defstr="( default=off ) ";
192 : }
193 4928 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
194 2464 : std::string fd,lowkey=k;
195 2464 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) {
196 26925 : return std::tolower(c);
197 : });
198 2464 : fd=defstr + d;
199 4928 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
200 2464 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
201 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
202 2464 : reserved_keys.push_back(k);
203 2464 : }
204 :
205 17719 : void Keywords::use( const std::string & k ) {
206 17719 : plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
207 237781 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
208 220062 : if(reserved_keys[i]==k) {
209 17719 : keys.push_back( reserved_keys[i] );
210 : }
211 : }
212 17719 : }
213 :
214 5295 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
215 5295 : plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
216 5295 : (types.find(k)->second).setStyle(style);
217 5295 : if( (types.find(k)->second).isVessel() ) {
218 4595 : allowmultiple[k]=true;
219 : }
220 5295 : if( (types.find(k)->second).isAtomList() ) {
221 696 : atomtags.insert( std::pair<std::string,std::string>(k,style) );
222 : }
223 5295 : }
224 :
225 586519 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
226 1759557 : plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
227 : std::string fd;
228 586519 : if( t=="numbered" ) {
229 3630 : fd=d + ". You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
230 1815 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
231 3630 : types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
232 : } else {
233 : fd=d;
234 584704 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
235 1169408 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
236 584704 : if( (types.find(k)->second).isAtomList() ) {
237 311340 : atomtags.insert( std::pair<std::string,std::string>(k,t) );
238 : }
239 : }
240 586519 : if( t=="atoms" && isaction ) {
241 37570 : fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
242 : }
243 586519 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
244 586519 : keys.push_back(k);
245 586519 : }
246 :
247 254986 : void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) {
248 509972 : plumed_assert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
249 254986 : types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) );
250 509972 : documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
251 254986 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
252 254986 : numdefs.insert( std::pair<std::string,std::string>(k,def) );
253 254986 : keys.push_back(k);
254 254986 : }
255 :
256 240491 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
257 240491 : plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
258 : std::string defstr;
259 240491 : plumed_massert( !def, "the second argument to addFlag must be false " + k );
260 : defstr="( default=off ) ";
261 480982 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
262 480982 : documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
263 240491 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
264 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
265 240491 : keys.push_back(k);
266 240491 : }
267 :
268 1894 : void Keywords::remove( const std::string & k ) {
269 : bool found=false;
270 : unsigned j=0, n=0;
271 :
272 : while(true) {
273 22014 : for(j=0; j<keys.size(); j++)
274 20008 : if(keys[j]==k) {
275 : break;
276 : }
277 46612 : for(n=0; n<reserved_keys.size(); n++)
278 42936 : if(reserved_keys[n]==k) {
279 : break;
280 : }
281 3788 : if(j<keys.size()) {
282 1782 : keys.erase(keys.begin()+j);
283 : found=true;
284 2006 : } else if(n<reserved_keys.size()) {
285 112 : reserved_keys.erase(reserved_keys.begin()+n);
286 : found=true;
287 : } else {
288 : break;
289 : }
290 : }
291 : // Delete documentation, type and so on from the description
292 : types.erase(k);
293 : documentation.erase(k);
294 : allowmultiple.erase(k);
295 : booldefs.erase(k);
296 : numdefs.erase(k);
297 1894 : 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
298 1894 : }
299 :
300 18555 : bool Keywords::numbered( const std::string & k ) const {
301 37110 : if( style( k,"atoms") ) {
302 : return true;
303 : }
304 0 : plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
305 15505 : return allowmultiple.find(k)->second;
306 : }
307 :
308 866731 : bool Keywords::style( const std::string & k, const std::string & t ) const {
309 866731 : if( getStyle(k)==t ) {
310 222896 : return true;
311 : }
312 : return false;
313 : }
314 :
315 990301 : unsigned Keywords::size() const {
316 990301 : return keys.size();
317 : }
318 :
319 46111 : std::string Keywords::getKeyword( const unsigned i ) const {
320 46111 : plumed_assert( i<size() );
321 46111 : return keys[i];
322 : }
323 :
324 1516414 : bool Keywords::exists( const std::string & k ) const {
325 16443546 : for(unsigned i=0; i<keys.size(); ++i) {
326 15173336 : if( keys[i]==k ) {
327 : return true;
328 : }
329 : }
330 : return false;
331 : }
332 :
333 1245466 : bool Keywords::reserved( const std::string & k ) const {
334 2881641 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
335 1658657 : if( reserved_keys[i]==k ) {
336 : return true;
337 : }
338 : }
339 : return false;
340 : }
341 :
342 0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
343 : unsigned nkeys=0;
344 : std::printf("%s",actionname.c_str());
345 0 : for(unsigned i=0; i<keys.size(); ++i) {
346 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
347 0 : nkeys++;
348 : }
349 : }
350 0 : if( nkeys>0 ) {
351 0 : std::string prevtag="start";
352 0 : for(unsigned i=0; i<keys.size(); ++i) {
353 0 : if( (types.find(keys[i])->second).isAtomList() ) {
354 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
355 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) {
356 : break;
357 : }
358 0 : if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) {
359 : std::printf(" %s=<residue selection>", keys[i].c_str() );
360 : } else {
361 : std::printf(" %s=<atom selection>", keys[i].c_str() );
362 : }
363 0 : prevtag=atomtags.find(keys[i])->second;
364 : }
365 : }
366 : }
367 : nkeys=0;
368 0 : for(unsigned i=0; i<keys.size(); ++i) {
369 0 : if ( include_optional || \
370 : (types.find(keys[i])->second).isCompulsory() ) {
371 0 : nkeys++;
372 : }
373 : }
374 0 : if( nkeys>0 ) {
375 0 : for(unsigned i=0; i<keys.size(); ++i) {
376 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
377 : std::string def;
378 0 : if( getDefaultValue( keys[i], def) ) {
379 : std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
380 : } else {
381 : std::printf(" %s= ", keys[i].c_str() );
382 : }
383 0 : } else if (include_optional) {
384 : // TG no defaults for optional keywords?
385 : std::printf(" [%s]", keys[i].c_str() );
386 : }
387 : }
388 : }
389 : std::printf("\n");
390 : std::flush(std::cout);
391 0 : }
392 :
393 584 : void Keywords::print_vim() const {
394 9574 : for(unsigned i=0; i<keys.size(); ++i) {
395 8990 : if( (types.find(keys[i])->second).isFlag() ) {
396 : std::printf( ",flag:%s", keys[i].c_str() );
397 : } else {
398 7088 : if( allowmultiple.find(keys[i])->second ) {
399 : std::printf(",numbered:%s",keys[i].c_str() );
400 : } else {
401 : std::printf(",option:%s",keys[i].c_str() );
402 : }
403 : }
404 : }
405 584 : std::fprintf(stdout, "\n%s", getHelpString().c_str() );
406 584 : }
407 :
408 0 : void Keywords::print_html() const {
409 :
410 : // This is the part that outputs the details of the components
411 0 : if( cnames.size()>0 ) {
412 : unsigned ndef=0;
413 0 : for(unsigned i=0; i<cnames.size(); ++i) {
414 0 : if(ckey.find(cnames[i])->second=="default") {
415 0 : ndef++;
416 : }
417 : }
418 :
419 0 : if( ndef>0 ) {
420 0 : std::cout<<"\\par Description of components\n\n";
421 0 : std::cout<<cstring<<"\n\n";
422 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
423 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
424 : unsigned nndef=0;
425 0 : for(unsigned i=0; i<cnames.size(); ++i) {
426 : //plumed_assert( ckey.find(cnames[i])->second=="default" );
427 0 : if( ckey.find(cnames[i])->second!="default" ) {
428 0 : nndef++;
429 0 : continue;
430 : }
431 : std::printf("<tr>\n");
432 : std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
433 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
434 : std::printf("</tr>\n");
435 : }
436 0 : std::cout<<"</table>\n\n";
437 0 : if( nndef>0 ) {
438 0 : std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
439 0 : std::cout<<"\n\n";
440 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
441 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
442 0 : for(unsigned i=0; i<cnames.size(); ++i) {
443 0 : if( ckey.find(cnames[i])->second!="default") {
444 : std::printf("<tr>\n");
445 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
446 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
447 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
448 : std::printf("</tr>\n");
449 : }
450 : }
451 0 : std::cout<<"</table>\n\n";
452 : }
453 : } else {
454 : unsigned nregs=0;
455 0 : for(unsigned i=0; i<cnames.size(); ++i) {
456 0 : if( exists(ckey.find(cnames[i])->second) ) {
457 0 : nregs++;
458 : }
459 : }
460 0 : if( nregs>0 ) {
461 0 : std::cout<<"\\par Description of components\n\n";
462 0 : std::cout<<cstring<<"\n\n";
463 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
464 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
465 0 : for(unsigned i=0; i<cnames.size(); ++i) {
466 0 : if( exists(ckey.find(cnames[i])->second) ) {
467 : std::printf("<tr>\n");
468 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
469 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
470 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
471 : std::printf("</tr>\n");
472 : }
473 : }
474 0 : std::cout<<"</table>\n\n";
475 : }
476 : }
477 : }
478 :
479 : unsigned nkeys=0;
480 0 : for(unsigned i=0; i<keys.size(); ++i) {
481 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
482 0 : nkeys++;
483 : }
484 : }
485 0 : if( nkeys>0 ) {
486 0 : if(isaction && isatoms) {
487 0 : std::cout<<"\\par The atoms involved can be specified using\n\n";
488 0 : } else if(isaction) {
489 0 : std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
490 : } else {
491 0 : std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
492 : }
493 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
494 0 : std::string prevtag="start";
495 : unsigned counter=0;
496 0 : for(unsigned i=0; i<keys.size(); ++i) {
497 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
498 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
499 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
500 0 : std::cout<<"</table>\n\n";
501 0 : if( isatoms ) {
502 0 : std::cout<<"\\par Or alternatively by using\n\n";
503 0 : } else if( counter==0 ) {
504 0 : std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n";
505 0 : counter++;
506 : } else {
507 0 : std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
508 : }
509 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
510 : }
511 0 : print_html_item( keys[i] );
512 0 : prevtag=atomtags.find(keys[i])->second;
513 : }
514 : }
515 0 : std::cout<<"</table>\n\n";
516 : }
517 : nkeys=0;
518 0 : for(unsigned i=0; i<keys.size(); ++i) {
519 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
520 0 : nkeys++;
521 : }
522 : }
523 0 : if( nkeys>0 ) {
524 0 : if(isaction) {
525 0 : std::cout<< "\\par Compulsory keywords\n\n";
526 : } else {
527 0 : std::cout<<"\\par The following must be present\n\n";
528 : }
529 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
530 0 : for(unsigned i=0; i<keys.size(); ++i) {
531 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
532 0 : print_html_item( keys[i] );
533 : }
534 : }
535 0 : std::cout<<"</table>\n\n";
536 : }
537 : nkeys=0;
538 0 : for(unsigned i=0; i<keys.size(); ++i) {
539 0 : if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
540 0 : nkeys++;
541 : }
542 : }
543 0 : if( nkeys>0 ) {
544 0 : if(isaction) {
545 0 : std::cout<<"\\par Options\n\n";
546 : } else {
547 0 : std::cout<<"\\par The following options are available\n\n";
548 : }
549 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
550 0 : for(unsigned i=0; i<keys.size(); ++i) {
551 0 : if ( (types.find(keys[i])->second).isFlag() ) {
552 0 : print_html_item( keys[i] );
553 : }
554 : }
555 0 : std::cout<<"\n";
556 : }
557 : nkeys=0;
558 0 : for(unsigned i=0; i<keys.size(); ++i) {
559 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
560 0 : nkeys++;
561 : }
562 : }
563 0 : if( nkeys>0 ) {
564 0 : for(unsigned i=0; i<keys.size(); ++i) {
565 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
566 0 : print_html_item( keys[i] );
567 : }
568 : }
569 : }
570 0 : std::cout<<"</table>\n\n";
571 0 : }
572 :
573 0 : void Keywords::print_spelling() const {
574 0 : for(unsigned i=0; i<keys.size(); ++i) {
575 : std::printf("%s\n", keys[i].c_str() );
576 : }
577 0 : for(unsigned i=0; i<cnames.size(); ++i) {
578 : std::printf("%s\n",cnames[i].c_str() );
579 : }
580 0 : }
581 :
582 14164 : std::string Keywords::getKeywordDocs( const std::string& key ) const {
583 14164 : bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
584 14164 : std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
585 14164 : std::stringstream sstr;
586 14164 : sstr<<std::setw(23)<<key<<" - ";
587 : unsigned nl=0;
588 14164 : std::string blank=" ";
589 300460 : for(unsigned i=0; i<w.size(); ++i) {
590 287372 : nl+=w[i].length() + 1;
591 287372 : if( nl>60 ) {
592 66336 : sstr<<"\n"<<std::setw(23)<<blank<<" "<<w[i]<<" ";
593 : nl=0;
594 : } else {
595 265260 : sstr<<w[i]<<" ";
596 : }
597 287372 : if( killdot && w[i].find(".")!=std::string::npos ) {
598 : break; // If there is latex only write up to first dot
599 : }
600 : }
601 14164 : sstr<<"\n";
602 14164 : return sstr.str();
603 14164 : }
604 :
605 1168 : std::string Keywords::getHelpString() const {
606 : std::string helpstr;
607 : unsigned nkeys=0;
608 19148 : for(unsigned i=0; i<keys.size(); ++i) {
609 17980 : if ( (types.find(keys[i])->second).isAtomList() ) {
610 1080 : nkeys++;
611 : }
612 : }
613 1168 : if( nkeys>0 ) {
614 : helpstr += "The input trajectory can be in any of the following formats: \n\n";
615 10540 : for(unsigned i=0; i<keys.size(); ++i) {
616 10020 : if ( (types.find(keys[i])->second).isAtomList() ) {
617 2160 : helpstr += getKeywordDocs( keys[i] );
618 : }
619 : }
620 : }
621 : nkeys=0;
622 19148 : for(unsigned i=0; i<keys.size(); ++i) {
623 17980 : if ( (types.find(keys[i])->second).isCompulsory() ) {
624 3516 : nkeys++;
625 : }
626 : }
627 : unsigned ncompulsory=nkeys;
628 1168 : if( nkeys>0 ) {
629 : helpstr += "\nThe following arguments are compulsory: \n\n";
630 15684 : for(unsigned i=0; i<keys.size(); ++i) {
631 14756 : if ( (types.find(keys[i])->second).isCompulsory() ) {
632 7032 : helpstr += getKeywordDocs( keys[i] );
633 : }
634 : }
635 : }
636 : nkeys=0;
637 19148 : for(unsigned i=0; i<keys.size(); ++i) {
638 17980 : if ( (types.find(keys[i])->second).isFlag() ) {
639 3804 : nkeys++;
640 : }
641 : }
642 1168 : if( nkeys>0 ) {
643 1036 : if(ncompulsory>0) {
644 : helpstr += "\nIn addition you may use the following options: \n\n";
645 : } else {
646 : helpstr += "\nThe following options are available\n\n";
647 : }
648 18288 : for(unsigned i=0; i<keys.size(); ++i) {
649 17252 : if ( (types.find(keys[i])->second).isFlag() ) {
650 7608 : helpstr += getKeywordDocs( keys[i] ).c_str();
651 : }
652 : }
653 : }
654 : nkeys=0;
655 19148 : for(unsigned i=0; i<keys.size(); ++i) {
656 32304 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
657 5764 : nkeys++;
658 : }
659 : }
660 1168 : if( nkeys>0 ) {
661 16672 : for(unsigned i=0; i<keys.size(); ++i) {
662 27912 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) {
663 11528 : helpstr += getKeywordDocs( keys[i] );
664 : }
665 : }
666 : helpstr += "\n";
667 : }
668 1168 : return helpstr;
669 : }
670 :
671 0 : void Keywords::print( Log& log ) const {
672 0 : log.printf("%s", getHelpString().c_str() );
673 0 : }
674 :
675 0 : void Keywords::print( FILE* out ) const {
676 0 : fprintf( out,"%s", getHelpString().c_str() );
677 0 : }
678 :
679 0 : std::string Keywords::getTooltip( const std::string& name ) const {
680 0 : std::size_t dd=name.find_first_of("0123456789");
681 0 : std::string kname=name.substr(0,dd);
682 0 : if( !exists(kname) ) {
683 0 : return "<b> could not find this keyword </b>";
684 : }
685 0 : std::string mystring, docstr = documentation.find(kname)->second;
686 0 : if( types.find(kname)->second.isCompulsory() ) {
687 : mystring += "<b>compulsory keyword ";
688 0 : if( docstr.find("default")!=std::string::npos ) {
689 0 : std::size_t bra = docstr.find_first_of(")");
690 0 : mystring += docstr.substr(0,bra+1);
691 0 : docstr = docstr.substr(bra+1);
692 : }
693 : mystring += "</b>\n";
694 : }
695 0 : std::vector<std::string> w=Tools::getWords( docstr );
696 : unsigned nl=0;
697 0 : for(unsigned i=0; i<w.size(); ++i) {
698 0 : nl+=w[i].length() + 1;
699 0 : if( nl>80 ) {
700 0 : mystring += w[i] + "\n";
701 : nl=0;
702 : } else {
703 0 : mystring += w[i] + " ";
704 : }
705 0 : if( w[i].find(".")!=std::string::npos ) {
706 : break; // Only write up the the first dot
707 : }
708 : }
709 : return mystring;
710 0 : }
711 :
712 0 : void Keywords::print_html_item( const std::string& key ) const {
713 : std::printf("<tr>\n");
714 : std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
715 : std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
716 : std::printf("</tr>\n");
717 0 : }
718 :
719 440378 : std::string Keywords::get( const unsigned k ) const {
720 440378 : plumed_assert( k<size() );
721 440378 : return keys[k];
722 : }
723 :
724 37428 : bool Keywords::getLogicalDefault(const std::string & key, bool& def ) const {
725 37428 : if( booldefs.find(key)!=booldefs.end() ) {
726 37428 : def=booldefs.find(key)->second;
727 37428 : return true;
728 : } else {
729 : return false;
730 : }
731 : }
732 :
733 11708 : bool Keywords::getDefaultValue(const std::string & key, std::string& def ) const {
734 22934 : plumed_assert( style(key,"compulsory") || style(key,"hidden") );
735 :
736 11708 : if( numdefs.find(key)!=numdefs.end() ) {
737 6095 : def=numdefs.find(key)->second;
738 6095 : return true;
739 : } else {
740 : return false;
741 : }
742 : }
743 :
744 0 : void Keywords::destroyData() {
745 0 : keys.clear();
746 0 : reserved_keys.clear();
747 : types.clear();
748 : allowmultiple.clear();
749 : documentation.clear();
750 : booldefs.clear();
751 : numdefs.clear();
752 : atomtags.clear();
753 : ckey.clear();
754 : cdocs.clear();
755 : ckey.clear();
756 0 : }
757 :
758 7796 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
759 7796 : cstring = instr;
760 7796 : }
761 :
762 94752 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
763 94752 : plumed_assert( !outputComponentExists( name, false ) );
764 94752 : plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
765 :
766 94752 : std::size_t num2=name.find_first_of("_");
767 94752 : if( num2!=std::string::npos ) {
768 373 : char uu = '_';
769 373 : plumed_massert( std::count(name.begin(),name.end(), uu)==1, "underscore is reserved character in component names and there should only be one");
770 373 : plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
771 : }
772 :
773 94752 : ckey.insert( std::pair<std::string,std::string>(name,key) );
774 94752 : cdocs.insert( std::pair<std::string,std::string>(name,descr) );
775 94752 : cnames.push_back(name);
776 94752 : }
777 :
778 129139 : bool Keywords::outputComponentExists( const std::string& name, const bool& custom ) const {
779 129139 : if( custom && cstring.find("customize")!=std::string::npos ) {
780 : return true;
781 : }
782 :
783 : std::string sname;
784 125678 : std::size_t num=name.find_first_of("-");
785 125678 : std::size_t num2=name.find_last_of("_");
786 :
787 125678 : if( num2!=std::string::npos ) {
788 4088 : sname=name.substr(num2);
789 123634 : } else if( num!=std::string::npos ) {
790 52380 : sname=name.substr(0,num);
791 : } else {
792 : sname=name;
793 : }
794 :
795 1187643 : for(unsigned i=0; i<cnames.size(); ++i) {
796 1092891 : if( sname==cnames[i] ) {
797 : return true;
798 : }
799 : }
800 : return false;
801 : }
802 :
803 9046 : std::string Keywords::getOutputComponentFlag( const std::string& name ) const {
804 9046 : return ckey.find(name)->second;
805 : }
806 :
807 4796 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
808 4796 : if( cstring.find("customized")!=std::string::npos ) {
809 112 : return "the label of this action is set by user in the input. See documentation above.";
810 : }
811 :
812 : bool found=false;
813 84276 : for(unsigned i=0; i<cnames.size(); ++i) {
814 79592 : if( name==cnames[i] ) {
815 : found=true;
816 : }
817 : }
818 4684 : if( !found ) {
819 0 : plumed_merror("could not find output component named " + name );
820 : }
821 4684 : return cdocs.find(name)->second;
822 : }
823 :
824 0 : void Keywords::removeComponent( const std::string& name ) {
825 : bool found=false;
826 :
827 : while(true) {
828 : unsigned j;
829 0 : for(j=0; j<cnames.size(); j++)
830 0 : if(cnames[j]==name) {
831 : break;
832 : }
833 0 : if(j<cnames.size()) {
834 0 : cnames.erase(cnames.begin()+j);
835 : found=true;
836 : } else {
837 : break;
838 : }
839 0 : }
840 : // Delete documentation, type and so on from the description
841 : cdocs.erase(name);
842 : ckey.erase(name);
843 0 : plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
844 0 : }
845 :
846 444 : std::vector<std::string> Keywords::getOutputComponents() const {
847 444 : return cnames;
848 : }
849 :
850 8990 : std::string Keywords::getKeywordDescription( const std::string& key ) const {
851 8990 : plumed_assert( exists( key ) );
852 8990 : return documentation.find(key)->second;
853 : }
854 :
855 : }
|