LOOS  v2.3.2
OptionsFramework.cpp
1 /*
2  This file is part of LOOS.
3 
4  LOOS (Lightweight Object-Oriented Structure library)
5  Copyright (c) 2011, Tod D. Romo, Alan Grossfield
6  Department of Biochemistry and Biophysics
7  School of Medicine & Dentistry, University of Rochester
8 
9  This package (LOOS) is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation under version 3 of the License.
12 
13  This package is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 
23 #include <utils_structural.hpp>
24 #include <OptionsFramework.hpp>
25 
26 
27 namespace loos {
28  namespace OptionsFramework {
29 
30  void BasicOptions::addGeneric(po::options_description& opts) {
31  if (!full_help.empty())
32  opts.add_options()("fullhelp", "More detailed help");
33 
34  opts.add_options()
35  ("help,h", "Produce this message")
36  ("verbosity,v", po::value<int>(&verbosity)->default_value(verbosity), "Verbosity of output (if available)");
37  }
38 
39  std::string BasicOptions::print() const {
40  std::ostringstream oss;
41  oss << "verbosity=" << verbosity ;
42  return(oss.str());
43  }
44 
45 
46  // Presumably, BasicOptions will be the first OptionsPackage in
47  // the list of options. This means we can catch the --fullhelp at
48  // the check() stage. If we try later (i.e. with
49  // postConditions()), then another OptionsPackage may fail the
50  // check (such as required args or a model name)
51  bool BasicOptions::check(po::variables_map& map) {
52  if (!full_help.empty()) {
53  if (map.count("fullhelp")) {
54  std::cout << full_help << std::endl;
55  return(true);
56  }
57  }
58  return(false);
59  }
60 
61 
62  void BasicOptions::setFullHelp(const std::string& s) {
63  full_help = s;
64  }
65 
66  // -------------------------------------------------------
67 
68  void OutputPrefix::addGeneric(po::options_description& opts) {
69  opts.add_options()
70  ("prefix,p", po::value<std::string>(&prefix)->default_value(prefix), label.c_str());
71  }
72 
73  std::string OutputPrefix::print() const {
74  std::ostringstream oss;
75  oss << "prefix='" << prefix << "'";
76  return(oss.str());
77  }
78 
79  // -------------------------------------------------------
80 
81  void BasicSelection::addGeneric(po::options_description& opts) {
82  opts.add_options()
83  ("selection,s", po::value<std::string>(&selection)->default_value(selection), label.c_str());
84  }
85 
86  std::string BasicSelection::print() const {
87  std::ostringstream oss;
88  oss << "selection='" << selection << "'";
89  return(oss.str());
90  }
91 
92  // -------------------------------------------------------
93  void BasicSplitBy::addGeneric(po::options_description& opts) {
94  opts.add_options()
95  ("splitby", po::value<std::string>(&split_method)->default_value(split_method), label.c_str());
96  }
97 
98  std::string BasicSplitBy::print() const {
99  std::ostringstream oss;
100  oss << "splitby='" << split_method << "'";
101  return(oss.str());
102  }
103 
104  BasicSplitBy::SplitType BasicSplitBy::methodToType(const std::string& name)
105  {
106  std::string canonical_name(name);
107  boost::to_upper(canonical_name);
108 
109  if (canonical_name == "NONE")
110  return(NONE);
111  else if (canonical_name == "MOL")
112  return(MOLECULE);
113  else if (canonical_name == "SEGID")
114  return(SEGID);
115  else if (canonical_name == "RES")
116  return(RESIDUE);
117 
118 
119  throw(OptionsError("Invalid split-by method in options"));
120  }
121 
122  bool BasicSplitBy::postConditions(po::variables_map& map)
123  {
124  try {
125  split_type = methodToType(split_method);
126  }
127  catch (OptionsError& e) {
128  std::cerr << "Error- '" << split_method << "' is an invalid method for splitting a selection.\n";
129  return(false);
130  }
131  catch (...) {
132  throw;
133  }
134 
135 
136  return(true);
137  }
138 
139  std::vector<AtomicGroup> BasicSplitBy::split(const AtomicGroup& grp)
140  {
141  std::vector<AtomicGroup> result;
142 
143  switch(split_type) {
144  case NONE:
145  result.push_back(grp);
146  break;
147 
148  case MOLECULE:
149  result = grp.splitByMolecule();
150  break;
151 
152  case SEGID:
153  result = grp.splitByUniqueSegid();
154  break;
155 
156  case RESIDUE:
157  result = grp.splitByResidue();
158  break;
159 
160  default:
161  throw(LOOSError("Unknown split method"));
162  }
163 
164  return(result);
165  }
166 
167 
168 
169  // -------------------------------------------------------
170 
171  void ModelWithCoords::addGeneric(po::options_description& opts) {
172  std::string filetypes = "Model types:\n" + availableSystemFileTypes();
173 
174  opts.add_options()
175  ("coordinates,c", po::value<std::string>(&coords_name)->default_value(coords_name), "File to use for coordinates")
176  ("modeltype", po::value<std::string>(), filetypes.c_str());
177  }
178 
179  void ModelWithCoords::addHidden(po::options_description& opts) {
180  opts.add_options()
181  ("model", po::value<std::string>(&model_name), "Model Filename");
182  }
183 
184 
185  void ModelWithCoords::addPositional(po::positional_options_description& pos) {
186  pos.add("model", 1);
187  }
188 
189 
190  bool ModelWithCoords::check(po::variables_map& map) {
191  return(!map.count("model"));
192  }
193 
194  bool ModelWithCoords::postConditions(po::variables_map& map) {
195  if (map.count("modeltype")) {
196  model_type = map["modeltype"].as<std::string>();
197  model = loadStructureWithCoords(model_name, model_type, coords_name);
198  } else
199  model = loadStructureWithCoords(model_name, coords_name);
200 
201  return(true);
202  }
203 
204  std::string ModelWithCoords::help() const { return("model"); }
205 
206 
207  std::string ModelWithCoords::print() const {
208  std::ostringstream oss;
209 
210  oss << boost::format("model='%s', modeltype='%s'") % model_name % model_type;
211  if (!coords_name.empty())
212  oss << boost::format(", coords='%s'") % coords_name;
213 
214  return(oss.str());
215  }
216 
217 
218 
219 
220  // -------------------------------------------------------
221 
222 
223  void TwoModelsWithCoords::addGeneric(po::options_description& opts) {
224  std::string filetypes = "Model types:\n" + availableSystemFileTypes();
225  std::string optdesc1 = std::string("File to use for coordinates for") + desc1;
226  std::string optdesc2 = std::string("File to use for coordinates for") + desc2;
227 
228 
229  opts.add_options()
230  ("coord1,c", po::value<std::string>(&coords1_name)->default_value(coords1_name), optdesc1.c_str())
231  ("model1type", po::value<std::string>(), filetypes.c_str())
232  ("coord2,d", po::value<std::string>(&coords2_name)->default_value(coords2_name), optdesc2.c_str())
233  ("model2type", po::value<std::string>(), filetypes.c_str());
234  }
235 
236  void TwoModelsWithCoords::addHidden(po::options_description& opts) {
237  opts.add_options()
238  ("model1", po::value<std::string>(&model1_name), desc1.c_str())
239  ("model2", po::value<std::string>(&model2_name), desc2.c_str());
240  }
241 
242 
243  void TwoModelsWithCoords::addPositional(po::positional_options_description& pos) {
244  pos.add("model1", 1);
245  pos.add("model2", 1);
246  }
247 
248 
249  bool TwoModelsWithCoords::check(po::variables_map& map) {
250  return(!(map.count("model1") && map.count("model2")));
251  }
252 
253  bool TwoModelsWithCoords::postConditions(po::variables_map& map) {
254  if (map.count("model1type")) {
255  model1_type = map["model1type"].as<std::string>();
256  model1 = loadStructureWithCoords(model1_name, model1_type, coords1_name);
257  } else
258  model1 = loadStructureWithCoords(model1_name, coords1_name);
259 
260  if (map.count("model2type")) {
261  model2_type = map["model2type"].as<std::string>();
262  model2 = loadStructureWithCoords(model2_name, model2_type, coords2_name);
263  } else
264  model2 = loadStructureWithCoords(model2_name, coords2_name);
265 
266  return(true);
267  }
268 
269  std::string TwoModelsWithCoords::help() const {
270  std::string msg = desc1 + " " + desc2;
271  return(msg);
272  }
273 
274 
275  std::string TwoModelsWithCoords::print() const {
276  std::ostringstream oss;
277 
278  oss << boost::format("model1='%s', model1type='%s'") % model1_name % model1_type;
279  if (!coords1_name.empty())
280  oss << boost::format(", coords1='%s'") % coords1_name;
281 
282  oss << boost::format("model2='%s', model2type='%s'") % model2_name % model2_type;
283  if (!coords2_name.empty())
284  oss << boost::format(", coords2='%s'") % coords2_name;
285 
286  return(oss.str());
287  }
288 
289 
290 
291 
292  // -------------------------------------------------------
293 
294 
295 
296  void BasicTrajectory::addGeneric(po::options_description& opts) {
297  std::string modeltypes = "Model types:\n" + availableSystemFileTypes();
298  std::string trajtypes = "Trajectory types:\n" + availableTrajectoryFileTypes();
299 
300  opts.add_options()
301  ("skip,k", po::value<unsigned int>(&skip)->default_value(skip), "Number of frames to skip")
302  ("modeltype", po::value<std::string>(), modeltypes.c_str())
303  ("trajtype", po::value<std::string>(), trajtypes.c_str());
304  };
305 
306  void BasicTrajectory::addHidden(po::options_description& opts) {
307  opts.add_options()
308  ("model", po::value<std::string>(&model_name), "Model filename")
309  ("traj", po::value<std::string>(&traj_name), "Trajectory filename");
310  }
311 
312  void BasicTrajectory::addPositional(po::positional_options_description& pos) {
313  pos.add("model", 1);
314  pos.add("traj", 1);
315  }
316 
317  bool BasicTrajectory::check(po::variables_map& map) {
318  return(! (map.count("model") && map.count("traj")));
319  }
320 
321  bool BasicTrajectory::postConditions(po::variables_map& map) {
322  if (map.count("modeltype")) {
323  model_type = map["modeltype"].as<std::string>();
324  model = createSystem(model_name, model_type);
325  } else
326  model = createSystem(model_name);
327 
328  if (map.count("trajtype")) {
329  traj_type = map["trajtype"].as<std::string>();
330  trajectory = createTrajectory(traj_name, traj_type, model);
331  } else
332  trajectory = createTrajectory(traj_name, model);
333 
334  if (skip > 0)
335  trajectory->readFrame(skip-1);
336 
337  return(true);
338  }
339 
340  std::string BasicTrajectory::help() const { return("model trajectory"); }
341  std::string BasicTrajectory::print() const {
342  std::ostringstream oss;
343  oss << boost::format("model='%s', model_type='%s', traj='%s', traj_type='%s', skip=%d") % model_name % model_type % traj_name % traj_type % skip;
344  return(oss.str());
345  }
346 
347 
348  // -------------------------------------------------------
349 
350 
351  void TrajectoryWithFrameIndices::addGeneric(po::options_description& opts) {
352  std::string modeltypes = "Model types:\n" + availableSystemFileTypes();
353  std::string trajtypes = "Trajectory types:\n" + availableTrajectoryFileTypes();
354 
355  opts.add_options()
356  ("skip,k", po::value<unsigned int>(&skip)->default_value(skip), "Number of frames to skip")
357  ("modeltype", po::value<std::string>(&model_type)->default_value(model_type), modeltypes.c_str())
358  ("trajtype", po::value<std::string>(&traj_type)->default_value(traj_type), trajtypes.c_str())
359  ("stride,i", po::value<unsigned int>(&stride)->default_value(stride), "Take every ith frame")
360  ("range,r", po::value<std::string>(&frame_index_spec), "Which frames to use (matlab style range, overrides stride and skip)");
361  };
362 
363  void TrajectoryWithFrameIndices::addHidden(po::options_description& opts) {
364  opts.add_options()
365  ("model", po::value<std::string>(&model_name), "Model filename")
366  ("traj", po::value<std::string>(&traj_name), "Trajectory filename");
367  }
368 
369  void TrajectoryWithFrameIndices::addPositional(po::positional_options_description& pos) {
370  pos.add("model", 1);
371  pos.add("traj", 1);
372  }
373 
374  bool TrajectoryWithFrameIndices::check(po::variables_map& map) {
375  return(! (map.count("model") && map.count("traj")));
376  }
377 
378  bool TrajectoryWithFrameIndices::postConditions(po::variables_map& map) {
379  if (skip > 0 && !frame_index_spec.empty()) {
380  std::cerr << "Error- you cannot specify both a skip and a frame range...I might get confused!\n";
381  return(false);
382  }
383 
384  if (model_type.empty())
385  model = createSystem(model_name);
386  else
387  model = createSystem(model_name, model_type);
388 
389  if (traj_type.empty())
390  trajectory = createTrajectory(traj_name, model);
391  else
392  trajectory = createTrajectory(traj_name, traj_type, model);
393 
394  return(true);
395  }
396 
397  std::string TrajectoryWithFrameIndices::help() const { return("model trajectory"); }
398  std::string TrajectoryWithFrameIndices::print() const {
399  std::ostringstream oss;
400  oss << boost::format("model='%s', modeltype='%s', traj='%s', trajtype='%s'") % model_name % model_type % traj_name % traj_type;
401  if (skip > 0)
402  oss << ", skip=" << skip;
403  else if (!frame_index_spec.empty())
404  oss << ", range='" << frame_index_spec << "'";
405 
406  return(oss.str());
407  }
408 
409 
410  std::vector<uint> TrajectoryWithFrameIndices::frameList() const {
411  return(assignTrajectoryFrames(trajectory, frame_index_spec, skip, stride));
412  }
413 
414 
415 
416  // -------------------------------------------------------
417 
418  void OutputTrajectoryOptions::addGeneric(po::options_description& opts) {
419  std::string types = availableOutputTrajectoryFileTypes();
420 
421  opts.add_options()
422  ("outtrajtype,t", po::value<std::string>(&type), types.c_str())
423  ("append", po::value<bool>(&append)->default_value(append), "Append if trajectory exists, otherwise overwrite");
424  }
425 
426  void OutputTrajectoryOptions::addHidden(po::options_description& opts) {
427  opts.add_options()
428  ("outraj", po::value<std::string>(&name), "Output trajectory name");
429  }
430 
431  void OutputTrajectoryOptions::addPositional(po::positional_options_description& pos) {
432  pos.add("outraj", 1);
433  }
434 
435  bool OutputTrajectoryOptions::check(po::variables_map& map) {
436  return(! map.count("outraj"));
437  }
438 
439  bool OutputTrajectoryOptions::postConditions(po::variables_map& map) {
440  boost::tuple<std::string, std::string> names = splitFilename(name);
441  basename = boost::get<0>(names);
442 
443  if (type.empty())
444  type = boost::get<1>(names);
445 
446  outraj = createOutputTrajectory(name, type, append);
447  return(true);
448  }
449 
450 
451  std::string OutputTrajectoryOptions::help() const {
452  return("output-trajectory");
453  }
454 
455  std::string OutputTrajectoryOptions::print() const {
456  std::ostringstream oss;
457  oss << boost::format("outraj='%s',outraj_type='%s',append=%d")
458  % name
459  % type
460  % append;
461  return(oss.str());
462  }
463 
464  // -------------------------------------------------------
465 
466  void OutputTrajectoryTypeOptions::addGeneric(po::options_description& opts) {
467  std::string types = availableOutputTrajectoryFileTypes();
468 
469  opts.add_options()
470  ("outtrajtype,t", po::value<std::string>(&type)->default_value("dcd"), types.c_str())
471  ("append", po::value<bool>(&append)->default_value(append), "Append if trajectory exists, otherwise overwrite");
472  }
473 
474 
475  std::string OutputTrajectoryTypeOptions::print() const {
476  std::ostringstream oss;
477  oss << boost::format("outraj_type='%s',append=%d")
478  % type
479  % append;
480  return(oss.str());
481  }
482 
483 
484  pTrajectoryWriter OutputTrajectoryTypeOptions::createTrajectory(const std::string& prefix) {
485 
486  std::string fname = prefix + "." + type;
487  return(createOutputTrajectory(fname, type, append));
488  }
489 
490  // -------------------------------------------------------
491 
492  void RequiredArguments::addArgument(const std::string& name, const std::string& description) {
493  StringPair arg(name, description);
494  if (find(arguments.begin(), arguments.end(), arg) != arguments.end()) {
495  std::ostringstream oss;
496  oss << "Error- duplicate command line argument requested for '" << name << "'";
497  throw(LOOSError(oss.str()));
498  }
499 
500  arguments.push_back(arg);
501  }
502 
503  void RequiredArguments::addVariableArguments(const std::string& name, const std::string& description) {
504  if (vargs_set)
505  throw(LOOSError("Multiple variable arguments requested"));
506 
507  variable_arguments = StringPair(name, description);
508  vargs_set = true;
509  }
510 
511  void RequiredArguments::addHidden(po::options_description& o) {
512  for (std::vector<StringPair>::const_iterator i = arguments.begin(); i != arguments.end(); ++i)
513  o.add_options()(i->first.c_str(), po::value<std::string>(), i->second.c_str());
514  if (vargs_set)
515  o.add_options()(variable_arguments.first.c_str(), po::value< std::vector<std::string> >(), variable_arguments.second.c_str());
516  }
517 
518  void RequiredArguments::addPositional(po::positional_options_description& pos) {
519  for (std::vector<StringPair>::const_iterator i = arguments.begin(); i != arguments.end(); ++i)
520  pos.add(i->first.c_str(), 1);
521  if (vargs_set)
522  pos.add(variable_arguments.first.c_str(), -1);
523  }
524 
525 
526  bool RequiredArguments::check(po::variables_map& map) {
527  for (std::vector<StringPair>::const_iterator i = arguments.begin(); i != arguments.end(); ++i)
528  if (! map.count(i->first.c_str()) )
529  return(true);
530 
531  if (vargs_set && !map.count(variable_arguments.first))
532  return(true);
533 
534  return(false);
535  }
536 
537  bool RequiredArguments::postConditions(po::variables_map& map) {
538  held_map = map;
539  return(true);
540  }
541 
542  std::string RequiredArguments::value(const std::string& s) const {
543  std::string result;
544  if (held_map.count(s))
545  result = held_map[s].as<std::string>();
546  return(result);
547  }
548 
549 
550  std::vector<std::string> RequiredArguments::variableValues(const std::string& s) const {
551  return(held_map[s].as< std::vector<std::string> >());
552  }
553 
554 
555  std::string RequiredArguments::help() const {
556  std::string s;
557  for (std::vector<StringPair>::const_iterator i = arguments.begin(); i != arguments.end(); ++i)
558  s = s + (i == arguments.begin() ? "" : " ") + i->first;
559  if (vargs_set)
560  s = s + (s.empty() ? "" : " ") + variable_arguments.first + " [" + variable_arguments.first + " ...]";
561  return(s);
562  }
563 
564  std::string RequiredArguments::print() const {
565  std::ostringstream oss;
566  for (std::vector<StringPair>::const_iterator i = arguments.begin(); i != arguments.end(); ++i) {
567  oss << i->first << "='" << held_map[i->first].as<std::string>() << "'";
568  if (i != arguments.end() - 1)
569  oss << ',';
570  }
571 
572  if (vargs_set) {
573  std::vector<std::string> v = variableValues(variable_arguments.first);
574  oss << variable_arguments.first << "=(";
575  oss << vectorAsStringWithCommas<std::string>(v);
576  oss << ")";
577  }
578 
579  return(oss.str());
580  }
581 
582 
583  // -------------------------------------------------------
584 
585 
587  options.push_back(pack); return(*this);
588  }
589 
590 
591  void AggregateOptions::setupOptions() {
592  for (vOpts::iterator i = options.begin(); i != options.end(); ++i)
593  (*i)->addGeneric(generic);
594 
595  for (vOpts::iterator i = options.begin(); i != options.end(); ++i)
596  (*i)->addHidden(hidden);
597 
598  command_line.add(generic).add(hidden);
599 
600  for (vOpts::iterator i = options.begin(); i != options.end(); ++i)
601  (*i)->addPositional(pos);
602  }
603 
605  std::cout << "Usage- " << program_name << " [options] ";
606  for (vOpts::iterator i = options.begin(); i != options.end(); ++i) {
607  std::string help_text = (*i)->help();
608  if (! help_text.empty())
609  std::cout << (*i)->help() << " ";
610  }
611  std::cout << std::endl;
612  std::cout << generic;
613  }
614 
615 
616  bool AggregateOptions::parse(int argc, char *argv[]) {
617  if (program_name.empty())
618  program_name = std::string(argv[0]);
619 
620  generic.add_options()
621  ("config", po::value<std::string>(&config_name), "Options config file");
622 
623  setupOptions();
624  bool show_help = false;
625 
626  try {
627  po::store(po::command_line_parser(argc, argv).style(po::command_line_style::default_style ^ po::command_line_style::allow_guessing).
628  options(command_line).positional(pos).run(), vm);
629  po::notify(vm);
630 
631  if (!config_name.empty()) {
632  std::ifstream ifs(config_name.c_str());
633  if (!ifs)
634  throw(LOOSError("Cannot open options config file"));
635  store(parse_config_file(ifs, command_line), vm);
636  notify(vm);
637  }
638 
639  }
640  catch (std::exception& e) {
641  std::cerr << "Error- " << e.what() << std::endl;
642  show_help = true;
643  }
644 
645  if (!show_help)
646  show_help = vm.count("help");
647 
648  if (!show_help)
649  for (vOpts::iterator i = options.begin(); i != options.end() && !show_help; ++i)
650  show_help = (*i)->check(vm);
651 
652  if (show_help) {
653  showHelp();
654  return(false);
655  }
656 
657  for (vOpts::iterator i = options.begin(); i != options.end(); ++i)
658  if (!(*i)->postConditions(vm)) {
659  showHelp();
660  return(false);
661  }
662 
663  return(true);
664 
665  }
666 
667  std::vector<std::string> AggregateOptions::print() const {
668  std::vector<std::string> results;
669 
670  results.push_back(program_name);
671 
672  for (vOpts::const_iterator i = options.begin(); i != options.end(); ++i)
673  results.push_back((*i)->print());
674 
675  return(results);
676  }
677 
678  };
679 };
680 
pTraj trajectory
The trajectory, primed by the –skip value (if specified)
Namespace for encapsulating options processing.
void addArgument(const std::string &name, const std::string &description)
Add a required argument given a name (tag) and a description (currently unused)
AtomicGroup model
Model that describes the trajectory.
AtomicGroup loadStructureWithCoords(const std::string &model_name, const std::string &coord_name)
Loads a structure and optional coordinates.
bool parse(int argc, char *argv[])
Parses a command line, returning true if parsing was ok.
AtomicGroup model
Model that describes the trajectory.
AtomicGroup createSystem(const std::string &filename)
Factory function for reading in structure files.
Definition: sfactories.cpp:115
std::string value(const std::string &s) const
Retrieve the value for an argument.
Generic LOOS exception.
Definition: exceptions.hpp:40
std::vector< std::string > print() const
void addVariableArguments(const std::string &name, const std::string &description)
Add a required argument that can be an arbitrary number of items.
void showHelp()
Displays the help for this tool.
std::vector< uint > frameList() const
Returns the list of frames the user requested.
Namespace for most things not already encapsulated within a class.
std::vector< uint > assignTrajectoryFrames(const pTraj &traj, const std::string &frame_index_spec, uint skip, uint stride)
Builds a list of trajectory indices (frame_index_spec supercedes skip)
std::vector< std::string > variableValues(const std::string &s) const
Retrieve the variable-number argument.
Combines a set of OptionsPackages.
AggregateOptions & add(OptionsPackage *pack)
Add a pointer to an OptionsPackage that will be used for options.