Merge remote-tracking branch 'origin/release-4-6' into HEAD
[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() | efOption_NoDefaultValue
64                            | efOption_DontCheckMinimumCount),
65       info_(this), manager_(NULL), selectionFlags_(settings.selectionFlags_)
66 {
67     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
68                        "allowMultiple() is not supported for selection options");
69     if (settings.infoPtr_ != NULL)
70     {
71         *settings.infoPtr_ = &info_;
72     }
73 }
74
75
76 void SelectionOptionStorage::setManager(SelectionOptionManager *manager)
77 {
78     GMX_RELEASE_ASSERT(manager_ == NULL || manager_ == manager,
79                        "Manager cannot be changed once set");
80     if (manager_ == NULL)
81     {
82         manager->registerOption(this);
83         manager_ = manager;
84     }
85 }
86
87
88 std::string SelectionOptionStorage::formatSingleValue(const Selection &value) const
89 {
90     return value.selectionText();
91 }
92
93
94 void SelectionOptionStorage::addSelections(
95         const SelectionList &selections,
96         bool bFullValue)
97 {
98     if (bFullValue && selections.size() < static_cast<size_t>(minValueCount()))
99     {
100         GMX_THROW(InvalidInputError("Too few selections provided"));
101     }
102     if (bFullValue)
103     {
104         clearSet();
105     }
106     SelectionList::const_iterator i;
107     for (i = selections.begin(); i != selections.end(); ++i)
108     {
109         // TODO: Having this check in the parser would make interactive input
110         // behave better.
111         if (selectionFlags_.test(efSelection_OnlyStatic) && i->isDynamic())
112         {
113             GMX_THROW(InvalidInputError("Dynamic selections not supported"));
114         }
115         addValue(*i);
116     }
117     if (bFullValue)
118     {
119         commitValues();
120         markAsSet();
121     }
122 }
123
124
125 void SelectionOptionStorage::convertValue(const std::string &value)
126 {
127     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
128
129     manager_->convertOptionValue(this, value);
130 }
131
132 void SelectionOptionStorage::processSetValues(ValueList *values)
133 {
134     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
135
136     if (values->size() == 0)
137     {
138         manager_->requestOptionDelayedParsing(this);
139     }
140     else if (values->size() < static_cast<size_t>(minValueCount()))
141     {
142         GMX_THROW(InvalidInputError("Too few (valid) values provided"));
143     }
144     ValueList::iterator i;
145     for (i = values->begin(); i != values->end(); ++i)
146     {
147         i->data().setFlags(selectionFlags_);
148     }
149 }
150
151 void SelectionOptionStorage::processAll()
152 {
153     if (isRequired() && !isSet())
154     {
155         GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
156
157         manager_->requestOptionDelayedParsing(this);
158         markAsSet();
159     }
160 }
161
162 void SelectionOptionStorage::setAllowedValueCount(int count)
163 {
164     // TODO: It should be possible to have strong exception safety here.
165     MessageStringCollector errors;
166     errors.startContext("In option '" + name() + "'");
167     if (count >= 0)
168     {
169         // Should not throw because efOption_DontCheckMinimumCount is set.
170         setMinValueCount(count);
171         if (valueCount() > 0 && valueCount() < count)
172         {
173             errors.append("Too few (valid) values provided");
174         }
175     }
176     try
177     {
178         setMaxValueCount(count);
179     }
180     catch (const UserInputError &ex)
181     {
182         errors.append(ex.what());
183     }
184     errors.finishContext();
185     if (!errors.isEmpty())
186     {
187         GMX_THROW(InvalidInputError(errors.toString()));
188     }
189 }
190
191 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
192 {
193     ValueList::iterator i;
194     for (i = values().begin(); i != values().end(); ++i)
195     {
196         if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
197         {
198             MessageStringCollector errors;
199             errors.startContext("In option '" + name() + "'");
200             errors.append("Dynamic selections not supported");
201             errors.finishContext();
202             GMX_THROW(InvalidInputError(errors.toString()));
203         }
204     }
205     selectionFlags_.set(flag, bSet);
206     for (i = values().begin(); i != values().end(); ++i)
207     {
208         i->data().setFlags(selectionFlags_);
209     }
210 }
211
212
213 /********************************************************************
214  * SelectionOptionInfo
215  */
216
217 SelectionOptionInfo::SelectionOptionInfo(SelectionOptionStorage *option)
218     : OptionInfo(option)
219 {
220 }
221
222 SelectionOptionStorage &SelectionOptionInfo::option()
223 {
224     return static_cast<SelectionOptionStorage &>(OptionInfo::option());
225 }
226
227 const SelectionOptionStorage &SelectionOptionInfo::option() const
228 {
229     return static_cast<const SelectionOptionStorage &>(OptionInfo::option());
230 }
231
232 void SelectionOptionInfo::setManager(SelectionOptionManager *manager)
233 {
234     option().setManager(manager);
235 }
236
237 void SelectionOptionInfo::setValueCount(int count)
238 {
239     option().setAllowedValueCount(count);
240 }
241
242 void SelectionOptionInfo::setEvaluateVelocities(bool bEnabled)
243 {
244     option().setSelectionFlag(efSelection_EvaluateVelocities, bEnabled);
245 }
246
247 void SelectionOptionInfo::setEvaluateForces(bool bEnabled)
248 {
249     option().setSelectionFlag(efSelection_EvaluateForces, bEnabled);
250 }
251
252 void SelectionOptionInfo::setOnlyAtoms(bool bEnabled)
253 {
254     option().setSelectionFlag(efSelection_OnlyAtoms, bEnabled);
255 }
256
257 void SelectionOptionInfo::setOnlyStatic(bool bEnabled)
258 {
259     option().setSelectionFlag(efSelection_OnlyStatic, bEnabled);
260 }
261
262 void SelectionOptionInfo::setDynamicMask(bool bEnabled)
263 {
264     option().setSelectionFlag(efSelection_DynamicMask, bEnabled);
265 }
266
267 void SelectionOptionInfo::setDynamicOnlyWhole(bool bEnabled)
268 {
269     option().setSelectionFlag(efSelection_DynamicOnlyWhole, bEnabled);
270 }
271
272
273 /********************************************************************
274  * SelectionOption
275  */
276
277 AbstractOptionStoragePointer SelectionOption::createStorage() const
278 {
279     return AbstractOptionStoragePointer(new SelectionOptionStorage(*this));
280 }
281
282
283 /********************************************************************
284  * SelectionFileOptionStorage
285  */
286
287 SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
288     : AbstractOptionStorage(settings, OptionFlags() | efOption_MultipleTimes
289                                           | efOption_DontCheckMinimumCount),
290       info_(this), manager_(NULL), bValueParsed_(false)
291 {
292 }
293
294 void SelectionFileOptionStorage::clearSet()
295 {
296     bValueParsed_ = false;
297 }
298
299 void SelectionFileOptionStorage::convertValue(const std::string &value)
300 {
301     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
302
303     if (bValueParsed_)
304     {
305         GMX_THROW(InvalidInputError("More than one file name provided"));
306     }
307     bValueParsed_ = true;
308     // TODO: Should we throw an InvalidInputError if the file does not exist?
309     manager_->parseRequestedFromFile(value);
310 }
311
312 void SelectionFileOptionStorage::processSet()
313 {
314     if (!bValueParsed_)
315     {
316         GMX_THROW(InvalidInputError("No file name provided"));
317     }
318 }
319
320
321 /********************************************************************
322  * SelectionFileOptionInfo
323  */
324
325 SelectionFileOptionInfo::SelectionFileOptionInfo(SelectionFileOptionStorage *option)
326     : OptionInfo(option)
327 {
328 }
329
330 SelectionFileOptionStorage &SelectionFileOptionInfo::option()
331 {
332     return static_cast<SelectionFileOptionStorage &>(OptionInfo::option());
333 }
334
335 const SelectionFileOptionStorage &SelectionFileOptionInfo::option() const
336 {
337     return static_cast<const SelectionFileOptionStorage &>(OptionInfo::option());
338 }
339
340 void SelectionFileOptionInfo::setManager(SelectionOptionManager *manager)
341 {
342     option().setManager(manager);
343 }
344
345
346 /********************************************************************
347  * SelectionFileOption
348  */
349
350 SelectionFileOption::SelectionFileOption(const char *name)
351     : AbstractOption(name)
352 {
353     setDescription("Provide selections from files");
354 }
355
356 AbstractOptionStoragePointer SelectionFileOption::createStorage() const
357 {
358     return AbstractOptionStoragePointer(new SelectionFileOptionStorage(*this));
359 }
360
361
362 /********************************************************************
363  * Global functions
364  */
365
366 namespace
367 {
368
369 /*! \internal \brief
370  * Visitor that sets the manager for each selection option.
371  *
372  * \ingroup module_selection
373  */
374 class SelectionOptionManagerSetter : public OptionsModifyingVisitor
375 {
376     public:
377         //! Construct a visitor that sets given manager.
378         explicit SelectionOptionManagerSetter(SelectionOptionManager *manager)
379             : manager_(manager)
380         {
381         }
382
383         void visitSubSection(Options *section)
384         {
385             OptionsModifyingIterator iterator(section);
386             iterator.acceptSubSections(this);
387             iterator.acceptOptions(this);
388         }
389
390         void visitOption(OptionInfo *option)
391         {
392             SelectionOptionInfo *selOption
393                 = option->toType<SelectionOptionInfo>();
394             if (selOption != NULL)
395             {
396                 selOption->setManager(manager_);
397             }
398             SelectionFileOptionInfo *selFileOption
399                 = option->toType<SelectionFileOptionInfo>();
400             if (selFileOption != NULL)
401             {
402                 selFileOption->setManager(manager_);
403             }
404         }
405
406     private:
407         SelectionOptionManager *manager_;
408 };
409
410 } // namespace
411
412 void setManagerForSelectionOptions(Options *options,
413                                    SelectionOptionManager *manager)
414 {
415     SelectionOptionManagerSetter(manager).visitSubSection(options);
416 }
417
418 } // namespace gmx