Merge "Extract doxygen documentation for static symbols."
[alexxy/gromacs.git] / src / gromacs / options / basicoptions.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 basicoptions.h, basicoptioninfo.h and
34  * basicoptionstorage.h.
35  *
36  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
37  * \ingroup module_options
38  */
39 #include "gromacs/options/basicoptions.h"
40
41 #include <cstdio>
42 #include <cstdlib>
43
44 #include <string>
45 #include <vector>
46
47 #include "gromacs/options/basicoptioninfo.h"
48 #include "gromacs/utility/exceptions.h"
49 #include "gromacs/utility/stringutil.h"
50
51 #include "basicoptionstorage.h"
52
53 namespace
54 {
55
56 /*! \brief
57  * Expands a single value to a vector by copying the value.
58  *
59  * \tparam        ValueType  Type of values to process.
60  * \param[in]     length     Length of the resulting vector.
61  * \param[in,out] values     Values to process.
62  * \throws   std::bad_alloc    if out of memory.
63  * \throws   InvalidInputError if \p values has an invalid number of values.
64  *
65  * \p values should have 0, 1, or \p length values.
66  * If \p values has 1 value, it is expanded such that it has \p length
67  * identical values.  In other valid cases, nothing is done.
68  */
69 template <typename ValueType>
70 void expandVector(size_t length, std::vector<ValueType> *values)
71 {
72     if (length > 0 && values->size() > 0 && values->size() != length)
73     {
74         if (values->size() != 1)
75         {
76             GMX_THROW(gmx::InvalidInputError(gmx::formatString(
77                       "Expected 1 or %d values, got %d", length, values->size())));
78         }
79         const ValueType &value = (*values)[0];
80         values->resize(length, value);
81     }
82 }
83
84 } // namespace
85
86 namespace gmx
87 {
88
89 /********************************************************************
90  * BooleanOptionStorage
91  */
92
93 std::string BooleanOptionStorage::formatSingleValue(const bool &value) const
94 {
95     return value ? "yes" : "no";
96 }
97
98 void BooleanOptionStorage::convertValue(const std::string &value)
99 {
100     // TODO: Case-independence
101     if (value == "1" || value == "yes" || value == "true")
102     {
103         addValue(true);
104         return;
105     }
106     else if (value == "0" || value == "no" || value == "false")
107     {
108         addValue(false);
109         return;
110     }
111     GMX_THROW(InvalidInputError("Invalid value: '" + value + "'; supported values are: 1, 0, yes, no, true, false"));
112 }
113
114 /********************************************************************
115  * BooleanOptionInfo
116  */
117
118 BooleanOptionInfo::BooleanOptionInfo(BooleanOptionStorage *option)
119     : OptionInfo(option)
120 {
121 }
122
123 /********************************************************************
124  * BooleanOption
125  */
126
127 AbstractOptionStoragePointer BooleanOption::createStorage() const
128 {
129     return AbstractOptionStoragePointer(new BooleanOptionStorage(*this));
130 }
131
132
133 /********************************************************************
134  * IntegerOptionStorage
135  */
136
137 std::string IntegerOptionStorage::formatSingleValue(const int &value) const
138 {
139     return formatString("%d", value);
140 }
141
142 void IntegerOptionStorage::convertValue(const std::string &value)
143 {
144     const char *ptr = value.c_str();
145     char *endptr;
146     long int ival = std::strtol(ptr, &endptr, 10);
147     if (*endptr != '\0')
148     {
149         GMX_THROW(InvalidInputError("Invalid value: " + value));
150     }
151     addValue(ival);
152 }
153
154 void IntegerOptionStorage::processSetValues(ValueList *values)
155 {
156     if (isVector())
157     {
158         expandVector(maxValueCount(), values);
159     }
160 }
161
162 /********************************************************************
163  * IntegerOptionInfo
164  */
165
166 IntegerOptionInfo::IntegerOptionInfo(IntegerOptionStorage *option)
167     : OptionInfo(option)
168 {
169 }
170
171 /********************************************************************
172  * IntegerOption
173  */
174
175 AbstractOptionStoragePointer IntegerOption::createStorage() const
176 {
177     return AbstractOptionStoragePointer(new IntegerOptionStorage(*this));
178 }
179
180
181 /********************************************************************
182  * DoubleOptionStorage
183  */
184
185 DoubleOptionStorage::DoubleOptionStorage(const DoubleOption &settings)
186     : MyBase(settings), info_(this), bTime_(settings.bTime_), factor_(1.0)
187 {
188 }
189
190 const char *DoubleOptionStorage::typeString() const
191 {
192     return isVector() ? "vector" : (isTime() ? "time" : "double");
193 }
194
195 std::string DoubleOptionStorage::formatSingleValue(const double &value) const
196 {
197     return formatString("%g", value / factor_);
198 }
199
200 void DoubleOptionStorage::convertValue(const std::string &value)
201 {
202     const char *ptr = value.c_str();
203     char *endptr;
204     double dval = std::strtod(ptr, &endptr);
205     if (*endptr != '\0')
206     {
207         GMX_THROW(InvalidInputError("Invalid value: " + value));
208     }
209     addValue(dval * factor_);
210 }
211
212 void DoubleOptionStorage::processSetValues(ValueList *values)
213 {
214     if (isVector())
215     {
216         expandVector(maxValueCount(), values);
217     }
218 }
219
220 void DoubleOptionStorage::processAll()
221 {
222 }
223
224 void DoubleOptionStorage::setScaleFactor(double factor)
225 {
226     GMX_RELEASE_ASSERT(factor > 0.0, "Invalid scaling factor");
227     if (!hasFlag(efOption_HasDefaultValue))
228     {
229         double scale = factor / factor_;
230         ValueList::iterator i;
231         for (i = values().begin(); i != values().end(); ++i)
232         {
233             (*i) *= scale;
234         }
235         refreshValues();
236     }
237     factor_ = factor;
238 }
239
240 /********************************************************************
241  * DoubleOptionInfo
242  */
243
244 DoubleOptionInfo::DoubleOptionInfo(DoubleOptionStorage *option)
245     : OptionInfo(option)
246 {
247 }
248
249 DoubleOptionStorage &DoubleOptionInfo::option()
250 {
251     return static_cast<DoubleOptionStorage &>(OptionInfo::option());
252 }
253
254 const DoubleOptionStorage &DoubleOptionInfo::option() const
255 {
256     return static_cast<const DoubleOptionStorage &>(OptionInfo::option());
257 }
258
259 bool DoubleOptionInfo::isTime() const
260 {
261     return option().isTime();
262 }
263
264 void DoubleOptionInfo::setScaleFactor(double factor)
265 {
266     option().setScaleFactor(factor);
267 }
268
269 /********************************************************************
270  * DoubleOption
271  */
272
273 AbstractOptionStoragePointer DoubleOption::createStorage() const
274 {
275     return AbstractOptionStoragePointer(new DoubleOptionStorage(*this));
276 }
277
278
279 /********************************************************************
280  * StringOptionStorage
281  */
282
283 StringOptionStorage::StringOptionStorage(const StringOption &settings)
284     : MyBase(settings), info_(this), enumIndexStore_(NULL)
285 {
286     if (settings.defaultEnumIndex_ >= 0 && settings.enumValues_ == NULL)
287     {
288         GMX_THROW(APIError("Cannot set default enum index without enum values"));
289     }
290     if (settings.enumIndexStore_ != NULL && settings.enumValues_ == NULL)
291     {
292         GMX_THROW(APIError("Cannot set enum index store without enum values"));
293     }
294     if (settings.enumIndexStore_ != NULL && settings.maxValueCount_ < 0)
295     {
296         GMX_THROW(APIError("Cannot set enum index store with arbitrary number of values"));
297     }
298     if (settings.enumValues_ != NULL)
299     {
300         enumIndexStore_ = settings.enumIndexStore_;
301         const std::string *defaultValue = settings.defaultValue();
302         int match = -1;
303         for (int i = 0; settings.enumValues_[i] != NULL; ++i)
304         {
305             if (defaultValue != NULL && settings.enumValues_[i] == *defaultValue)
306             {
307                 match = i;
308             }
309             allowed_.push_back(settings.enumValues_[i]);
310         }
311         if (defaultValue != NULL)
312         {
313             if (match < 0)
314             {
315                 GMX_THROW(APIError("Default value is not one of allowed values"));
316             }
317         }
318         if (settings.defaultEnumIndex_ >= 0)
319         {
320             if (settings.defaultEnumIndex_ >= static_cast<int>(allowed_.size()))
321             {
322                 GMX_THROW(APIError("Default enumeration index is out of range"));
323             }
324             if (defaultValue != NULL && *defaultValue != allowed_[settings.defaultEnumIndex_])
325             {
326                 GMX_THROW(APIError("Conflicting default values"));
327             }
328         }
329         // If there is no default value, match is still -1.
330         if (enumIndexStore_ != NULL)
331         {
332             *enumIndexStore_ = match;
333         }
334     }
335     if (settings.defaultEnumIndex_ >= 0)
336     {
337         clear();
338         addValue(allowed_[settings.defaultEnumIndex_]);
339         commitValues();
340     }
341 }
342
343 std::string StringOptionStorage::formatSingleValue(const std::string &value) const
344 {
345     return value;
346 }
347
348 void StringOptionStorage::convertValue(const std::string &value)
349 {
350     if (allowed_.size() == 0)
351     {
352         addValue(value);
353     }
354     else
355     {
356         ValueList::const_iterator  i;
357         ValueList::const_iterator  match = allowed_.end();
358         for (i = allowed_.begin(); i != allowed_.end(); ++i)
359         {
360             // TODO: Case independence.
361             if (i->find(value) == 0)
362             {
363                 if (match == allowed_.end() || i->size() < match->size())
364                 {
365                     match = i;
366                 }
367             }
368         }
369         if (match == allowed_.end())
370         {
371             GMX_THROW(InvalidInputError("Invalid value: " + value));
372         }
373         addValue(*match);
374     }
375 }
376
377 void StringOptionStorage::refreshValues()
378 {
379     MyBase::refreshValues();
380     if (enumIndexStore_ != NULL)
381     {
382         for (size_t i = 0; i < values().size(); ++i)
383         {
384             ValueList::const_iterator match =
385                 std::find(allowed_.begin(), allowed_.end(), values()[i]);
386             GMX_ASSERT(match != allowed_.end(),
387                        "Enum value not found (internal error)");
388             enumIndexStore_[i] = static_cast<int>(match - allowed_.begin());
389         }
390     }
391 }
392
393 /********************************************************************
394  * StringOptionInfo
395  */
396
397 StringOptionInfo::StringOptionInfo(StringOptionStorage *option)
398     : OptionInfo(option)
399 {
400 }
401
402 /********************************************************************
403  * StringOption
404  */
405
406 AbstractOptionStoragePointer StringOption::createStorage() const
407 {
408     return AbstractOptionStoragePointer(new StringOptionStorage(*this));
409 }
410
411 std::string StringOption::createDescription() const
412 {
413     std::string value(MyBase::createDescription());
414
415     if (enumValues_ != NULL)
416     {
417         value.append(": ");
418         for (int i = 0; enumValues_[i] != NULL; ++i)
419         {
420             value.append(enumValues_[i]);
421             if (enumValues_[i + 1] != NULL)
422             {
423                 value.append(enumValues_[i + 2] != NULL ? ", " : ", or ");
424             }
425         }
426     }
427     return value;
428 }
429
430 } // namespace gmx