rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
main.cpp
1 #include "main.hpp"
2 
3 #include <iostream>
4 #include <limits>
5 #include <string>
6 
7 #include "RSVSclass.hpp"
8 #include "RSVSintegration.hpp"
9 #include "cxxopts.hpp"
10 #include "makeontargetchange.h"
11 #include "parameters.hpp"
12 
13 #ifdef RSVSTEST
14 #include "test.hpp"
15 #endif // RSVSTEST
16 #ifndef RSVS_NOTESTS
17 #include "test.hpp"
18 #endif
19 
20 using namespace std;
21 
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic ignored "-Wunused-parameter"
24 
25 #ifndef LIB_RSVS
26 int main(int argc, char *argv[])
27 #else
28 int main_rsvs3d(int argc, char *argv[])
29 #endif
30 {
31 // Execution paths for different compilation flags allows building test
32 // executables
33 #ifndef RSVSTEST
34  return RSVSExecution(argc, argv);
35 #elif defined(TEST_ALL)
36  return rsvstest::maintest();
37 #elif defined(TEST_SHORT)
38  return rsvstest::shorttest();
39 #else
40  return rsvstest::newtest();
41 #endif // RSVSTEST
42 }
43 #pragma GCC diagnostic pop
44 
45 int RSVSExecution(int argc, char *argv[])
46 {
47  param::parameters paramconf;
48 
49  auto parseOut = parse::CommandLineParser(argc, argv, paramconf);
50  if (parseOut.execFlow > 0)
51  {
52  integrate::RSVSclass RSVSobj(parseOut.isHeadless);
53  RSVSobj.paramconf = paramconf;
54  if (parseOut.execFlow == 1)
55  {
56  integrate::execute::All(RSVSobj);
57  }
58  else if (parseOut.execFlow == 2)
59  {
60  integrate::execute::Interactive(RSVSobj);
61  }
62  else
63  {
64  RSVS3D_ERROR_ARGUMENT("Invalid execution flow");
65  }
66  }
67  else if (parseOut.execFlow == -3)
68  {
69 #ifndef RSVS_NOTESTS
70  polyscopersvs::test::TEST_HEADLESS = parseOut.isHeadless;
71  ExecuteTests(parseOut);
72 #else
73  RSVS3D_ERROR("Tests not compiled; use `make all` to produce an executable"
74  "with tests;\n or `make notest` for an executable without");
75 #endif
76  }
77  else
78  {
79  // Output parameter file to the directory (NO OVERWRITE?)
80  NoExecution(parseOut, paramconf);
81  }
82  return (0);
83 }
84 
85 void ExecuteTests(const parse::ParserOutput &parseOut)
86 {
87  int testNum = 0;
88 
89 #ifndef RSVS_HIDETESTS
90  if (parseOut.testCase.compare("all") == 0)
91  {
92  testNum = rsvstest::maintest();
93  }
94  else if (parseOut.testCase.compare("short") == 0)
95  {
96  testNum = rsvstest::shorttest();
97  }
98  else if (parseOut.testCase.compare("new") == 0)
99  {
100  testNum = rsvstest::newtest();
101  }
102  else
103  {
104  std::stringstream errStr;
105  errStr << "The test case '" << parseOut.testCase << "'is not known, valid options are:" << std::endl
106  << "'all', 'short', or 'new'.";
107  RSVS3D_ERROR_ARGUMENT(errStr.str().c_str());
108  }
109 #endif // RSVS_HIDETESTS
110 
111  exit(testNum);
112 }
113 
114 void NoExecution(parse::ParserOutput &parseOut, param::parameters &paramconf)
115 {
116  if (parseOut.execFlow == -2)
117  {
118  parseOut.paramFileOut = "failexec_rsvsconfig.json";
119  }
120 
121  param::io::writeflat(parseOut.paramFileOut + "flat", paramconf);
122  param::io::write(parseOut.paramFileOut, paramconf);
123 
124  if (parseOut.execFlow == -2)
125  {
126  std::cerr << "Error while parsing the arguments. Check generated '" << parseOut.paramFileOut << "' file";
127  exit(-2);
128  }
129 }
130 
144 {
145  parse::ParserOutput parseOut;
146  parseOut.execFlow = 0;
147  std::vector<std::string> triggerExec, configParam, configFiles, configPredef, noexecStr, testString;
148  // options that will trigger execution of RSVS
149  triggerExec = {"use-config", "load-config", "param"};
150 
151  std::string strDescription;
152  strDescription = "\nProgram for the execution of the Restricted-Surface";
153  strDescription += " Volume of Solid in 3D";
154  cxxopts::Options options(argv[0], strDescription);
155  options.positional_help("[optional args]").show_positional_help();
156  // clang-format off
157  options.add_options("")("h,help", "Print help");
158 
159  options.add_options("Parameter configuration")
160  ("u,use-config", "Use one of the predefined configurations stored in the code.", cxxopts::value(configPredef),"STRING")
161  ("l,load-config",std::string("Load configuration file in JSON format to set parameter "
162  "structure. Multiple files can be specified and will be processed"
163  " in order of appearance."),cxxopts::value(configFiles), "FILES")
164  ("p,param", "Define a parameter manually on the command line."
165  " The format must be a flat key into the JSON configuration:"
166  " (e.g.: '/snak/maxsteps:50' will set 'param.snak.maxsteps=50')",
167  cxxopts::value(configParam),
168  "KEY:VAL")
169  ("default-config", "Output the default configuration to a file.",
170  cxxopts::value<std::string>()->implicit_value("default_config"), "FILE");
171 
172  options.add_options("Execution control")
173  ("n,noexec", std::string("Do not execute RSVS process, will only parse the inputs and output "
174  "the resulting configuration file to 'arg'"),
175  cxxopts::value(noexecStr)->implicit_value("./noexec_config.json"), "STRING")
176  ("e,exec", "Execute RSVS. With no command line argument the program does nothing.")
177  ("i,interactive", "Execute the RSVS in interactive mode using polyscope")
178  ("no-gui", "Disable all GUI calls and OpenGL functionality.")
179 #ifndef RSVS_HIDETESTS
180  ("test", std::string("Executes specified tests. requires compilation without flag RSVS_NOTESTS."),
181  cxxopts::value(testString)->implicit_value("short"), "STRING")
182 #endif
183  ;
184  // clang-format on
185  auto result = options.parse(argc, argv);
186  // ""
187  if (result.count("help"))
188  {
189  std::cout << options.help({"", "Execution control", "Parameter configuration"}) << std::endl;
190  exit(0);
191  }
192  // "Execution control"
193  if (result.count("noexec") > 0 && result.count("exec") > 0)
194  {
195  std::cerr << std::endl << " Invalid specification of -e (exec) and -n (noexec)";
196  std::cerr << " on the command line." << std::endl;
197  std::cerr << " see --help for more info" << std::endl;
198  exit(-1);
199  }
200  else if ((result.count("exec") || result.count("interactive")) && result.count("test"))
201  {
202  std::cerr << std::endl << " Invalid specification of -e/i (exec/interactive) and -t (test)";
203  std::cerr << " on the command line." << std::endl;
204  std::cerr << " see --help for more info" << std::endl;
205  exit(-1);
206  }
207  else if (result.count("noexec") && result.count("test"))
208  {
209  std::cerr << std::endl << " Invalid specification of -n (noexec) and -t (test)";
210  std::cerr << " on the command line." << std::endl;
211  std::cerr << " see --help for more info" << std::endl;
212  exit(-1);
213  }
214  else if (result.count("interactive"))
215  {
216  parseOut.execFlow = 2;
217  }
218  else if (result.count("exec"))
219  {
220  parseOut.execFlow = 1;
221  }
222  else if (result.count("test"))
223  {
224  parseOut.execFlow = -3;
225  for (auto testCase : testString)
226  {
227  parseOut.testCase = testCase;
228  std::cout << parseOut.testCase << " " << testCase << std::endl;
229  }
230  }
231  else if (result.count("noexec"))
232  {
233  parseOut.execFlow = -1;
234  for (auto confCase : noexecStr)
235  {
236  parseOut.paramFileOut = confCase;
237  break;
238  }
239  std::cout << parseOut.paramFileOut << std::endl;
240  }
241  if (result.count("no-gui"))
242  {
243  parseOut.isHeadless = true;
244  }
245  // Parameter configuration
246  // if one of the triggers is found specify that execution
247  // should take place
248  if (parseOut.execFlow == 0)
249  {
250  for (auto i : triggerExec)
251  {
252  if (result.count(i))
253  {
254  parseOut.execFlow = 1;
255  break;
256  }
257  }
258  }
259  // Parse a predefined config:
260  if (result.count("use-config"))
261  {
262  for (auto confCase : configPredef)
263  {
264  parse::config::useconfig(confCase, paramconf);
265  }
266  }
267  if (result.count("load-config"))
268  {
269  for (auto confCase : configFiles)
270  {
271  parse::config::loadconfig(confCase, paramconf);
272  }
273  }
274  if (result.count("param"))
275  {
276  if (param::io::updatefromstring(configParam, paramconf) > 0)
277  {
278  parseOut.execFlow = -2;
279  }
280  }
281 
282  return (parseOut);
283 }
284 
285 #pragma GCC diagnostic push
286 #pragma GCC diagnostic ignored "-Wunused-parameter"
287 void parse::config::useconfig(const std::string &confCase, param::parameters &paramconf)
288 {
289  std::cerr << "No predefined cases yet." << std::endl;
290 }
291 #pragma GCC diagnostic pop
292 void parse::config::loadconfig(const std::string &confCase, param::parameters &paramconf)
293 {
294  param::io::read(confCase, paramconf);
295 }
296 
297 parse::ParserOutput parse::StringParser(std::vector<std::string> &commands, param::parameters &paramconf)
298 {
299  int argc = commands.size();
300  char **argv;
301  argv = new char *[argc];
302  for (int i = 0; i < argc; ++i)
303  {
304  argv[i] = new char[commands[i].length() + 1];
305  strcpy(argv[i], commands[i].c_str());
306  }
307 
308  auto parseOut = parse::CommandLineParser(argc, argv, paramconf);
309 
310  for (int i = 0; i < argc; ++i)
311  {
312  delete[] argv[i];
313  }
314  return (parseOut);
315 }
Simple class containing all the information needed for the 3D-RSVS execution.
Integration into the full 3 dimensional Restricted Snake Volume of Solid method.
Root class for all the parameters.
Definition: parameters.hpp:288
file containing the main functions and the command line parser.
ParserOutput CommandLineParser(int argc, char *argv[], param::parameters &paramconf)
Takes in the command line arguments and returns an integer specifying the execution flow of the rest ...
Definition: main.cpp:143
bool TEST_HEADLESS
Boolean controlling wether tests are run in headless mode or not.
Parameters for the integrated 3DRSVS.
Provides the custom testing system used by the RSVS3D project.
#define RSVS3D_ERROR(M)
Throw generic rsvs errors.
Definition: warning.hpp:113
#define RSVS3D_ERROR_ARGUMENT(M)
Throw a invalid_argument.
Definition: warning.hpp:148