Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / selection / selectionoption.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS 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 GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements classes in selectionoption.h and selectionoptionstorage.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include "selectionoption.h"
43 #include "selectionfileoption.h"
44 #include "selectionoptionstorage.h"
45 #include "selectionfileoptionstorage.h"
46
47 #include <string>
48
49 #include "gromacs/selection/selection.h"
50 #include "gromacs/selection/selectionoptionmanager.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/gmxassert.h"
53 #include "gromacs/utility/messagestringcollector.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 }
70
71
72 void SelectionOptionStorage::setManager(SelectionOptionManager *manager)
73 {
74     GMX_RELEASE_ASSERT(manager_ == NULL || manager_ == manager,
75                        "Manager cannot be changed once set");
76     if (manager_ == NULL)
77     {
78         manager->registerOption(this);
79         manager_ = manager;
80     }
81 }
82
83
84 std::string SelectionOptionStorage::formatSingleValue(const Selection &value) const
85 {
86     return value.selectionText();
87 }
88
89
90 void SelectionOptionStorage::addSelections(
91         const SelectionList &selections,
92         bool                 bFullValue)
93 {
94     if (bFullValue && selections.size() < static_cast<size_t>(minValueCount()))
95     {
96         GMX_THROW(InvalidInputError("Too few selections provided"));
97     }
98     if (bFullValue)
99     {
100         clearSet();
101     }
102     SelectionList::const_iterator i;
103     for (i = selections.begin(); i != selections.end(); ++i)
104     {
105         // TODO: Having this check in the parser would make interactive input
106         // behave better.
107         if (selectionFlags_.test(efSelection_OnlyStatic) && i->isDynamic())
108         {
109             GMX_THROW(InvalidInputError("Dynamic selections not supported"));
110         }
111         // Create a copy to allow modifications.
112         Selection sel(*i);
113         sel.data().setFlags(selectionFlags_);
114         addValue(sel);
115     }
116     if (bFullValue)
117     {
118         commitValues();
119         markAsSet();
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 }
144
145 void SelectionOptionStorage::processAll()
146 {
147     if (isRequired() && !isSet())
148     {
149         GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
150
151         manager_->requestOptionDelayedParsing(this);
152         markAsSet();
153     }
154 }
155
156 void SelectionOptionStorage::setAllowedValueCount(int count)
157 {
158     // TODO: It should be possible to have strong exception safety here.
159     MessageStringCollector errors;
160     errors.startContext("In option '" + name() + "'");
161     if (count >= 0)
162     {
163         // Should not throw because efOption_DontCheckMinimumCount is set.
164         setMinValueCount(count);
165         if (valueCount() > 0 && valueCount() < count)
166         {
167             errors.append("Too few (valid) values provided");
168         }
169     }
170     try
171     {
172         setMaxValueCount(count);
173     }
174     catch (const UserInputError &ex)
175     {
176         errors.append(ex.what());
177     }
178     errors.finishContext();
179     if (!errors.isEmpty())
180     {
181         GMX_THROW(InvalidInputError(errors.toString()));
182     }
183 }
184
185 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
186 {
187     ValueList::iterator i;
188     for (i = values().begin(); i != values().end(); ++i)
189     {
190         if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
191         {
192             MessageStringCollector errors;
193             errors.startContext("In option '" + name() + "'");
194             errors.append("Dynamic selections not supported");
195             errors.finishContext();
196             GMX_THROW(InvalidInputError(errors.toString()));
197         }
198     }
199     selectionFlags_.set(flag, bSet);
200     for (i = values().begin(); i != values().end(); ++i)
201     {
202         i->data().setFlags(selectionFlags_);
203     }
204 }
205
206
207 /********************************************************************
208  * SelectionOptionInfo
209  */
210
211 SelectionOptionInfo::SelectionOptionInfo(SelectionOptionStorage *option)
212     : OptionInfo(option)
213 {
214 }
215
216 SelectionOptionStorage &SelectionOptionInfo::option()
217 {
218     return static_cast<SelectionOptionStorage &>(OptionInfo::option());
219 }
220
221 const SelectionOptionStorage &SelectionOptionInfo::option() const
222 {
223     return static_cast<const SelectionOptionStorage &>(OptionInfo::option());
224 }
225
226 void SelectionOptionInfo::setManager(SelectionOptionManager *manager)
227 {
228     option().setManager(manager);
229 }
230
231 void SelectionOptionInfo::setValueCount(int count)
232 {
233     option().setAllowedValueCount(count);
234 }
235
236 void SelectionOptionInfo::setEvaluateVelocities(bool bEnabled)
237 {
238     option().setSelectionFlag(efSelection_EvaluateVelocities, bEnabled);
239 }
240
241 void SelectionOptionInfo::setEvaluateForces(bool bEnabled)
242 {
243     option().setSelectionFlag(efSelection_EvaluateForces, bEnabled);
244 }
245
246 void SelectionOptionInfo::setOnlyAtoms(bool bEnabled)
247 {
248     option().setSelectionFlag(efSelection_OnlyAtoms, bEnabled);
249 }
250
251 void SelectionOptionInfo::setOnlyStatic(bool bEnabled)
252 {
253     option().setSelectionFlag(efSelection_OnlyStatic, bEnabled);
254 }
255
256 void SelectionOptionInfo::setDynamicMask(bool bEnabled)
257 {
258     option().setSelectionFlag(efSelection_DynamicMask, bEnabled);
259 }
260
261
262 /********************************************************************
263  * SelectionOption
264  */
265
266 AbstractOptionStoragePointer SelectionOption::createStorage() const
267 {
268     return AbstractOptionStoragePointer(new SelectionOptionStorage(*this));
269 }
270
271
272 /********************************************************************
273  * SelectionFileOptionStorage
274  */
275
276 SelectionFileOptionStorage::SelectionFileOptionStorage(const SelectionFileOption &settings)
277     : AbstractOptionStorage(settings, OptionFlags() | efOption_MultipleTimes
278                             | efOption_DontCheckMinimumCount),
279       info_(this), manager_(NULL), bValueParsed_(false)
280 {
281 }
282
283 void SelectionFileOptionStorage::clearSet()
284 {
285     bValueParsed_ = false;
286 }
287
288 void SelectionFileOptionStorage::convertValue(const std::string &value)
289 {
290     GMX_RELEASE_ASSERT(manager_ != NULL, "Manager is not set");
291
292     if (bValueParsed_)
293     {
294         GMX_THROW(InvalidInputError("More than one file name provided"));
295     }
296     bValueParsed_ = true;
297     // TODO: Should we throw an InvalidInputError if the file does not exist?
298     manager_->parseRequestedFromFile(value);
299 }
300
301 void SelectionFileOptionStorage::processSet()
302 {
303     if (!bValueParsed_)
304     {
305         GMX_THROW(InvalidInputError("No file name provided"));
306     }
307 }
308
309
310 /********************************************************************
311  * SelectionFileOptionInfo
312  */
313
314 SelectionFileOptionInfo::SelectionFileOptionInfo(SelectionFileOptionStorage *option)
315     : OptionInfo(option)
316 {
317 }
318
319 SelectionFileOptionStorage &SelectionFileOptionInfo::option()
320 {
321     return static_cast<SelectionFileOptionStorage &>(OptionInfo::option());
322 }
323
324 const SelectionFileOptionStorage &SelectionFileOptionInfo::option() const
325 {
326     return static_cast<const SelectionFileOptionStorage &>(OptionInfo::option());
327 }
328
329 void SelectionFileOptionInfo::setManager(SelectionOptionManager *manager)
330 {
331     option().setManager(manager);
332 }
333
334
335 /********************************************************************
336  * SelectionFileOption
337  */
338
339 SelectionFileOption::SelectionFileOption(const char *name)
340     : AbstractOption(name)
341 {
342     setDescription("Provide selections from files");
343 }
344
345 AbstractOptionStoragePointer SelectionFileOption::createStorage() const
346 {
347     return AbstractOptionStoragePointer(new SelectionFileOptionStorage(*this));
348 }
349
350 } // namespace gmx