Nektar++
NekMesh.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: NekMesh.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Mesh conversion utility.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
37 #include <boost/algorithm/string.hpp>
38 #include <boost/asio/ip/host_name.hpp>
39 #include <boost/format.hpp>
40 #include <boost/program_options.hpp>
41 #include <string>
42 
43 #include <NekMesh/Module/Module.h>
44 
45 using namespace std;
46 using namespace Nektar::NekMesh;
47 
48 namespace po = boost::program_options;
49 namespace ip = boost::asio::ip;
50 
51 int main(int argc, char *argv[])
52 {
53  po::options_description desc("Available options");
54 
55  // clang-format off
56  desc.add_options()
57  ("help,h", "Produce this help message.")
58  ("forceoutput,f", "Force the output to be written without any checks")
59  ("modules-list,l", "Print the list of available modules.")
60  ("modules-opt,p", po::value<string>(),
61  "Print options for a module.")
62  ("module,m", po::value<vector<string> >(),
63  "Specify modules which are to be used.")
64  ("verbose,v", "Enable verbose output.");
65  // clang-format on
66 
67  po::options_description hidden("Hidden options");
68 
69  // clang-format off
70  hidden.add_options()
71  ("input-file", po::value<vector<string> >(), "Input filename");
72  // clang-format on
73 
74  po::options_description cmdline_options;
75  cmdline_options.add(hidden).add(desc);
76 
77  po::options_description visible("Allowed options");
78  visible.add(desc);
79 
80  po::positional_options_description p;
81  p.add("input-file", -1);
82 
83  po::variables_map vm;
84 
85  try
86  {
87  po::store(po::command_line_parser(argc, argv)
88  .options(cmdline_options)
89  .positional(p)
90  .run(),
91  vm);
92  po::notify(vm);
93  }
94  catch (const std::exception &e)
95  {
96  cerr << e.what() << endl;
97  cerr << desc;
98  return 1;
99  }
100 
101  // If NEKTAR_DISABLE_BACKUPS environment variable is set, enable the
102  // forceoutput option.
103  if (std::getenv("NEKTAR_DISABLE_BACKUPS") != nullptr)
104  {
105  vm.insert(std::make_pair("forceoutput", po::variable_value()));
106  }
107 
108  // Create a logger.
109  auto logOutput = std::make_shared<StreamOutput>(std::cout);
110  Logger log(logOutput, vm.count("verbose") ? VERBOSE : INFO);
111 
112  // Print available modules.
113  if (vm.count("modules-list"))
114  {
116  return 1;
117  }
118 
119  if (vm.count("modules-opt"))
120  {
121  vector<string> tmp1;
122  boost::split(tmp1, vm["modules-opt"].as<string>(),
123  boost::is_any_of(":"));
124 
125  if (tmp1.size() != 2)
126  {
127  cerr << "ERROR: To specify a module, use one of in, out or proc "
128  << "together with the filename; for example in:vtk." << endl;
129  return 1;
130  }
131 
132  if (tmp1[0] != "in" && tmp1[0] != "out" && tmp1[0] != "proc")
133  {
134  cerr << "ERROR: Invalid module type " << tmp1[0] << endl;
135  return 1;
136  }
137 
139 
140  if (tmp1[0] == "in")
141  {
142  t = eInputModule;
143  }
144  else if (tmp1[0] == "out")
145  {
146  t = eOutputModule;
147  }
148  else if (tmp1[0] == "proc")
149  {
150  t = eProcessModule;
151  }
152 
153  MeshSharedPtr m = std::shared_ptr<Mesh>(new Mesh());
154  ModuleSharedPtr mod =
155  GetModuleFactory().CreateInstance(ModuleKey(t, tmp1[1]), m);
156  cerr << "Options for module " << tmp1[1] << ":" << endl;
157  mod->SetLogger(log);
158  mod->PrintConfig();
159  return 1;
160  }
161 
162  if (vm.count("help") || vm.count("input-file") != 1)
163  {
164  cerr << "Usage: NekMesh [options] inputfile.ext1 outputfile.ext2"
165  << endl;
166  cout << desc;
167  return 1;
168  }
169 
170  vector<string> inout = vm["input-file"].as<vector<string>>();
171 
172  if (inout.size() < 2)
173  {
174  cerr << "ERROR: You must specify an input and output file." << endl;
175  return 1;
176  }
177 
178  /*
179  * Process list of modules. Each element of the vector of module strings can
180  * be in the following form:
181  *
182  * modname:arg1=a:arg2=b:arg3=c:arg4:arg5=asd
183  *
184  * where the only required argument is 'modname', specifing the name of the
185  * module to load.
186  */
187 
188  MeshSharedPtr mesh = std::shared_ptr<Mesh>(new Mesh());
189 
190  // Add provenance information to mesh.
191  stringstream ss;
192  for (int i = 1; i < argc; i++)
193  {
194  ss << argv[i] << " ";
195  }
196  mesh->m_metadata["NekMeshCommandLine"] = ss.str();
197 
198  vector<ModuleSharedPtr> modules;
199  vector<string> modcmds;
200 
201  if (vm.count("module"))
202  {
203  modcmds = vm["module"].as<vector<string>>();
204  }
205 
206  bool forceOutput = vm.count("forceoutput");
207 
208  // Add input and output modules to beginning and end of this vector.
209  modcmds.insert(modcmds.begin(), inout[0]);
210  modcmds.push_back(inout[1]);
211 
212  // Keep track of maximum string length for nicer verbose output.
213  size_t maxModName = 0;
214 
215  for (int i = 0; i < modcmds.size(); ++i)
216  {
217  // First split each command by the colon separator.
218  vector<string> tmp1;
219  ModuleKey module;
220  int offset = 1;
221 
222  boost::split(tmp1, modcmds[i], boost::is_any_of(":"));
223 
224  if (i == 0 || i == modcmds.size() - 1)
225  {
226  module.first = (i == 0 ? eInputModule : eOutputModule);
227 
228  // If no colon detected, automatically detect mesh type from
229  // file extension. Otherwise override and use tmp1[1] as the
230  // module to load. This also allows us to pass options to
231  // input/output modules. So, for example, to override
232  // filename.xml to be read as vtk, you use:
233  //
234  // filename.xml:vtk:opt1=arg1:opt2=arg2
235  if (tmp1.size() == 1)
236  {
237  int dot = tmp1[0].find_last_of('.') + 1;
238  string ext = tmp1[0].substr(dot, tmp1[0].length() - dot);
239 
240  if (ext == "gz")
241  {
242  string tmp = tmp1[0].substr(0, tmp1[0].length() - 3);
243  dot = tmp.find_last_of('.') + 1;
244  ext = tmp.substr(dot, tmp.length() - dot);
245  }
246 
247  module.second = ext;
248  tmp1.push_back(string(i == 0 ? "infile=" : "outfile=") +
249  tmp1[0]);
250  }
251  else
252  {
253  module.second = tmp1[1];
254  tmp1.push_back(string(i == 0 ? "infile=" : "outfile=") +
255  tmp1[0]);
256  offset++;
257  }
258  }
259  else
260  {
261  module.first = eProcessModule;
262  module.second = tmp1[0];
263  }
264 
265  // Create module.
266  ModuleSharedPtr mod = GetModuleFactory().CreateInstance(module, mesh);
267  mod->SetLogger(log);
268  modules.push_back(mod);
269 
270  // Set options for this module.
271  for (int j = offset; j < tmp1.size(); ++j)
272  {
273  vector<string> tmp2;
274  boost::split(tmp2, tmp1[j], boost::is_any_of("="));
275 
276  if (tmp2.size() == 1)
277  {
278  mod->RegisterConfig(tmp2[0]);
279  }
280  else if (tmp2.size() == 2)
281  {
282  mod->RegisterConfig(tmp2[0], tmp2[1]);
283  }
284  else
285  {
286  cerr << "ERROR: Invalid module configuration: format is "
287  << "either :arg or :arg=val" << endl;
288  return 1;
289  }
290  }
291 
292  if (i == modcmds.size() - 1 && forceOutput)
293  {
294  mod->RegisterConfig("forceoutput", "true");
295  }
296 
297  // Ensure configuration options have been set.
298  mod->SetDefaults();
299 
300  // Track maximum module name length.
301  std::string modName = mod->GetModuleName();
302  maxModName = std::max(maxModName, modName.length());
303  }
304 
305  log.SetPrefixLen(maxModName);
306 
307  // Run mesh process.
308  for (int i = 0; i < modules.size(); ++i)
309  {
311  t.Start();
312  try
313  {
314  modules[i]->GetLogger().SetPrefixLen(maxModName);
315  modules[i]->Process();
316  }
317  catch (NekMeshError &e)
318  {
319  return 1;
320  }
321  t.Stop();
322 
323  log.SetPrefix(modules[i]->GetModuleName());
324  log(VERBOSE) << " - Elapsed time: " << t.TimePerTest(1) << "s."
325  << std::endl;
326  }
327 
328  return 0;
329 }
int main(int argc, char *argv[])
Definition: NekMesh.cpp:51
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:232
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:68
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
std::shared_ptr< Module > ModuleSharedPtr
Definition: Module.h:321
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303