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 :
27 : namespace PLMD {
28 :
29 915339 : Keywords::KeyType::KeyType( const std::string& type ) {
30 915339 : if( type=="compulsory" ) {
31 242031 : style=compulsory;
32 673308 : } else if( type=="flag" ) {
33 186749 : style=flag;
34 486559 : } else if( type=="optional" ) {
35 252231 : style=optional;
36 234328 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
37 121214 : style=atoms;
38 113114 : } else if( type=="hidden" ) {
39 54073 : style=hidden;
40 59041 : } else if( type=="vessel" ) {
41 59041 : style=vessel;
42 : } else {
43 0 : plumed_massert(false,"invalid keyword specifier " + type);
44 : }
45 915339 : }
46 :
47 3912 : void Keywords::KeyType::setStyle( const std::string& type ) {
48 3912 : if( type=="compulsory" ) {
49 80 : style=compulsory;
50 3832 : } else if( type=="flag" ) {
51 0 : style=flag;
52 3832 : } else if( type=="optional" ) {
53 25 : style=optional;
54 3807 : } else if( type.find("atoms")!=std::string::npos || type.find("residues")!=std::string::npos ) {
55 205 : style=atoms;
56 3602 : } else if( type=="hidden" ) {
57 129 : style=hidden;
58 3473 : } else if( type=="vessel" ) {
59 3473 : style=vessel;
60 : } else {
61 0 : plumed_massert(false,"invalid keyword specifier " + type);
62 : }
63 3912 : }
64 :
65 682 : void Keywords::add( const Keywords& newkeys ) {
66 682 : newkeys.copyData( keys, reserved_keys, types, allowmultiple, documentation, booldefs, numdefs, atomtags, cnames, ckey, cdocs );
67 682 : }
68 :
69 682 : 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,
70 : std::map<std::string,std::string>& docs, std::map<std::string,bool>& bools, std::map<std::string,std::string>& nums,
71 : std::map<std::string,std::string>& atags, std::vector<std::string>& cnam, std::map<std::string,std::string>& ck,
72 : std::map<std::string,std::string>& cd ) const {
73 682 : for(unsigned i=0; i<keys.size(); ++i) {
74 0 : std::string thiskey=keys[i];
75 0 : for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
76 0 : for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
77 0 : kk.push_back( thiskey );
78 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
79 0 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
80 0 : if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
81 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
82 0 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
83 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
84 0 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
85 0 : if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
86 0 : if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
87 : }
88 12958 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
89 12276 : std::string thiskey=reserved_keys[i];
90 108072 : for(unsigned j=0; j<kk.size(); ++j) plumed_massert( thiskey!=kk[j], "keyword " + thiskey + " is in twice" );
91 170280 : for(unsigned j=0; j<rk.size(); ++j) plumed_massert( thiskey!=rk[j], "keyword " + thiskey + " is in twice" );
92 12276 : rk.push_back( thiskey );
93 0 : plumed_massert( types.count( thiskey ), "no type data on keyword " + thiskey + " to copy" );
94 12276 : tt.insert( std::pair<std::string,KeyType>( thiskey,types.find(thiskey)->second) );
95 12276 : if( (types.find(thiskey)->second).isAtomList() ) atags.insert( std::pair<std::string,std::string>( thiskey,atomtags.find(thiskey)->second) );
96 0 : plumed_massert( allowmultiple.count( thiskey ), "no numbered data on keyword " + thiskey + " to copy" );
97 12276 : am.insert( std::pair<std::string,bool>(thiskey,allowmultiple.find(thiskey)->second) );
98 0 : plumed_massert( documentation.count( thiskey ), "no documentation for keyword " + thiskey + " to copy" );
99 24552 : docs.insert( std::pair<std::string,std::string>(thiskey,documentation.find(thiskey)->second) );
100 0 : if( booldefs.count( thiskey ) ) bools.insert( std::pair<std::string,bool>( thiskey,booldefs.find(thiskey)->second) );
101 0 : if( numdefs.count( thiskey ) ) nums.insert( std::pair<std::string,std::string>( thiskey,numdefs.find(thiskey)->second) );
102 : }
103 12958 : for(unsigned i=0; i<cnames.size(); ++i) {
104 12276 : std::string thisnam=cnames[i];
105 116622 : for(unsigned j=0; j<cnam.size(); ++j) plumed_massert( thisnam!=cnam[j], "component " + thisnam + " is in twice" );
106 12276 : cnam.push_back( thisnam );
107 0 : plumed_massert( ckey.count( thisnam ), "no keyword data on component " + thisnam + " to copy" );
108 24552 : ck.insert( std::pair<std::string,std::string>( thisnam, ckey.find(thisnam)->second) );
109 0 : plumed_massert( cdocs.count( thisnam ), "no documentation on component " + thisnam + " to copy" );
110 24552 : cd.insert( std::pair<std::string,std::string>( thisnam, cdocs.find(thisnam)->second) );
111 : }
112 682 : }
113 :
114 112849 : void Keywords::reserve( const std::string & t, const std::string & k, const std::string & d ) {
115 112849 : plumed_assert( !exists(k) && !reserved(k) );
116 112849 : std::string fd, lowkey=k;
117 : // Convert to lower case
118 972044 : std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
119 : // Remove any underscore characters
120 : for(unsigned i=0;; ++i) {
121 154817 : std::size_t num=lowkey.find_first_of("_");
122 154817 : if( num==std::string::npos ) break;
123 41968 : lowkey.erase( lowkey.begin() + num, lowkey.begin() + num + 1 );
124 41968 : }
125 112849 : if( t=="vessel" ) {
126 118082 : fd = d + " The final value can be referenced using <em>label</em>." + lowkey;
127 111136 : if(d.find("flag")==std::string::npos) fd += ". You can use multiple instances of this keyword i.e. " +
128 104190 : k +"1, " + k + "2, " + k + "3... The corresponding values are then "
129 104190 : "referenced using <em>label</em>."+ lowkey +"-1, <em>label</em>." + lowkey +
130 104190 : "-2, <em>label</em>." + lowkey + "-3...";
131 59041 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
132 118082 : types.insert( std::pair<std::string,KeyType>(k,KeyType("vessel")) );
133 53808 : } else if( t=="numbered" ) {
134 5994 : fd = d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
135 2997 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
136 5994 : types.insert( std::pair<std::string,KeyType>(k,KeyType("optional")) );
137 : } else {
138 : fd = d;
139 50811 : if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
140 50811 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
141 101622 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
142 52086 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
143 : }
144 225698 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
145 112849 : reserved_keys.push_back(k);
146 112849 : }
147 :
148 1953 : void Keywords::reserveFlag( const std::string & k, const bool def, const std::string & d ) {
149 1953 : plumed_assert( !exists(k) && !reserved(k) );
150 : std::string defstr;
151 1953 : if( def ) { defstr="( default=on ) "; } else { defstr="( default=off ) "; }
152 3906 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
153 24266 : std::string fd,lowkey=k; std::transform(lowkey.begin(),lowkey.end(),lowkey.begin(),[](unsigned char c) { return std::tolower(c); });
154 1953 : fd=defstr + d;
155 3906 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
156 1953 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
157 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
158 1953 : reserved_keys.push_back(k);
159 1953 : }
160 :
161 14436 : void Keywords::use( const std::string & k ) {
162 14436 : plumed_massert( reserved(k), "the " + k + " keyword is not reserved");
163 179967 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
164 165531 : if(reserved_keys[i]==k) keys.push_back( reserved_keys[i] );
165 : }
166 14436 : }
167 :
168 3912 : void Keywords::reset_style( const std::string & k, const std::string & style ) {
169 3912 : plumed_massert( exists(k) || reserved(k), "no " + k + " keyword" );
170 3912 : (types.find(k)->second).setStyle(style);
171 3912 : if( (types.find(k)->second).isVessel() ) allowmultiple[k]=true;
172 4117 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,style) );
173 3912 : }
174 :
175 426605 : void Keywords::add( const std::string & t, const std::string & k, const std::string & d ) {
176 1279815 : plumed_massert( !exists(k) && t!="flag" && !reserved(k) && t!="vessel", "keyword " + k + " has already been registered");
177 : std::string fd;
178 426605 : if( t=="numbered" ) {
179 2742 : fd=d + " You can use multiple instances of this keyword i.e. " + k +"1, " + k + "2, " + k + "3...";
180 1371 : allowmultiple.insert( std::pair<std::string,bool>(k,true) );
181 2742 : types.insert( std::pair<std::string,KeyType>(k, KeyType("optional")) );
182 : } else {
183 : fd=d;
184 425234 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
185 850468 : types.insert( std::pair<std::string,KeyType>(k,KeyType(t)) );
186 545173 : if( (types.find(k)->second).isAtomList() ) atomtags.insert( std::pair<std::string,std::string>(k,t) );
187 : }
188 442649 : if( t=="atoms" && isaction ) fd = d + ". For more information on how to specify lists of atoms see \\ref Group";
189 853210 : documentation.insert( std::pair<std::string,std::string>(k,fd) );
190 426605 : keys.push_back(k);
191 426605 : }
192 :
193 189136 : void Keywords::add( const std::string & t, const std::string & k, const std::string & def, const std::string & d ) {
194 378272 : plumed_assert( !exists(k) && !reserved(k) && (t=="compulsory" || t=="hidden" )); // An optional keyword can't have a default
195 189136 : types.insert( std::pair<std::string,KeyType>(k, KeyType(t)) );
196 378272 : documentation.insert( std::pair<std::string,std::string>(k,"( default=" + def + " ) " + d) );
197 189136 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
198 378272 : numdefs.insert( std::pair<std::string,std::string>(k,def) );
199 189136 : keys.push_back(k);
200 189136 : }
201 :
202 184796 : void Keywords::addFlag( const std::string & k, const bool def, const std::string & d ) {
203 184796 : plumed_massert( !exists(k) && !reserved(k), "keyword " + k + " has already been registered");
204 184796 : std::string defstr; plumed_massert( !def, "the second argument to addFlag must be false " + k );
205 : defstr="( default=off ) ";
206 369592 : types.insert( std::pair<std::string,KeyType>(k,KeyType("flag")) );
207 369592 : documentation.insert( std::pair<std::string,std::string>(k,defstr + d) );
208 184796 : allowmultiple.insert( std::pair<std::string,bool>(k,false) );
209 0 : booldefs.insert( std::pair<std::string,bool>(k,def) );
210 184796 : keys.push_back(k);
211 184796 : }
212 :
213 1438 : void Keywords::remove( const std::string & k ) {
214 : bool found=false; unsigned j=0, n=0;
215 :
216 : while(true) {
217 14291 : for(j=0; j<keys.size(); j++) if(keys[j]==k)break;
218 33184 : for(n=0; n<reserved_keys.size(); n++) if(reserved_keys[n]==k)break;
219 2876 : if(j<keys.size()) {
220 1353 : keys.erase(keys.begin()+j);
221 : found=true;
222 1523 : } else if(n<reserved_keys.size()) {
223 85 : reserved_keys.erase(reserved_keys.begin()+n);
224 : found=true;
225 : } else break;
226 : }
227 : // Delete documentation, type and so on from the description
228 : types.erase(k); documentation.erase(k); allowmultiple.erase(k); booldefs.erase(k); numdefs.erase(k);
229 1438 : 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
230 1438 : }
231 :
232 8070 : bool Keywords::numbered( const std::string & k ) const {
233 16140 : if( style( k,"atoms") ) return true;
234 0 : plumed_massert( allowmultiple.count(k), "Did not find keyword " + k );
235 6094 : return allowmultiple.find(k)->second;
236 : }
237 :
238 727474 : bool Keywords::style( const std::string & k, const std::string & t ) const {
239 0 : plumed_massert( types.count(k), "Did not find keyword " + k );
240 :
241 727474 : if( (types.find(k)->second).toString()==t ) return true;
242 : return false;
243 : }
244 :
245 783765 : unsigned Keywords::size() const {
246 783765 : return keys.size();
247 : }
248 :
249 9262 : std::string Keywords::getKeyword( const unsigned i ) const {
250 9262 : plumed_assert( i<size() );
251 9262 : return keys[i];
252 : }
253 :
254 1160571 : bool Keywords::exists( const std::string & k ) const {
255 12056720 : for(unsigned i=0; i<keys.size(); ++i) {
256 11096368 : if( keys[i]==k ) return true;
257 : }
258 : return false;
259 : }
260 :
261 933368 : bool Keywords::reserved( const std::string & k ) const {
262 2158698 : for(unsigned i=0; i<reserved_keys.size(); ++i) {
263 1243359 : if( reserved_keys[i]==k ) return true;
264 : }
265 : return false;
266 : }
267 :
268 0 : void Keywords::print_template(const std::string& actionname, bool include_optional) const {
269 : unsigned nkeys=0;
270 : std::printf("%s",actionname.c_str());
271 0 : for(unsigned i=0; i<keys.size(); ++i) {
272 0 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
273 : }
274 0 : if( nkeys>0 ) {
275 0 : std::string prevtag="start";
276 0 : for(unsigned i=0; i<keys.size(); ++i) {
277 0 : if( (types.find(keys[i])->second).isAtomList() ) {
278 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
279 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second ) break;
280 0 : if( (atomtags.find(keys[i])->second).find("residues")!=std::string::npos) std::printf(" %s=<residue selection>", keys[i].c_str() );
281 : else std::printf(" %s=<atom selection>", keys[i].c_str() );
282 0 : prevtag=atomtags.find(keys[i])->second;
283 : }
284 : }
285 : }
286 : nkeys=0;
287 0 : for(unsigned i=0; i<keys.size(); ++i) {
288 0 : if ( include_optional || \
289 0 : (types.find(keys[i])->second).isCompulsory() ) nkeys++;
290 : }
291 0 : if( nkeys>0 ) {
292 0 : for(unsigned i=0; i<keys.size(); ++i) {
293 0 : if ( (types.find(keys[i])->second).isCompulsory() ) {
294 : std::string def;
295 0 : if( getDefaultValue( keys[i], def) ) {
296 : std::printf(" %s=%s ", keys[i].c_str(), def.c_str() );
297 : } else {
298 : std::printf(" %s= ", keys[i].c_str() );
299 : }
300 0 : } else if (include_optional) {
301 : // TG no defaults for optional keywords?
302 : std::printf(" [%s]", keys[i].c_str() );
303 : }
304 : }
305 : }
306 : std::printf("\n");
307 0 : }
308 :
309 287 : void Keywords::print_vim() const {
310 4426 : for(unsigned i=0; i<keys.size(); ++i) {
311 4139 : if( (types.find(keys[i])->second).isFlag() ) {
312 : std::printf( ",flag:%s", keys[i].c_str() );
313 : } else {
314 3209 : if( allowmultiple.find(keys[i])->second ) std::printf(",numbered:%s",keys[i].c_str() );
315 : else std::printf(",option:%s",keys[i].c_str() );
316 : }
317 : }
318 287 : std::fprintf(stdout,"\n");
319 287 : print(stdout);
320 287 : }
321 :
322 0 : void Keywords::print_html() const {
323 :
324 : // This is the part that outputs the details of the components
325 0 : if( cnames.size()>0 ) {
326 : unsigned ndef=0;
327 0 : for(unsigned i=0; i<cnames.size(); ++i) {
328 0 : if(ckey.find(cnames[i])->second=="default") ndef++;
329 : }
330 :
331 0 : if( ndef>0 ) {
332 0 : std::cout<<"\\par Description of components\n\n";
333 0 : std::cout<<cstring<<"\n\n";
334 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
335 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Description </b> </td> </tr>\n");
336 : unsigned nndef=0;
337 0 : for(unsigned i=0; i<cnames.size(); ++i) {
338 : //plumed_assert( ckey.find(cnames[i])->second=="default" );
339 0 : if( ckey.find(cnames[i])->second!="default" ) { nndef++; continue; }
340 : std::printf("<tr>\n");
341 : std::printf("<td width=15%%> <b> %s </b></td>\n",cnames[i].c_str() );
342 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
343 : std::printf("</tr>\n");
344 : }
345 0 : std::cout<<"</table>\n\n";
346 0 : if( nndef>0 ) {
347 0 : std::cout<<"In addition the following quantities can be calculated by employing the keywords listed below"<<std::endl;
348 0 : std::cout<<"\n\n";
349 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
350 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
351 0 : for(unsigned i=0; i<cnames.size(); ++i) {
352 0 : if( ckey.find(cnames[i])->second!="default") {
353 : std::printf("<tr>\n");
354 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
355 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
356 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
357 : std::printf("</tr>\n");
358 : }
359 : }
360 0 : std::cout<<"</table>\n\n";
361 : }
362 : } else {
363 : unsigned nregs=0;
364 0 : for(unsigned i=0; i<cnames.size(); ++i) {
365 0 : if( exists(ckey.find(cnames[i])->second) ) nregs++;
366 : }
367 0 : if( nregs>0 ) {
368 0 : std::cout<<"\\par Description of components\n\n";
369 0 : std::cout<<cstring<<"\n\n";
370 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
371 : std::printf("<tr> <td width=5%%> <b> Quantity </b> </td> <td> <b> Keyword </b> </td> <td> <b> Description </b> </td> </tr>\n");
372 0 : for(unsigned i=0; i<cnames.size(); ++i) {
373 0 : if( exists(ckey.find(cnames[i])->second) ) {
374 : std::printf("<tr>\n");
375 : std::printf("<td width=5%%> <b> %s </b></td> <td width=10%%> <b> %s </b> </td> \n",
376 : cnames[i].c_str(),(ckey.find(cnames[i])->second).c_str() );
377 : std::printf("<td> %s </td>\n",(cdocs.find(cnames[i])->second).c_str() );
378 : std::printf("</tr>\n");
379 : }
380 : }
381 0 : std::cout<<"</table>\n\n";
382 : }
383 : }
384 : }
385 :
386 : unsigned nkeys=0;
387 0 : for(unsigned i=0; i<keys.size(); ++i) {
388 0 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
389 : }
390 0 : if( nkeys>0 ) {
391 0 : if(isaction && isatoms) std::cout<<"\\par The atoms involved can be specified using\n\n";
392 0 : else if(isaction) std::cout<<"\\par The data to analyze can be the output from another analysis algorithm\n\n";
393 0 : else std::cout<<"\\par The input trajectory is specified using one of the following\n\n";
394 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
395 0 : std::string prevtag="start"; unsigned counter=0;
396 0 : for(unsigned i=0; i<keys.size(); ++i) {
397 0 : if ( (types.find(keys[i])->second).isAtomList() ) {
398 0 : plumed_massert( atomtags.count(keys[i]), "keyword " + keys[i] + " allegedly specifies atoms but no tag has been specified. Please email Gareth Tribello");
399 0 : if( prevtag!="start" && prevtag!=atomtags.find(keys[i])->second && isaction ) {
400 0 : std::cout<<"</table>\n\n";
401 0 : if( isatoms ) std::cout<<"\\par Or alternatively by using\n\n";
402 0 : else if( counter==0 ) { std::cout<<"\\par Alternatively data can be collected from the trajectory using \n\n"; counter++; }
403 0 : else std::cout<<"\\par Lastly data collected in a previous analysis action can be reanalyzed by using the keyword \n\n";
404 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
405 : }
406 0 : print_html_item( keys[i] );
407 0 : prevtag=atomtags.find(keys[i])->second;
408 : }
409 : }
410 0 : std::cout<<"</table>\n\n";
411 : }
412 : nkeys=0;
413 0 : for(unsigned i=0; i<keys.size(); ++i) {
414 0 : if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
415 : }
416 0 : if( nkeys>0 ) {
417 0 : if(isaction) std::cout<< "\\par Compulsory keywords\n\n";
418 0 : else std::cout<<"\\par The following must be present\n\n";
419 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
420 0 : for(unsigned i=0; i<keys.size(); ++i) {
421 0 : if ( (types.find(keys[i])->second).isCompulsory() ) print_html_item( keys[i] );
422 : }
423 0 : std::cout<<"</table>\n\n";
424 : }
425 : nkeys=0;
426 0 : for(unsigned i=0; i<keys.size(); ++i) {
427 0 : if ( (types.find(keys[i])->second).isFlag() || (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
428 : }
429 0 : if( nkeys>0 ) {
430 0 : if(isaction) std::cout<<"\\par Options\n\n";
431 0 : else std::cout<<"\\par The following options are available\n\n";
432 0 : std::cout<<" <table align=center frame=void width=95%% cellpadding=5%%> \n";
433 0 : for(unsigned i=0; i<keys.size(); ++i) {
434 0 : if ( (types.find(keys[i])->second).isFlag() ) print_html_item( keys[i] );
435 : }
436 0 : std::cout<<"\n";
437 : }
438 : nkeys=0;
439 0 : for(unsigned i=0; i<keys.size(); ++i) {
440 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
441 : }
442 0 : if( nkeys>0 ) {
443 0 : for(unsigned i=0; i<keys.size(); ++i) {
444 0 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) print_html_item( keys[i] );
445 : }
446 : }
447 0 : std::cout<<"</table>\n\n";
448 0 : }
449 :
450 0 : void Keywords::print_spelling() const {
451 0 : for(unsigned i=0; i<keys.size(); ++i) std::printf("%s\n", keys[i].c_str() );
452 0 : for(unsigned i=0; i<cnames.size(); ++i) std::printf("%s\n",cnames[i].c_str() );
453 0 : }
454 :
455 287 : void Keywords::print( FILE* out ) const {
456 : unsigned nkeys=0;
457 4426 : for(unsigned i=0; i<keys.size(); ++i) {
458 4139 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
459 : }
460 287 : if( nkeys>0 ) {
461 : std::fprintf(out,"The input trajectory can be in any of the following formats: \n\n");
462 2386 : for(unsigned i=0; i<keys.size(); ++i) {
463 2260 : if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], out );
464 : }
465 : }
466 : nkeys=0;
467 4426 : for(unsigned i=0; i<keys.size(); ++i) {
468 4139 : if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
469 : }
470 : unsigned ncompulsory=nkeys;
471 287 : if( nkeys>0 ) {
472 : std::fprintf(out,"\nThe following arguments are compulsory: \n\n");
473 3616 : for(unsigned i=0; i<keys.size(); ++i) {
474 3388 : if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] );
475 : }
476 : }
477 : nkeys=0;
478 4426 : for(unsigned i=0; i<keys.size(); ++i) {
479 4139 : if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
480 : }
481 287 : if( nkeys>0 ) {
482 253 : if(ncompulsory>0) std::fprintf( out,"\nIn addition you may use the following options: \n\n");
483 : else std::fprintf( out,"\nThe following options are available\n\n");
484 4211 : for(unsigned i=0; i<keys.size(); ++i) {
485 3958 : if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] );
486 : }
487 : }
488 : nkeys=0;
489 4426 : for(unsigned i=0; i<keys.size(); ++i) {
490 7427 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) nkeys++;
491 : }
492 287 : if( nkeys>0 ) {
493 3855 : for(unsigned i=0; i<keys.size(); ++i) {
494 6425 : if ( (types.find(keys[i])->second).isOptional() || (types.find(keys[i])->second).isVessel() ) printKeyword( keys[i], out ); //log.printKeyword( keys[i], documentation[i] );
495 : }
496 : std::fprintf(out,"\n");
497 : }
498 287 : }
499 :
500 3412 : void Keywords::printKeyword( const std::string& key, FILE* out ) const {
501 3412 : bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
502 3412 : std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
503 : std::fprintf(out,"%23s - ", key.c_str() );
504 3412 : unsigned nl=0; std::string blank=" ";
505 72717 : for(unsigned i=0; i<w.size(); ++i) {
506 69598 : nl+=w[i].length() + 1;
507 69598 : if( nl>60 ) {
508 : std::fprintf(out,"\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0;
509 : } else {
510 : std::fprintf(out,"%s ", w[i].c_str() );
511 : }
512 69598 : if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
513 : }
514 : std::fprintf(out,"\n");
515 3412 : }
516 :
517 0 : void Keywords::print( Log& log ) const {
518 : unsigned nkeys=0;
519 0 : for(unsigned i=0; i<keys.size(); ++i) {
520 0 : if ( (types.find(keys[i])->second).isAtomList() ) nkeys++;
521 : }
522 0 : if (nkeys>0 ) {
523 0 : log.printf( "The input for this keyword can be specified using one of the following \n\n");
524 0 : for(unsigned i=0; i<keys.size(); ++i) {
525 0 : if ( (types.find(keys[i])->second).isAtomList() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] );
526 : }
527 : }
528 : nkeys=0;
529 0 : for(unsigned i=0; i<keys.size(); ++i) {
530 0 : if ( (types.find(keys[i])->second).isCompulsory() ) nkeys++;
531 : }
532 0 : if( nkeys>0 ) {
533 0 : log.printf( "\n The compulsory keywords for this action are: \n\n");
534 0 : for(unsigned i=0; i<keys.size(); ++i) {
535 0 : if ( (types.find(keys[i])->second).isCompulsory() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] );
536 : }
537 : }
538 : nkeys=0;
539 0 : for(unsigned i=0; i<keys.size(); ++i) {
540 0 : if ( (types.find(keys[i])->second).isFlag() ) nkeys++;
541 : }
542 0 : if( nkeys>0 ) {
543 0 : log.printf( "\n The following options are available: \n\n");
544 0 : for(unsigned i=0; i<keys.size(); ++i) {
545 0 : if ( (types.find(keys[i])->second).isFlag() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] );
546 : }
547 0 : log.printf("\n");
548 : }
549 : nkeys=0;
550 0 : for(unsigned i=0; i<keys.size(); ++i) {
551 0 : if ( (types.find(keys[i])->second).isOptional() ) nkeys++;
552 : }
553 0 : if( nkeys>0 ) {
554 0 : for(unsigned i=0; i<keys.size(); ++i) {
555 0 : if ( (types.find(keys[i])->second).isOptional() ) printKeyword( keys[i], log ); //log.printKeyword( keys[i], documentation[i] );
556 : }
557 0 : log.printf("\n");
558 : }
559 0 : }
560 :
561 0 : void Keywords::printKeyword( const std::string& key, Log& log ) const {
562 0 : bool killdot=( (documentation.find(key)->second).find("\\f$")!=std::string::npos ); // Check for latex
563 0 : std::vector<std::string> w=Tools::getWords( documentation.find(key)->second );
564 0 : log.printf("%23s - ", key.c_str() );
565 0 : unsigned nl=0; std::string blank=" ";
566 0 : for(unsigned i=0; i<w.size(); ++i) {
567 0 : nl+=w[i].length() + 1;
568 0 : if( nl>60 ) {
569 0 : log.printf("\n%23s %s ", blank.c_str(), w[i].c_str() ); nl=0;
570 : } else {
571 0 : log.printf("%s ", w[i].c_str() );
572 : }
573 0 : if( killdot && w[i].find(".")!=std::string::npos ) break; // If there is latex only write up to first dot
574 : }
575 0 : log.printf("\n");
576 0 : }
577 :
578 0 : std::string Keywords::getTooltip( const std::string& name ) const {
579 0 : std::size_t dd=name.find_first_of("0123456789"); std::string kname=name.substr(0,dd);
580 0 : if( !exists(kname) ) return "<b> could not find this keyword </b>";
581 0 : std::string mystring, docstr = documentation.find(kname)->second;
582 0 : if( types.find(kname)->second.isCompulsory() ) {
583 : mystring += "<b>compulsory keyword ";
584 0 : if( docstr.find("default")!=std::string::npos ) {
585 0 : std::size_t bra = docstr.find_first_of(")"); mystring += docstr.substr(0,bra+1); docstr = docstr.substr(bra+1);
586 : }
587 : mystring += "</b>\n";
588 : }
589 0 : std::vector<std::string> w=Tools::getWords( docstr ); unsigned nl=0;
590 0 : for(unsigned i=0; i<w.size(); ++i) {
591 0 : nl+=w[i].length() + 1;
592 0 : if( nl>80 ) { mystring += w[i] + "\n"; nl=0; }
593 0 : else { mystring += w[i] + " "; }
594 0 : if( w[i].find(".")!=std::string::npos ) break; // Only write up the the first dot
595 : }
596 : return mystring;
597 0 : }
598 :
599 0 : void Keywords::print_html_item( const std::string& key ) const {
600 : std::printf("<tr>\n");
601 : std::printf("<td width=15%%> <b> %s </b></td>\n",key.c_str() );
602 : std::printf("<td> %s </td>\n",(documentation.find(key)->second).c_str() );
603 : std::printf("</tr>\n");
604 0 : }
605 :
606 368197 : std::string Keywords::get( const unsigned k ) const {
607 368197 : plumed_assert( k<size() );
608 368197 : return keys[k];
609 : }
610 :
611 36577 : bool Keywords::getLogicalDefault( std::string key, bool& def ) const {
612 36577 : if( booldefs.find(key)!=booldefs.end() ) {
613 36577 : def=booldefs.find(key)->second;
614 36577 : return true;
615 : } else {
616 : return false;
617 : }
618 : }
619 :
620 10262 : bool Keywords::getDefaultValue( std::string key, std::string& def ) const {
621 20702 : plumed_assert( style(key,"compulsory") || style(key,"hidden") );
622 :
623 10262 : if( numdefs.find(key)!=numdefs.end() ) {
624 5042 : def=numdefs.find(key)->second;
625 5042 : return true;
626 : } else {
627 : return false;
628 : }
629 : }
630 :
631 0 : void Keywords::destroyData() {
632 0 : keys.clear(); reserved_keys.clear(); types.clear();
633 : allowmultiple.clear(); documentation.clear();
634 : booldefs.clear(); numdefs.clear(); atomtags.clear();
635 : ckey.clear(); cdocs.clear(); ckey.clear();
636 0 : }
637 :
638 6275 : void Keywords::setComponentsIntroduction( const std::string& instr ) {
639 6275 : cstring = instr;
640 6275 : }
641 :
642 72441 : void Keywords::addOutputComponent( const std::string& name, const std::string& key, const std::string& descr ) {
643 72441 : plumed_assert( !outputComponentExists( name, false ) );
644 72441 : plumed_massert( name.find("-")==std::string::npos,"dash is reseved character in component names" );
645 :
646 72441 : std::size_t num2=name.find_first_of("_");
647 72441 : if( num2!=std::string::npos ) {
648 298 : 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");
649 298 : plumed_massert( num2==0, "underscore is reserved character in component names that has special meaning");
650 : }
651 :
652 144882 : ckey.insert( std::pair<std::string,std::string>(name,key) );
653 144882 : cdocs.insert( std::pair<std::string,std::string>(name,descr) );
654 72441 : cnames.push_back(name);
655 72441 : }
656 :
657 106111 : bool Keywords::outputComponentExists( const std::string& name, const bool& custom ) const {
658 106111 : if( custom && cstring.find("customize")!=std::string::npos ) return true;
659 :
660 : std::string sname;
661 102652 : std::size_t num=name.find_first_of("-");
662 102652 : std::size_t num2=name.find_last_of("_");
663 :
664 104570 : if( num2!=std::string::npos ) sname=name.substr(num2);
665 126538 : else if( num!=std::string::npos ) sname=name.substr(0,num);
666 : else sname=name;
667 :
668 976400 : for(unsigned i=0; i<cnames.size(); ++i) {
669 903959 : if( sname==cnames[i] ) return true;
670 : }
671 : return false;
672 : }
673 :
674 0 : std::string Keywords::getOutputComponentDescription( const std::string& name ) const {
675 0 : if( cstring.find("customized")!=std::string::npos ) return "the label of this action is set by user in the input. See documentation above.";
676 :
677 : bool found=false;
678 0 : for(unsigned i=0; i<cnames.size(); ++i) {
679 0 : if( name==cnames[i] ) found=true;
680 : }
681 0 : if( !found ) plumed_merror("could not find output component named " + name );
682 0 : return cdocs.find(name)->second;
683 : }
684 :
685 0 : void Keywords::removeComponent( const std::string& name ) {
686 : bool found=false;
687 :
688 : while(true) {
689 : unsigned j;
690 0 : for(j=0; j<cnames.size(); j++) if(cnames[j]==name)break;
691 0 : if(j<cnames.size()) {
692 0 : cnames.erase(cnames.begin()+j);
693 : found=true;
694 : } else break;
695 0 : }
696 : // Delete documentation, type and so on from the description
697 : cdocs.erase(name); ckey.erase(name);
698 0 : plumed_massert(found,"You are trying to remove " + name + " a component that isn't there");
699 0 : }
700 :
701 : }
|