1 /* ----------------------------------------------------------------------
2     This is the
3 
4     ██╗     ██╗ ██████╗  ██████╗  ██████╗ ██╗  ██╗████████╗███████╗
5     ██║     ██║██╔════╝ ██╔════╝ ██╔════╝ ██║  ██║╚══██╔══╝██╔════╝
6     ██║     ██║██║  ███╗██║  ███╗██║  ███╗███████║   ██║   ███████╗
7     ██║     ██║██║   ██║██║   ██║██║   ██║██╔══██║   ██║   ╚════██║
8     ███████╗██║╚██████╔╝╚██████╔╝╚██████╔╝██║  ██║   ██║   ███████║
9     ╚══════╝╚═╝ ╚═════╝  ╚═════╝  ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝®
10 
11     DEM simulation engine, released by
12     DCS Computing Gmbh, Linz, Austria
13     http://www.dcs-computing.com, office@dcs-computing.com
14 
15     LIGGGHTS® is part of CFDEM®project:
16     http://www.liggghts.com | http://www.cfdem.com
17 
18     Core developer and main author:
19     Christoph Kloss, christoph.kloss@dcs-computing.com
20 
21     LIGGGHTS® is open-source, distributed under the terms of the GNU Public
22     License, version 2 or later. It is distributed in the hope that it will
23     be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
24     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have
25     received a copy of the GNU General Public License along with LIGGGHTS®.
26     If not, see http://www.gnu.org/licenses . See also top-level README
27     and LICENSE files.
28 
29     LIGGGHTS® and CFDEM® are registered trade marks of DCS Computing GmbH,
30     the producer of the LIGGGHTS® software and the CFDEM®coupling software
31     See http://www.cfdem.com/terms-trademark-policy for details.
32 
33 -------------------------------------------------------------------------
34     Contributing author and copyright for this file:
35 
36     Richard Berger (JKU Linz)
37 
38     Copyright 2012-2014 JKU Linz
39 ------------------------------------------------------------------------- */
40 
41 #ifndef SETTINGS_H_
42 #define SETTINGS_H_
43 
44 #include "pointers.h"
45 #include <string>
46 #include <set>
47 #include <map>
48 #include <sstream>
49 #include <stdlib.h>
50 
51 using namespace LAMMPS_NS;
52 
53 template<typename T>
54 class ValuePropagator {
55 public:
registerTarget(T & target)56   void registerTarget(T & target)
57   {
58     targets.insert(&target);
59     target = currentValue;
60   }
61 
setValue(T value)62   void setValue(T value)
63   {
64     currentValue = value;
65 
66     for(typename std::set<T*>::iterator it = targets.begin(); it != targets.end(); ++it) {
67       *(*it) = value;
68     }
69   }
70 
getValue()71   T getValue() const {
72     return currentValue;
73   }
74 
75 private:
76   T currentValue;
77   std::set<T*> targets;
78 };
79 
80 class Setting {
81 public:
Setting(std::string name,int num_params)82   Setting(std::string name, int num_params) : name(name), num_params(num_params)
83   {
84   }
~Setting()85   virtual ~Setting(){}
86 
87   // subclasses implement this method and return the amount of arguments have
88   // been consumed.
89   virtual int parseArguments(char ** args) = 0;
90 
91   virtual void print_value(FILE * out) = 0;
92 
93   std::string name;
94   int num_params;
95   std::string error_message;
96 };
97 
98 template<typename T>
99 class EnumSetting : public Setting
100 {
101 public:
102   typedef T value_type;
103 
EnumSetting(std::string name)104   EnumSetting(std::string name) : Setting(name, 1)
105   {
106   }
107 
~EnumSetting()108   virtual ~EnumSetting(){}
109 
addOption(std::string option,T value)110   void addOption(std::string option, T value)
111   {
112     options[option] = value;
113   }
114 
setDefault(std::string option)115   void setDefault(std::string option){
116     current.setValue(options[option]);
117   }
118 
registerTarget(T & target)119   void registerTarget(T & target) {
120     current.registerTarget(target);
121   }
122 
parseArguments(char ** args)123   int parseArguments(char ** args) {
124     if(name != args[0]) return 0; // argument not consumed
125     std::string selected(args[1]);
126     if(options.find(selected) != options.end()){
127       current.setValue(options[selected]);
128       return 2; // argument consumed
129     } else {
130       std::stringstream ss;
131       ss << "while parsing '" << name << "' argument: ";
132       ss << "unknown option or wrong keyword order: '" << args[1] << "'";
133       error_message = ss.str();
134     }
135     return -1; // error while parsing argument
136   }
137 
print_value(FILE * out)138   virtual void print_value(FILE* out) {
139     T value = current.getValue();
140     for(typename std::map<std::string, T>::iterator it = options.begin(); it != options.end(); ++it) {
141       if(it->second == value) {
142         fprintf(out, "%s", it->first.c_str());
143         return;
144       }
145     }
146     fprintf(out, "BAD_VALUE");
147   }
148 
149 private:
150   ValuePropagator<T> current;
151   std::map<std::string, T> options;
152 };
153 
154 class DoubleSetting : public Setting
155 {
156 public:
157   typedef double value_type;
158 
DoubleSetting(std::string name,double default_value)159   DoubleSetting(std::string name, double default_value) : Setting(name, 1)
160   {
161     setDefault(default_value);
162   }
163 
~DoubleSetting()164   virtual ~DoubleSetting(){}
165 
setDefault(double d)166   void setDefault(double d){
167     current.setValue(d);
168   }
169 
registerTarget(double & target)170   void registerTarget(double & target) {
171     current.registerTarget(target);
172   }
173 
parseArguments(char ** args)174   int parseArguments(char ** args) {
175     if(name != args[0]) return 0;
176     current.setValue(atof(args[1]));
177     return 2;
178   }
179 
print_value(FILE * out)180   void print_value(FILE* out) {
181     fprintf(out, "%g", current.getValue());
182   }
183 
184 private:
185   ValuePropagator<double> current;
186 };
187 
188 class OnOffSetting : public EnumSetting<bool> {
189 public:
OnOffSetting(std::string name,bool default_value)190   OnOffSetting(std::string name, bool default_value) : EnumSetting<bool>(name)
191   {
192     addOption("off", false);
193     addOption("on", true);
194     if(default_value) setDefault("on");
195     else setDefault("off");
196   }
197 
~OnOffSetting()198   virtual ~OnOffSetting(){}
199 };
200 
201 class YesNoSetting : public EnumSetting<bool> {
202 public:
YesNoSetting(std::string name,bool default_value)203   YesNoSetting(std::string name, bool default_value) : EnumSetting<bool>(name)
204   {
205     addOption("no", false);
206     addOption("yes", true);
207     if(default_value) setDefault("yes");
208     else setDefault("no");
209   }
~YesNoSetting()210 	virtual ~YesNoSetting(){}
211 };
212 
213 class Settings : protected Pointers
214 {
215   typedef std::map<std::string, Setting*> SettingMap;
216   SettingMap settings;
217 
218   template<typename SettingType>
registerSetting(std::string name,typename SettingType::value_type & variable,typename SettingType::value_type default_value)219   void registerSetting(std::string name, typename SettingType::value_type & variable, typename SettingType::value_type default_value) {
220     if(settings.find(name) == settings.end()) {
221       settings[name] = new SettingType(name, default_value);
222     }
223     SettingType * setting = dynamic_cast<SettingType*>(settings[name]);
224     if(setting) setting->registerTarget(variable);
225   }
226 
227 public:
228   std::string error_message;
229 
Settings(LAMMPS * lmp)230   Settings(LAMMPS * lmp) : Pointers(lmp) {}
~Settings()231   ~Settings() {
232     for(SettingMap::iterator it = settings.begin(); it != settings.end(); ++it) {
233       delete it->second;
234     }
235   }
236 
237   void registerOnOff(std::string name, bool & variable, bool default_value = false)
238   {
239     registerSetting<OnOffSetting>(name, variable, default_value);
240   }
241 
242   void registerYesNo(std::string name, bool & variable, bool default_value = false) {
243     registerSetting<YesNoSetting>(name, variable, default_value);
244   }
245 
246   void registerDoubleSetting(std::string name, double & variable, double default_value = 0.0)
247   {
248     registerSetting<DoubleSetting>(name, variable, default_value);
249   }
250 
parseArguments(int nargs,char ** args)251   bool parseArguments(int nargs, char ** args) {
252     bool found = false;
253     int remaining = nargs;
254     char ** remaining_args = args;
255     int consumed = 0;
256 
257     while(remaining > 0) {
258       found = false;
259 
260       for(SettingMap::iterator it = settings.begin(); it != settings.end(); ++it) {
261         consumed = it->second->parseArguments(remaining_args);
262         if(consumed > 0) {
263           found = true;
264           break;
265         } else if(consumed < 0) {
266           error_message = it->second->error_message;
267           return false;
268         }
269       }
270 
271       if(found) {
272         remaining -= consumed;
273         remaining_args = &remaining_args[consumed];
274       } else {
275         std::stringstream ss;
276         ss << "Unknown argument or wrong keyword order: '" << remaining_args[0] << "'";
277         error_message = ss.str();
278         return false;
279       }
280     }
281     return true;
282   }
283 
print_all(FILE * out)284   void print_all(FILE * out)
285   {
286     for(SettingMap::iterator it = settings.begin(); it != settings.end(); ++it) {
287       fprintf(out, " %s = ", it->first.c_str());
288       it->second->print_value(out);
289       fprintf(out, "\n");
290     }
291   }
292 };
293 
294 #endif /* SETTINGS_H_ */
295