923384d7e7fc2d1adaa9cd23510a4faa5d1e6543
[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,2014, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source 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 "gmxpre.h"
43
44 #include "selectionoption.h"
45 #include "selectionfileoption.h"
46 #include "selectionoptionstorage.h"
47 #include "selectionfileoptionstorage.h"
48
49 #include <string>
50
51 #include "gromacs/options/optionmanagercontainer.h"
52 #include "gromacs/selection/selection.h"
53 #include "gromacs/selection/selectionoptionmanager.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/gmxassert.h"
56 #include "gromacs/utility/messagestringcollector.h"
57
58 namespace gmx
59 {
60
61 /********************************************************************
62  * SelectionOptionStorage
63  */
64
65 SelectionOptionStorage::SelectionOptionStorage(const SelectionOption  &settings,
66                                                SelectionOptionManager *manager)
67     : MyBase(settings, OptionFlags() | efOption_NoDefaultValue
68              | efOption_DontCheckMinimumCount),
69       info_(this), manager_(*manager), defaultText_(settings.defaultText_),
70       selectionFlags_(settings.selectionFlags_)
71 {
72     GMX_RELEASE_ASSERT(manager != NULL,
73                        "SelectionOptionManager must be added before SelectionOption");
74     GMX_RELEASE_ASSERT(!hasFlag(efOption_MultipleTimes),
75                        "allowMultiple() is not supported for selection options");
76     manager_.registerOption(this);
77 }
78
79
80 std::string SelectionOptionStorage::formatSingleValue(const Selection &value) const
81 {
82     return value.selectionText();
83 }
84
85
86 void SelectionOptionStorage::addSelections(
87         const SelectionList &selections,
88         bool                 bFullValue)
89 {
90     if (bFullValue && selections.size() < static_cast<size_t>(minValueCount()))
91     {
92         GMX_THROW(InvalidInputError("Too few selections provided"));
93     }
94     if (bFullValue)
95     {
96         clearSet();
97     }
98     SelectionList::const_iterator i;
99     for (i = selections.begin(); i != selections.end(); ++i)
100     {
101         // TODO: Having this check in the parser would make interactive input
102         // behave better.
103         if (selectionFlags_.test(efSelection_OnlyStatic) && i->isDynamic())
104         {
105             GMX_THROW(InvalidInputError("Dynamic selections not supported"));
106         }
107         // Create a copy to allow modifications.
108         Selection sel(*i);
109         sel.data().setFlags(selectionFlags_);
110         addValue(sel);
111     }
112     if (bFullValue)
113     {
114         commitValues();
115         markAsSet();
116     }
117 }
118
119
120 void SelectionOptionStorage::convertValue(const std::string &value)
121 {
122     manager_.convertOptionValue(this, value, false);
123 }
124
125 void SelectionOptionStorage::processSetValues(ValueList *values)
126 {
127     if (values->size() == 0)
128     {
129         manager_.requestOptionDelayedParsing(this);
130     }
131     else if (values->size() < static_cast<size_t>(minValueCount()))
132     {
133         GMX_THROW(InvalidInputError("Too few (valid) values provided"));
134     }
135 }
136
137 void SelectionOptionStorage::processAll()
138 {
139     if (!isSet() && !defaultText_.empty())
140     {
141         manager_.convertOptionValue(this, defaultText_, true);
142     }
143     if (isRequired() && !isSet())
144     {
145         manager_.requestOptionDelayedParsing(this);
146         markAsSet();
147     }
148 }
149
150 void SelectionOptionStorage::setAllowedValueCount(int count)
151 {
152     // TODO: It should be possible to have strong exception safety here.
153     MessageStringCollector errors;
154     errors.startContext("In option '" + name() + "'");
155     if (count >= 0)
156     {
157         // Should not throw because efOption_DontCheckMinimumCount is set.
158         setMinValueCount(count);
159         if (valueCount() > 0 && valueCount() < count)
160         {
161             errors.append("Too few (valid) values provided");
162         }
163     }
164     try
165     {
166         setMaxValueCount(count);
167     }
168     catch (const UserInputError &ex)
169     {
170         errors.append(ex.what());
171     }
172     errors.finishContext();
173     if (!errors.isEmpty())
174     {
175         GMX_THROW(InvalidInputError(errors.toString()));
176     }
177 }
178
179 void SelectionOptionStorage::setSelectionFlag(SelectionFlag flag, bool bSet)
180 {
181     ValueList::iterator i;
182     for (i = values().begin(); i != values().end(); ++i)
183     {
184         if (flag == efSelection_OnlyStatic && bSet && i->isDynamic())
185         {
186             MessageStringCollector errors;
187             errors.startContext("In option '" + name() + "'");
188             errors.append("Dynamic selections not supported");
189             errors.finishContext();
190             GMX_THROW(InvalidInputError(errors.toString()));
191         }
192     }
193     selectionFlags_.set(flag, bSet);
194     for (i = values().begin(); i != values().end(); ++i)
195     {
196         i->data().setFlags(selectionFlags_);
197     }
198 }
199
200
201 /********************************************************************
202  * SelectionOptionInfo
203  */
204
205 SelectionOptionInfo::SelectionOptionInfo(SelectionOptionStorage *option)
206     : OptionInfo(option)
207 {
208 }
209
210 SelectionOptionStorage &SelectionOptionInfo::option()
211 {
212     return static_cast<SelectionOptionStorage &>(OptionInfo::option());
213 }
214
215 const SelectionOptionStorage &SelectionOptionInfo::option() const
216 {
217     return static_cast<const SelectionOptionStorage &>(OptionInfo::option());
218 }
219
220 void SelectionOptionInfo::setValueCount(int count)
221 {
222     option().setAllowedValueCount(count);
223 }
224
225 void SelectionOptionInfo::setEvaluateVelocities(bool bEnabled)
226 {
227     option().setSelectionFlag(efSelection_EvaluateVelocities, bEnabled);
228 }
229
230 void SelectionOptionInfo::setEvaluateForces(bool bEnabled)
231 {
232     option().setSelectionFlag(efSelection_EvaluateForces, bEnabled);
233 }
234
235 void SelectionOptionInfo::setOnlyAtoms(bool bEnabled)
236 {
237     option().setSelectionFlag(efSelection_OnlyAtoms, bEnabled);
238 }
239
240 void SelectionOptionInfo::setOnlyStatic(bool bEnabled)
241 {
242     option().setSelectionFlag(efSelection_OnlyStatic, bEnabled);
243 }
244
245 void SelectionOptionInfo::setDynamicMask(bool bEnabled)
246 {
247     option().setSelectionFlag(efSelection_DynamicMask, bEnabled);
248 }
249
250
251 /********************************************************************
252  * SelectionOption
253  */
254
255 AbstractOptionStorage *
256 SelectionOption::createStorage(const OptionManagerContainer &managers) const
257 {
258     return new SelectionOptionStorage(
259             *this, managers.get<SelectionOptionManager>());
260 }
261
262
263 /********************************************************************
264  * SelectionFileOptionStorage
265  */
266
267 SelectionFileOptionStorage::SelectionFileOptionStorage(
268         const SelectionFileOption &settings, SelectionOptionManager *manager)
269     : AbstractOptionStorage(settings, OptionFlags() | efOption_MultipleTimes
270                             | efOption_DontCheckMinimumCount),
271       info_(this), manager_(*manager), bValueParsed_(false)
272 {
273     GMX_RELEASE_ASSERT(manager != NULL,
274                        "SelectionOptionManager must be added before SelectionFileOption");
275 }
276
277 void SelectionFileOptionStorage::clearSet()
278 {
279     bValueParsed_ = false;
280 }
281
282 void SelectionFileOptionStorage::convertValue(const std::string &value)
283 {
284     if (bValueParsed_)
285     {
286         GMX_THROW(InvalidInputError("More than one file name provided"));
287     }
288     bValueParsed_ = true;
289     // TODO: Should we throw an InvalidInputError if the file does not exist?
290     manager_.parseRequestedFromFile(value);
291 }
292
293 void SelectionFileOptionStorage::processSet()
294 {
295     if (!bValueParsed_)
296     {
297         GMX_THROW(InvalidInputError("No file name provided"));
298     }
299 }
300
301
302 /********************************************************************
303  * SelectionFileOptionInfo
304  */
305
306 SelectionFileOptionInfo::SelectionFileOptionInfo(SelectionFileOptionStorage *option)
307     : OptionInfo(option)
308 {
309 }
310
311
312 /********************************************************************
313  * SelectionFileOption
314  */
315
316 SelectionFileOption::SelectionFileOption(const char *name)
317     : AbstractOption(name)
318 {
319     setDescription("Provide selections from files");
320 }
321
322 AbstractOptionStorage *
323 SelectionFileOption::createStorage(const OptionManagerContainer &managers) const
324 {
325     return new SelectionFileOptionStorage(
326             *this, managers.get<SelectionOptionManager>());
327 }
328
329 } // namespace gmx