Merge "Improve gmx::test::CommandLine."
[alexxy/gromacs.git] / src / gromacs / selection / selectionoption.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements classes in selectionoption.h and selectionoptionstorage.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #include "selectionfileoption.h"
39 #include "selectionfileoptioninfo.h"
40 #include "selectionoption.h"
41 #include "selectionoptioninfo.h"
42
43 #include <string>
44
45 #include "gromacs/options/optionsvisitor.h"
46 #include "gromacs/selection/selection.h"
47 #include "gromacs/selection/selectionoptionmanager.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/gmxassert.h"
50 #include "gromacs/utility/messagestringcollector.h"
51
52 #include "selectionfileoptionstorage.h"
53 #include "selectionoptionstorage.h"
54
55 namespace gmx
56 {
57
58 /********************************************************************
59  * SelectionOptionStorage
60  */
61
62 SelectionOptionStorage::SelectionOptionStorage(const SelectionOption &settings)
63     : MyBase(settings, OptionFlags() | efNoDefaultValue | efDontCheckMinimumCount),
64       info_(this), manager_(NULL), selectionFlags_(settings._selectionFlags)
65 {
66     GMX_RELEASE_ASSERT(!hasFlag(efMulti),
67                        "allowMultiple() is not supported for selection options");
68     if (settings._infoPtr != NULL)
69     {
70         *settings._infoPtr = &info_;
71     }
72 }
73
74
75 void SelectionOptionStorage::setManager(SelectionOptionManager *manager)
76 {
77     GMX_RELEASE_ASSERT(manager_ == NULL || manager_ == manager,
78                        "Manager cannot be changed once set");
79     if (manager_ == NULL)
80     {
81         manager->registerOption(this);
82         manager_ = manager;
83     }
84 }
85
86
87 std::string SelectionOptionStorage::formatSingleValue(const Selection &value) const
88 {
89     return value.selectionText();
90 }
91
92
93 void SelectionOptionStorage::addSelections(
94         const SelectionList &selections,
95         bool bFullValue)
96 {
97     if (bFullValue && selections.size() < static_cast<size_t>(minValueCount()))
98     {
99         GMX_THROW(InvalidInputError("Too few selections provided"));
100     }
101     if (bFullValue)
102     {
103         clearSet();
104     }
105     SelectionList::const_iterator i;
106     for (i = selections.begin(); i != selections.end(); ++i)
107     {
108         // TODO: Having this check in the parser would make interactive input
109         // behave better.
110         if (selectionFlags_.test(efOnlyStatic) && i->isDynamic())
111         {
112             GMX_THROW(InvalidInputError("Dynamic selections not supported"));
113         }
114         addValue(*i);
115     }
116     if (bFullValue)
117     {
118         commitValues();
119         setFlag(efSet);
120     }
121 }
122
123
124 void SelectionOptionStorage::convertValue(const std::string &value)
125 {
126     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
127
128     manager_->convertOptionValue(this, value);
129 }
130
131 void SelectionOptionStorage::processSetValues(ValueList *values)
132 {
133     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
134
135     if (values->size() == 0)
136     {
137         manager_->requestOptionDelayedParsing(this);
138     }
139     else if (values->size() < static_cast<size_t>(minValueCount()))
140     {
141         GMX_THROW(InvalidInputError("Too few (valid) values provided"));
142     }
143     ValueList::iterator i;
144     for (i = values->begin(); i != values->end(); ++i)
145     {
146         i->data().setFlags(selectionFlags_);
147     }
148 }
149
150 void SelectionOptionStorage::processAll()
151 {
152     if (isRequired() && !isSet())
153     {
154         GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
155
156         manager_->requestOptionDelayedParsing(this);
157         setFlag(efSet);
158     }
159 }
160
161 void SelectionOptionStorage::setAllowedValueCount(int count)
162 {
163     // TODO: It should be possible to have strong exception safety here.
164     MessageStringCollector errors;
165     errors.startContext("In option '" + name() + "'");
166     if (count >= 0)
167     {
168         // Should not throw because efDontCheckMinimumCount is set
169         setMinValueCount(count);
170         if (valueCount() > 0 && valueCount() < count)
171         {
172             errors.append("Too few (valid) values provided");
173         }
174     }
175     try
176     {
177         setMaxValueCount(count);
178     }
179     catch (const UserInputError &ex)
180     {
181         errors.append(ex.what());
182     }
183     errors.finishContext();
184     if (!errors.isEmpty())
185     {
186         GMX_THROW(InvalidInputError(errors.toString()));
187     }
188 }
189
190 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
191 {
192     ValueList::iterator i;
193     for (i = values().begin(); i != values().end(); ++i)
194     {
195         if (flag == efOnlyStatic && bSet && i->isDynamic())
196         {
197             MessageStringCollector errors;
198             errors.startContext("In option '" + name() + "'");
199             errors.append("Dynamic selections not supported");
200             errors.finishContext();
201             GMX_THROW(InvalidInputError(errors.toString()));
202         }
203     }
204     selectionFlags_.set(flag, bSet);
205     for (i = values().begin(); i != values().end(); ++i)
206     {
207         i->data().setFlags(selectionFlags_);
208     }
209 }
210
211
212 /********************************************************************
213  * SelectionOptionInfo
214  */
215
216 SelectionOptionInfo::SelectionOptionInfo(SelectionOptionStorage *option)
217     : OptionInfo(option)
218 {
219 }
220
221 SelectionOptionStorage &SelectionOptionInfo::option()
222 {
223     return static_cast<SelectionOptionStorage &>(OptionInfo::option());
224 }
225
226 const SelectionOptionStorage &SelectionOptionInfo::option() const
227 {
228     return static_cast<const SelectionOptionStorage &>(OptionInfo::option());
229 }
230
231 void SelectionOptionInfo::setManager(SelectionOptionManager *manager)
232 {
233     option().setManager(manager);
234 }
235
236 void SelectionOptionInfo::setValueCount(int count)
237 {
238     option().setAllowedValueCount(count);
239 }
240
241 void SelectionOptionInfo::setEvaluateVelocities(bool bEnabled)
242 {
243     option().setSelectionFlag(efEvaluateVelocities, bEnabled);
244 }
245
246 void SelectionOptionInfo::setEvaluateForces(bool bEnabled)
247 {
248     option().setSelectionFlag(efEvaluateForces, bEnabled);
249 }
250
251 void SelectionOptionInfo::setOnlyAtoms(bool bEnabled)
252 {
253     option().setSelectionFlag(efOnlyAtoms, bEnabled);
254 }
255
256 void SelectionOptionInfo::setOnlyStatic(bool bEnabled)
257 {
258     option().setSelectionFlag(efOnlyStatic, bEnabled);
259 }
260
261 void SelectionOptionInfo::setDynamicMask(bool bEnabled)
262 {
263     option().setSelectionFlag(efDynamicMask, bEnabled);
264 }
265
266 void SelectionOptionInfo::setDynamicOnlyWhole(bool bEnabled)
267 {
268     option().setSelectionFlag(efDynamicOnlyWhole, bEnabled);
269 }
270
271
272 /********************************************************************
273  * SelectionOption
274  */
275
276 AbstractOptionStoragePointer SelectionOption::createStorage() const
277 {
278     return AbstractOptionStoragePointer(new SelectionOptionStorage(*this));
279 }
280
281
282 /********************************************************************
283  * SelectionFileOptionStorage
284  */
285
286 SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
287     : AbstractOptionStorage(settings, OptionFlags() | efMulti | efDontCheckMinimumCount),
288       info_(this), manager_(NULL), bValueParsed_(false)
289 {
290 }
291
292 void SelectionFileOptionStorage::clearSet()
293 {
294     bValueParsed_ = false;
295 }
296
297 void SelectionFileOptionStorage::convertValue(const std::string &value)
298 {
299     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
300
301     if (bValueParsed_)
302     {
303         GMX_THROW(InvalidInputError("More than one file name provided"));
304     }
305     bValueParsed_ = true;
306     // TODO: Should we throw an InvalidInputError if the file does not exist?
307     manager_->parseRequestedFromFile(value);
308 }
309
310 void SelectionFileOptionStorage::processSet()
311 {
312     if (!bValueParsed_)
313     {
314         GMX_THROW(InvalidInputError("No file name provided"));
315     }
316 }
317
318
319 /********************************************************************
320  * SelectionFileOptionInfo
321  */
322
323 SelectionFileOptionInfo::SelectionFileOptionInfo(SelectionFileOptionStorage *option)
324     : OptionInfo(option)
325 {
326 }
327
328 SelectionFileOptionStorage &SelectionFileOptionInfo::option()
329 {
330     return static_cast<SelectionFileOptionStorage &>(OptionInfo::option());
331 }
332
333 const SelectionFileOptionStorage &SelectionFileOptionInfo::option() const
334 {
335     return static_cast<const SelectionFileOptionStorage &>(OptionInfo::option());
336 }
337
338 void SelectionFileOptionInfo::setManager(SelectionOptionManager *manager)
339 {
340     option().setManager(manager);
341 }
342
343
344 /********************************************************************
345  * SelectionFileOption
346  */
347
348 SelectionFileOption::SelectionFileOption(const char *name)
349     : AbstractOption(name)
350 {
351     setDescription("Provide selections from files");
352 }
353
354 AbstractOptionStoragePointer SelectionFileOption::createStorage() const
355 {
356     return AbstractOptionStoragePointer(new SelectionFileOptionStorage(*this));
357 }
358
359
360 /********************************************************************
361  * Global functions
362  */
363
364 namespace
365 {
366
367 /*! \internal \brief
368  * Visitor that sets the manager for each selection option.
369  *
370  * \ingroup module_selection
371  */
372 class SelectionOptionManagerSetter : public OptionsModifyingVisitor
373 {
374     public:
375         //! Construct a visitor that sets given manager.
376         explicit SelectionOptionManagerSetter(SelectionOptionManager *manager)
377             : manager_(manager)
378         {
379         }
380
381         void visitSubSection(Options *section)
382         {
383             OptionsModifyingIterator iterator(section);
384             iterator.acceptSubSections(this);
385             iterator.acceptOptions(this);
386         }
387
388         void visitOption(OptionInfo *option)
389         {
390             SelectionOptionInfo *selOption
391                 = option->toType<SelectionOptionInfo>();
392             if (selOption != NULL)
393             {
394                 selOption->setManager(manager_);
395             }
396             SelectionFileOptionInfo *selFileOption
397                 = option->toType<SelectionFileOptionInfo>();
398             if (selFileOption != NULL)
399             {
400                 selFileOption->setManager(manager_);
401             }
402         }
403
404     private:
405         SelectionOptionManager *manager_;
406 };
407
408 } // namespace
409
410 void setManagerForSelectionOptions(Options *options,
411                                    SelectionOptionManager *manager)
412 {
413     SelectionOptionManagerSetter(manager).visitSubSection(options);
414 }
415
416 } // namespace gmx