75d8e2d4549972d01e8c5d0143b75d78bd3debca
[alexxy/gromacs.git] / src / gromacs / options / basicoptions.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010-2018, The GROMACS development team.
5  * Copyright (c) 2019, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36 /*! \file
37  * \brief
38  * Declares option objects for basic option types.
39  *
40  * Together with options.h, this header forms the part of the public API
41  * that most classes will use to provide options.
42  *
43  * \author Teemu Murtola <teemu.murtola@gmail.com>
44  * \inpublicapi
45  * \ingroup module_options
46  */
47 #ifndef GMX_OPTIONS_BASICOPTIONS_H
48 #define GMX_OPTIONS_BASICOPTIONS_H
49
50 #include <memory>
51 #include <string>
52 #include <vector>
53
54 #include "gromacs/options/abstractoption.h"
55 #include "gromacs/utility/arrayref.h"
56 #include "gromacs/utility/basedefinitions.h"
57 #include "gromacs/utility/gmxassert.h"
58
59 #include "ivaluestore.h"
60
61 namespace gmx
62 {
63
64 class BooleanOptionInfo;
65 class BooleanOptionStorage;
66 class IntegerOptionInfo;
67 class IntegerOptionStorage;
68 class Int64OptionInfo;
69 class Int64OptionStorage;
70 class DoubleOptionInfo;
71 class DoubleOptionStorage;
72 class FloatOptionInfo;
73 class FloatOptionStorage;
74 class StringOptionInfo;
75 class StringOptionStorage;
76 class EnumOptionInfo;
77 class EnumOptionStorage;
78
79 //! \addtogroup module_options
80 //! \{
81
82 /*! \brief
83  * Specifies an option that provides boolean values.
84  *
85  * Example:
86  * \code
87    bool  bPBC;
88    using gmx::BooleanOption;
89    options.addOption(BooleanOption("pbc").store(&bPBC));
90  * \endcode
91  *
92  * Public methods in this class do not throw.
93  *
94  * \inpublicapi
95  */
96 class BooleanOption : public OptionTemplate<bool, BooleanOption>
97 {
98 public:
99     //! OptionInfo subclass corresponding to this option type.
100     typedef BooleanOptionInfo InfoType;
101
102     //! Initializes an option with the given name.
103     explicit BooleanOption(const char* name) : MyBase(name) {}
104
105 private:
106     //! Creates a BooleanOptionStorage object.
107     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
108 };
109
110 /*! \brief
111  * Specifies an option that provides integer values.
112  *
113  * Examples:
114  * \code
115    using gmx::IntegerOption;
116    // Simple option
117    int  rcut = 0;
118    options.addOption(IntegerOption("rcut").store(&rcut));
119    // Vector-valued option
120    int  box[3] = {1, 1, 1};  // Default value
121    options.addOption(IntegerOption("box").store(box).vector());
122  * \endcode
123  *
124  * Public methods in this class do not throw.
125  *
126  * \inpublicapi
127  */
128 class IntegerOption : public OptionTemplate<int, IntegerOption>
129 {
130 public:
131     //! OptionInfo subclass corresponding to this option type.
132     typedef IntegerOptionInfo InfoType;
133
134     //! Initializes an option with the given name.
135     explicit IntegerOption(const char* name) : MyBase(name) {}
136
137     /*! \brief
138      * Sets the option to return a vector value.
139      *
140      * A vector value returns a fixed number of values, the default being
141      * three (can be changed with valueCount()).  However, it also accepts
142      * a single value, in which case the value is used to fill the whole
143      * vector.
144      */
145     MyClass& vector()
146     {
147         setVector();
148         return me();
149     }
150
151 private:
152     //! Creates an IntegerOptionStorage object.
153     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
154
155     /*! \brief
156      * Needed to initialize IntegerOptionStorage from this class without
157      * otherwise unnecessary accessors.
158      */
159     friend class IntegerOptionStorage;
160 };
161
162 /*! \brief
163  * Specifies an option that provides 64-bit integer values.
164  *
165  * Public methods in this class do not throw.
166  *
167  * \see IntegerOption
168  *
169  * \inpublicapi
170  */
171 class Int64Option : public OptionTemplate<int64_t, Int64Option>
172 {
173 public:
174     //! OptionInfo subclass corresponding to this option type.
175     typedef Int64OptionInfo InfoType;
176
177     //! Initializes an option with the given name.
178     explicit Int64Option(const char* name) : MyBase(name) {}
179
180 private:
181     //! Creates an Int64OptionStorage object.
182     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
183
184     /*! \brief
185      * Needed to initialize Int64OptionStorage from this class without
186      * otherwise unnecessary accessors.
187      */
188     friend class Int64OptionStorage;
189 };
190
191 /*! \brief
192  * Specifies an option that provides floating-point (double) values.
193  *
194  * Public methods in this class do not throw.
195  *
196  * \inpublicapi
197  */
198 class DoubleOption : public OptionTemplate<double, DoubleOption>
199 {
200 public:
201     //! OptionInfo subclass corresponding to this option type.
202     typedef DoubleOptionInfo InfoType;
203
204     //! Initializes an option with the given name.
205     explicit DoubleOption(const char* name) : MyBase(name), bTime_(false) {}
206
207     //! \copydoc IntegerOption::vector()
208     MyClass& vector()
209     {
210         setVector();
211         return me();
212     }
213     /*! \brief
214      * Marks this option as providing a time value whose unit can be changed.
215      *
216      * By itself, this option does nothing.  It marks the option as a time
217      * value such that TimeUnitManager::scaleTimeOptions() can process it.
218      * In typical cases, \Gromacs scales the time options just before
219      * Options::finish() has been called, so the option value is only
220      * available after all option values have been processed.
221      * All values in the program are in ps (including any default value);
222      * user-provided values are scaled according to the time unit set in
223      * TimeUnitManager.
224      */
225     MyClass& timeValue()
226     {
227         bTime_ = true;
228         return me();
229     }
230
231 private:
232     //! Creates a DoubleOptionStorage object.
233     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
234
235     bool bTime_;
236
237     /*! \brief
238      * Needed to initialize DoubleOptionStorage from this class without
239      * otherwise unnecessary accessors.
240      */
241     friend class DoubleOptionStorage;
242 };
243
244 /*! \brief
245  * Specifies an option that provides floating-point (float) values.
246  *
247  * Public methods in this class do not throw.
248  *
249  * \see DoubleOption
250  *
251  * \inpublicapi
252  */
253 class FloatOption : public OptionTemplate<float, FloatOption>
254 {
255 public:
256     //! OptionInfo subclass corresponding to this option type.
257     typedef FloatOptionInfo InfoType;
258
259     //! Initializes an option with the given name.
260     explicit FloatOption(const char* name) : MyBase(name), bTime_(false) {}
261
262     //! \copydoc IntegerOption::vector()
263     MyClass& vector()
264     {
265         setVector();
266         return me();
267     }
268     //! \copydoc DoubleOption::timeValue()
269     MyClass& timeValue()
270     {
271         bTime_ = true;
272         return me();
273     }
274
275 private:
276     //! Creates a FloatOptionStorage object.
277     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
278
279     bool bTime_;
280
281     /*! \brief
282      * Needed to initialize FloatOptionStorage from this class without
283      * otherwise unnecessary accessors.
284      */
285     friend class FloatOptionStorage;
286 };
287
288 /*! \brief
289  * Specifies an option that provides string values.
290  *
291  * Examples:
292  * \code
293    using gmx::StringOption;
294    // Simple option
295    std::string  str;
296    options.addOption(StringOption("str").store(&str));
297    // Option that only accepts predefined values
298    const char * const  allowed[] = { "atom", "residue", "molecule" };
299    std::string  str;
300    options.addOption(StringOption("type").enumValue(allowed).store(&str));
301  * \endcode
302  *
303  * Public methods in this class do not throw.
304  *
305  * \inpublicapi
306  */
307 class StringOption : public OptionTemplate<std::string, StringOption>
308 {
309 public:
310     //! OptionInfo subclass corresponding to this option type.
311     typedef StringOptionInfo InfoType;
312
313     //! Initializes an option with the given name.
314     explicit StringOption(const char* name) :
315         MyBase(name),
316         enumValues_(nullptr),
317         enumValuesCount_(0),
318         defaultEnumIndex_(-1)
319     {
320     }
321
322     /*! \brief
323      * Sets the option to only accept one of a fixed set of strings.
324      *
325      * \param[in] values  Array of strings to accept.
326      *
327      * Also accepts prefixes of the strings; if a prefix matches more than
328      * one of the possible strings, the shortest one is used (in a tie, the
329      * first one is).
330      *
331      * The strings are copied once the option is created.
332      */
333     template<size_t count>
334     MyClass& enumValue(const char* const (&values)[count])
335     {
336         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
337         enumValues_      = values;
338         enumValuesCount_ = count;
339         return me();
340     }
341     /*! \brief
342      * Sets the option to only accept one of a fixed set of strings.
343      *
344      * \param[in] values  Array of strings to accept, with a NULL pointer
345      *      following the last string.
346      *
347      * Works otherwise as the array version, but accepts a pointer to
348      * an array of undetermined length.  The end of the array is indicated
349      * by a NULL pointer in the array.
350      *
351      * \see enumValue()
352      */
353     MyClass& enumValueFromNullTerminatedArray(const char* const* values)
354     {
355         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
356         enumValues_      = values;
357         enumValuesCount_ = -1;
358         return me();
359     }
360     /*! \brief
361      * Sets the default value using an index into the enumeration table.
362      *
363      * Cannot be specified without enumValue().
364      */
365     MyClass& defaultEnumIndex(int index)
366     {
367         GMX_ASSERT(index >= 0, "Invalid enumeration index");
368         defaultEnumIndex_ = index;
369         return me();
370     }
371
372 private:
373     //! Creates a StringOptionStorage object.
374     AbstractOptionStorage* createStorage(const OptionManagerContainer& managers) const override;
375
376     const char* const* enumValues_;
377     int                enumValuesCount_;
378     int                defaultEnumIndex_;
379
380     /*! \brief
381      * Needed to initialize StringOptionStorage from this class without
382      * otherwise unnecessary accessors.
383      */
384     friend class StringOptionStorage;
385 };
386
387 //! \}
388
389 namespace internal
390 {
391
392 /*! \internal
393  * \brief
394  * Type-specific implementation for IOptionValueStore for an enum option.
395  *
396  * This class is instantiated for each enum type for which EnumOption is used,
397  * and takes care of managing `int`-to-`enum` conversions.  Having this part in
398  * the header allows the actual storage implementation to not be in the header,
399  * which would require exposing all the internals through this one header...
400  *
401  * \ingroup module_options
402  */
403 template<typename EnumType>
404 class EnumIndexStore : public IOptionValueStore<int>
405 {
406 public:
407     //! Initializes the storage for the given actual enum variables.
408     EnumIndexStore(EnumType* store, std::vector<EnumType>* storeVector) :
409         store_(store),
410         storeVector_(storeVector)
411     {
412         if (storeVector_ != nullptr)
413         {
414             for (EnumType value : *storeVector_)
415             {
416                 intStore_.push_back(static_cast<int>(value));
417             }
418         }
419         else if (store_ != nullptr)
420         {
421             // TODO: Copy more than one value if that would make sense.
422             intStore_.push_back(static_cast<int>(store_[0]));
423         }
424     }
425
426     int           valueCount() override { return ssize(intStore_); }
427     ArrayRef<int> values() override { return intStore_; }
428     void          clear() override
429     {
430         intStore_.clear();
431         if (storeVector_ != nullptr)
432         {
433             storeVector_->clear();
434         }
435     }
436     void reserve(size_t count) override
437     {
438         intStore_.reserve(intStore_.size() + count);
439         if (storeVector_ != nullptr)
440         {
441             storeVector_->reserve(storeVector_->size() + count);
442         }
443     }
444     void append(const int& value) override
445     {
446         const size_t count = intStore_.size();
447         intStore_.push_back(value);
448         if (store_ != nullptr)
449         {
450             store_[count] = static_cast<EnumType>(value);
451         }
452         if (storeVector_ != nullptr)
453         {
454             storeVector_->push_back(static_cast<EnumType>(value));
455         }
456     }
457
458 private:
459     //! Stores the integer values for values().
460     std::vector<int>       intStore_;
461     EnumType*              store_;
462     std::vector<EnumType>* storeVector_;
463 };
464
465 //! \cond internal
466 /*! \internal
467  * \brief
468  * Helper to create EnumOptionStorage instances.
469  *
470  * This function works as a proxy between EnumOption::createStorage() and the
471  * EnumOptionStorage constructor, such that the latter does not need to be
472  * exposed in the header.
473  *
474  * \ingroup module_options
475  */
476 AbstractOptionStorage* createEnumOptionStorage(const AbstractOption& option,
477                                                const char* const*    enumValues,
478                                                int                   count,
479                                                int                   defaultValue,
480                                                int                   defaultValueIfSet,
481                                                std::unique_ptr<IOptionValueStore<int>> store);
482 //! \endcond
483
484 } // namespace internal
485
486 //! \addtogroup module_options
487 //! \{
488
489 /*! \brief
490  * Specifies an option that accepts enumerated string values and writes the
491  * selected index into an `enum` variable.
492  *
493  * \tparam EnumType  Type of the variable that receives the values
494  *     (can also be `int`).
495  *
496  * Examples:
497  * \code
498    enum MyEnum { eAtom, eRes, eMol };
499    using gmx::EnumOption;
500    const char * const  allowed[] = { "atom", "residue", "molecule" };
501    MyEnum       value = eAtom; // default value
502    options.addOption(EnumOption<MyEnum>("type").enumValue(allowed).store(&value));
503  * \endcode
504  *
505  * storeCount() is not currently implemented for this option type, and
506  * providing multiple default values through an array passed to store() does
507  * not work consistently in all cases.
508  * In the current implementation, the values of the enum type should correspond
509  * to indices in the array passed to enumValue(), i.e., be consencutive
510  * starting from zero.  Only values corresponding to valid indices are accepted
511  * as parameters to, e.g., defaultValue().  However, other values can be used
512  * as the initial value of the variable (`value` in the above example), and
513  * those will be preserved if the option is not set.
514  *
515  * Public methods in this class do not throw.
516  *
517  * \inpublicapi
518  */
519 template<typename EnumType>
520 class EnumOption : public OptionTemplate<EnumType, EnumOption<EnumType>>
521 {
522 public:
523     //! OptionInfo subclass corresponding to this option type.
524     typedef EnumOptionInfo InfoType;
525
526     // This needs to be duplicated from OptionTemplate because this class
527     // is a template.
528     //! Short-hand for the base class.
529     typedef OptionTemplate<EnumType, EnumOption<EnumType>> MyBase;
530
531     //! Initializes an option with the given name.
532     explicit EnumOption(const char* name) : MyBase(name), enumValues_(nullptr), enumValuesCount_(0)
533     {
534     }
535
536     /*! \brief
537      * Sets the option to only accept one of a fixed set of strings.
538      *
539      * \param[in] values  Array of strings to accept.
540      *
541      * Also accepts prefixes of the strings; if a prefix matches more than
542      * one of the possible strings, the shortest one is used (in a tie, the
543      * first one is).
544      *
545      * The strings are copied once the option is created.
546      */
547     template<size_t count>
548     EnumOption& enumValue(const char* const (&values)[count])
549     {
550         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
551         enumValues_      = values;
552         enumValuesCount_ = count;
553         return MyBase::me();
554     }
555     /*! \brief
556      * Sets the option to only accept one of a fixed set of strings.
557      *
558      * \param[in] values  Array of strings to accept, with a NULL pointer
559      *      following the last string.
560      *
561      * Works otherwise as the array version, but accepts a pointer to
562      * an array of undetermined length.  The end of the array is indicated
563      * by a NULL pointer in the array.
564      *
565      * \see enumValue()
566      */
567     EnumOption& enumValueFromNullTerminatedArray(const char* const* values)
568     {
569         GMX_ASSERT(enumValues_ == nullptr, "Multiple sets of enumerated values specified");
570         enumValues_      = values;
571         enumValuesCount_ = -1;
572         return MyBase::me();
573     }
574
575 private:
576     //! Helper function to convert default values for storate initialization.
577     static int convertToInt(const EnumType* defaultValue)
578     {
579         return defaultValue != nullptr ? static_cast<int>(*defaultValue) : -1;
580     }
581
582     //! Creates a EnumOptionStorage object.
583     AbstractOptionStorage* createStorage(const OptionManagerContainer& /*managers*/) const override
584     {
585         // TODO: Implement storeCount() if necessary.
586         return internal::createEnumOptionStorage(*this, enumValues_, enumValuesCount_,
587                                                  convertToInt(MyBase::defaultValue()),
588                                                  convertToInt(MyBase::defaultValueIfSet()),
589                                                  std::make_unique<internal::EnumIndexStore<EnumType>>(
590                                                          MyBase::store(), MyBase::storeVector()));
591     }
592
593     const char* const* enumValues_;
594     int                enumValuesCount_;
595
596     /*! \brief
597      * Needed to initialize EnumOptionStorage from this class without
598      * otherwise unnecessary accessors.
599      */
600     friend class EnumOptionStorage;
601 };
602
603 //! Shorthand for an enumerated option that stores into an `int` variable.
604 typedef EnumOption<int> EnumIntOption;
605
606 /*! \brief
607  * Wrapper class for accessing boolean option information.
608  *
609  * \inpublicapi
610  */
611 class BooleanOptionInfo : public OptionInfo
612 {
613 public:
614     //! Creates an option info object for the given option.
615     explicit BooleanOptionInfo(BooleanOptionStorage* option);
616
617     //! Returns the default value for this option.
618     bool defaultValue() const;
619
620 private:
621     const BooleanOptionStorage& option() const;
622 };
623
624 /*! \brief
625  * Wrapper class for accessing integer option information.
626  *
627  * \inpublicapi
628  */
629 class IntegerOptionInfo : public OptionInfo
630 {
631 public:
632     //! Creates an option info object for the given option.
633     explicit IntegerOptionInfo(IntegerOptionStorage* option);
634 };
635
636 /*! \brief
637  * Wrapper class for accessing 64-bit integer option information.
638  *
639  * \inpublicapi
640  */
641 class Int64OptionInfo : public OptionInfo
642 {
643 public:
644     //! Creates an option info object for the given option.
645     explicit Int64OptionInfo(Int64OptionStorage* option);
646 };
647
648 /*! \brief
649  * Wrapper class for accessing floating-point option information.
650  *
651  * \inpublicapi
652  */
653 class DoubleOptionInfo : public OptionInfo
654 {
655 public:
656     //! Creates an option info object for the given option.
657     explicit DoubleOptionInfo(DoubleOptionStorage* option);
658
659     //! Whether the option specifies a time value.
660     bool isTime() const;
661
662     /*! \brief
663      * Sets a scale factor for user-provided values.
664      *
665      * Any user-provided value is scaled by the provided factor.
666      * Programmatically set default values are not scaled.
667      * If called multiple times, later calls override the previously set
668      * value.  In other words, the scaling is not cumulative.
669      */
670     void setScaleFactor(double factor);
671
672 private:
673     DoubleOptionStorage&       option();
674     const DoubleOptionStorage& option() const;
675 };
676
677 /*! \brief
678  * Wrapper class for accessing floating-point option information.
679  *
680  * \inpublicapi
681  */
682 class FloatOptionInfo : public OptionInfo
683 {
684 public:
685     //! Creates an option info object for the given option.
686     explicit FloatOptionInfo(FloatOptionStorage* option);
687
688     //! Whether the option specifies a time value.
689     bool isTime() const;
690
691     //! \copydoc DoubleOptionInfo::setScaleFactor()
692     void setScaleFactor(double factor);
693
694 private:
695     FloatOptionStorage&       option();
696     const FloatOptionStorage& option() const;
697 };
698
699 /*! \brief
700  * Wrapper class for accessing string option information.
701  *
702  * \inpublicapi
703  */
704 class StringOptionInfo : public OptionInfo
705 {
706 public:
707     //! Creates an option info object for the given option.
708     explicit StringOptionInfo(StringOptionStorage* option);
709
710     /*! \brief
711      * Whether this option accepts an enumerated set of values.
712      *
713      * Returns true if StringOption::enumValues() was used when creating
714      * this option.
715      */
716     bool isEnumerated() const;
717     /*! \brief
718      * Returns the set of allowed values for this option.
719      *
720      * Returns an empty vector if isEnumerated() returns false.
721      */
722     const std::vector<std::string>& allowedValues() const;
723
724 private:
725     const StringOptionStorage& option() const;
726 };
727
728 /*! \brief
729  * Wrapper class for accessing enum option information.
730  *
731  * \inpublicapi
732  */
733 class EnumOptionInfo : public OptionInfo
734 {
735 public:
736     //! Creates an option info object for the given option.
737     explicit EnumOptionInfo(EnumOptionStorage* option);
738
739     /*! \brief
740      * Returns the set of allowed values for this option.
741      */
742     const std::vector<std::string>& allowedValues() const;
743
744 private:
745     const EnumOptionStorage& option() const;
746 };
747
748 /*! \typedef RealOption
749  * \brief
750  * Typedef for either DoubleOption or FloatOption, depending on precision.
751  *
752  * Generally, new would be better using DoubleOption, but this is provided for
753  * cases where the output value needs to be of type `real` for some reason.
754  */
755 /*! \typedef RealOptionInfo
756  * \brief
757  * Typedef for either DoubleOptionInfo or FloatOptionInfo, depending on precision.
758  *
759  * Generally, new would be better using DoubleOption, but this is provided for
760  * cases where the output value needs to be of type `real` for some reason.
761  */
762 #if GMX_DOUBLE
763 typedef DoubleOption     RealOption;
764 typedef DoubleOptionInfo RealOptionInfo;
765 #else
766 typedef FloatOption     RealOption;
767 typedef FloatOptionInfo RealOptionInfo;
768 #endif
769
770 //! \}
771
772 } // namespace gmx
773
774 #endif