Nektar++
FieldConvert.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: FieldConvert.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: Field conversion utility.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <string>
36 #include <boost/algorithm/string.hpp>
37 #include <boost/program_options.hpp>
40 #include <FieldUtils/Module.h>
41 
42 using namespace std;
43 using namespace Nektar;
44 using namespace Nektar::FieldUtils;
45 
46 void CheckModules(vector<ModuleSharedPtr> &modules);
47 
48 void PrintExecutionSequence(vector<ModuleSharedPtr> &modules);
49 
50 void RunModule(ModuleSharedPtr module, po::variables_map &vm, bool verbose);
51 
52 int main(int argc, char* argv[])
53 {
54  LibUtilities::Timer timer;
55  timer.Start();
56 
57  po::options_description desc("Available options");
58  desc.add_options()
59  ("help,h",
60  "Produce this help message.")
61  ("modules-list,l",
62  "Print the list of available modules.")
63  ("output-points,n", po::value<int>(),
64  "Output at n equipspaced points along the "
65  "collapsed coordinates (for .dat, .vtu).")
66  ("output-points-hom-z", po::value<int>(),
67  "Number of planes in the z-direction for output of "
68  "Homogeneous 1D expansion(for .dat, .vtu).")
69  ("error,e",
70  "Write error of fields for regression checking")
71  ("forceoutput,f",
72  "Force the output to be written without any checks")
73  ("range,r", po::value<string>(),
74  "Define output range i.e. (-r xmin,xmax,ymin,ymax,zmin,zmax) "
75  "in which any vertex is contained.")
76  ("noequispaced",
77  "Do not use equispaced output.")
78  ("nparts", po::value<int>(),
79  "Define nparts if running serial problem to mimic "
80  "parallel run with many partitions.")
81  ("npz", po::value<int>(),
82  "Used to define number of partitions in z for Homogeneous1D "
83  "expansions for parallel runs.")
84  ("onlyshape", po::value<string>(),
85  "Only use element with defined shape type i.e. -onlyshape "
86  " Tetrahedron")
87  ("part-only", po::value<int>(),
88  "Partition into specified npart partitions and exit")
89  ("part-only-overlapping", po::value<int>(),
90  "Partition into specified npart overlapping partitions and exit")
91  ("modules-opt,p", po::value<string>(),
92  "Print options for a module.")
93  ("module,m", po::value<vector<string> >(),
94  "Specify modules which are to be used.")
95  ("useSessionVariables",
96  "Use variables defined in session for output")
97  ("useSessionExpansion",
98  "Use expansion defined in session.")
99  ("verbose,v",
100  "Enable verbose mode.");
101 
102  po::options_description hidden("Hidden options");
103  hidden.add_options()
104  ("input-file", po::value<vector<string> >(), "Input filename");
105 
106  po::options_description cmdline_options;
107  cmdline_options.add(hidden).add(desc);
108 
109  po::options_description visible("Allowed options");
110  visible.add(desc);
111 
112  po::positional_options_description p;
113  p.add("input-file", -1);
114 
115  po::variables_map vm;
116 
117  try
118  {
119  po::store(po::command_line_parser(argc, argv).
120  options(cmdline_options).positional(p).run(), vm);
121  po::notify(vm);
122  }
123  catch (const std::exception& e)
124  {
125  cerr << e.what() << endl;
126  cerr << desc;
127  return 1;
128  }
129 
130 #ifdef NEKTAR_DISABLE_BACKUPS
131  vm.insert(std::make_pair("forceoutput", po::variable_value()));
132 #endif
133 
134  // Print available modules.
135  if (vm.count("modules-list"))
136  {
138  return 1;
139  }
140 
141  if (vm.count("modules-opt"))
142  {
143  vector<string> tmp1;
144  boost::split(tmp1, vm["modules-opt"].as<string>(),
145  boost::is_any_of(":"));
146 
147  if (tmp1.size() != 2)
148  {
149  cerr << "ERROR: To specify a module, use one of in, out or proc "
150  << "together with the filename; for example in:vtk." << endl;
151  return 1;
152  }
153 
154  if (tmp1[0] != "in" && tmp1[0] != "out" && tmp1[0] != "proc")
155  {
156  cerr << "ERROR: Invalid module type " << tmp1[0] << endl;
157  return 1;
158  }
159 
160  ModuleType t;
161 
162  if (tmp1[0] == "in")
163  {
164  t = eInputModule;
165  }
166  else if (tmp1[0] == "out")
167  {
168  t = eOutputModule;
169  }
170  else if (tmp1[0] == "proc")
171  {
172  t = eProcessModule;
173  }
174 
175  FieldSharedPtr f = std::shared_ptr<Field>(new Field());
177  ModuleKey(t, tmp1[1]), f);
178  cerr << "Options for module " << tmp1[1] << ":" << endl;
179  mod->PrintConfig();
180  return 1;
181  }
182 
183  if (vm.count("help") || vm.count("input-file") != 1)
184  {
185  cerr << "Usage: FieldConvert [options] inputfile.ext1 outputfile.ext2"
186  << endl;
187  cout << desc;
188  cout << endl;
189  cout << "Example Usage: \n" << endl;
190  cout << "\t FieldConvert -m vorticity file.xml file.fld file_vort.fld "
191  << endl;
192  cout << "(This will add vorticity to file file.fld and put it in a "
193  "new file file_vort.fld) " << endl;
194  cout << endl;
195  cout << "\t FieldConvert file.xml file_vort.fld file_vort.dat " << endl;
196  cout << "(process file_vort.fld and make a tecplot output "
197  "file_vort.dat) " << endl;
198 
199  return 1;
200  }
201 
202  ASSERTL0(vm.count("input-file"),
203  "Must specify input(s) and/or output file.");
204  vector<string> inout = vm["input-file"].as<vector<string> >();
205 
206 
207  /*
208  * Process list of modules. Each element of the vector of module
209  * strings can be in the following form:
210  *
211  * modname:arg1=a:arg2=b:arg3=c:arg4:arg5=asd
212  *
213  * where the only required argument is 'modname', specifing the
214  * name of the module to load.
215  */
216  FieldSharedPtr f = std::shared_ptr<Field>(new Field());
217  int nParts = 1;
218  int MPInprocs = 1;
219  int MPIrank = 0;
221 
222  if (LibUtilities::GetCommFactory().ModuleExists("ParallelMPI"))
223  {
224  // get hold of parallel communicator first
226  "ParallelMPI", argc, argv);
227 
228  if(vm.count("nparts"))
229  {
230  //work out number of processors to run in serial over partitions
231  MPInprocs = MPIComm->GetSize();
232  MPIrank = MPIComm->GetRank();
233 
234  nParts = vm["nparts"].as<int>();
235 
237  "Serial", argc, argv);
238  }
239  else
240  {
241  f->m_comm = MPIComm;
242  }
243  }
244  else
245  {
246  if(vm.count("nparts"))
247  {
248  nParts = vm["nparts"].as<int>();
249  }
250 
252  "Serial", argc, argv);
253  }
254 
255  vector<ModuleSharedPtr> modules;
256  vector<string> modcmds;
257  ModuleKey module;
258  ModuleSharedPtr mod;
259 
260  if (vm.count("verbose"))
261  {
262  f->m_verbose = true;
263  }
264 
265  if (vm.count("module"))
266  {
267  modcmds = vm["module"].as<vector<string> >();
268  }
269 
270  // Add input and output modules to beginning and end of this vector.
271  modcmds.insert(modcmds.begin(), inout.begin(), inout.end()-1);
272  modcmds.push_back(*(inout.end()-1));
273 
274  int nInput = inout.size()-1;
275 
276  // For special case of part-only or part-only-overlapping options
277  // only require a single input file and so reset the nInputs to be
278  // of size inout.size(). Since the code will exit before reaching
279  // any output module this seems to work as expected
280  if(vm.count("part-only")||vm.count("part-only-overlapping"))
281  {
282  nInput = inout.size();
283  }
284 
285  InputModuleSharedPtr inputModule;
286  string outfilename;
287 
288  for (int i = 0; i < modcmds.size(); ++i)
289  {
290  // First split each command by the colon separator.
291  vector<string> tmp1;
292  int offset = 1;
293 
294  boost::split(tmp1, modcmds[i], boost::is_any_of(":"));
295 
296  if (i < nInput || i == modcmds.size() - 1)
297  {
298  //assume all modules are input unless last, or specified to be :out
299  module.first = (i < nInput ? eInputModule : eOutputModule);
300  if (tmp1.size() > 1 && tmp1.back()=="out")
301  {
302  module.first = eOutputModule;
303  tmp1.pop_back();
304  }
305 
306  // If no colon detected, automatically detect mesh type from
307  // file extension. Otherwise override and use tmp1[1] as the
308  // module to load. This also allows us to pass options to
309  // input/output modules. So, for example, to override
310  // filename.xml to be read as vtk, you use:
311  //
312  // filename.xml:vtk:opt1=arg1:opt2=arg2
313  if (tmp1.size() == 1)
314  {
315  // First, let's try to guess the input format if we're dealing
316  // with input files.
317  string guess;
318 
319  if (module.first == eInputModule)
320  {
321  guess = InputModule::GuessFormat(tmp1[0]);
322  }
323 
324  // Found file type.
325  if (guess != "")
326  {
327  if (f->m_verbose)
328  {
329  cout << "Using input module " << guess << " for: "
330  << tmp1[0] << endl;
331  }
332 
333  module.second = guess;
334  tmp1.push_back(string("infile="+tmp1[0]));
335  }
336  else
337  {
338  int dot = tmp1[0].find_last_of('.') + 1;
339  string ext = tmp1[0].substr(dot, tmp1[0].length() - dot);
340 
341  // Remove trailing separator from extension to allow
342  // folder inputs using file.fld/
343  if(ext.back() == fs::path::preferred_separator)
344  {
345  ext.pop_back();
346  }
347 
348  if(ext == "gz")
349  {
350  string tmp2 = tmp1[0].substr(0,dot-1);
351  dot = tmp2.find_last_of('.') + 1;
352  ext = tmp1[0].substr(dot,tmp1[0].length()-dot);
353  }
354 
355  module.second = ext;
356  tmp1.push_back(string(module.first == eInputModule ? "infile=" :
357  "outfile=") +tmp1[0]);
358  }
359  }
360  else
361  {
362  module.second = tmp1[1];
363  tmp1.push_back(string(module.first == eInputModule ? "infile=" : "outfile=")
364  + tmp1[0]);
365  offset++;
366  }
367  }
368  else
369  {
370  module.first = eProcessModule;
371  module.second = tmp1[0];
372  }
373 
374  // Create module.
375  mod = GetModuleFactory().CreateInstance(module, f);
376  modules.push_back(mod);
377 
378  if (module.first == eInputModule)
379  {
380  inputModule = std::dynamic_pointer_cast<InputModule>(mod);
381  inputModule->AddFile(module.second, tmp1[0]);
382  }
383  else if(module.first == eOutputModule)
384  {
385  outfilename = tmp1[0];
386  if(nParts > 1)
387  {
388  // if nParts is specified then ensure output modules
389  // write out mutipile files
390  mod->RegisterConfig("writemultiplefiles");
391  }
392  }
393 
394  // Set options for this module.
395  for (int j = offset; j < tmp1.size(); ++j)
396  {
397  vector<string> tmp2;
398  boost::split(tmp2, tmp1[j], boost::is_any_of("="));
399 
400  if (tmp2.size() == 1)
401  {
402  mod->RegisterConfig(tmp2[0]);
403  }
404  else if (tmp2.size() == 2)
405  {
406  mod->RegisterConfig(tmp2[0], tmp2[1]);
407  }
408  else
409  {
410  cerr << "ERROR: Invalid module configuration: format is "
411  << "either :arg or :arg=val" << endl;
412  abort();
413  }
414  }
415 
416  // Ensure configuration options have been set.
417  mod->SetDefaults();
418  }
419 
420  // Include dummy module to create m_exp
421  module.first = eProcessModule;
422  module.second = string("createExp");
423  mod = GetModuleFactory().CreateInstance(module, f);
424  modules.push_back(mod);
425  mod->SetDefaults();
426 
427  // Include equispacedoutput module if needed
428  Array< OneD, int> modulesCount(SIZE_ModulePriority,0);
429  for (int i = 0; i < modules.size(); ++i)
430  {
431  ++modulesCount[modules[i]->GetModulePriority()];
432  }
433  if( modulesCount[eModifyPts] != 0 &&
434  modulesCount[eCreatePts] == 0 &&
435  modulesCount[eConvertExpToPts] == 0)
436  {
437  module.first = eProcessModule;
438  module.second = string("equispacedoutput");
439  mod = GetModuleFactory().CreateInstance(module, f);
440  modules.push_back(mod);
441  mod->SetDefaults();
442  }
443 
444  // Check if modules provided are compatible
445  CheckModules(modules);
446  // Can't have ContField with range option (because of boundaries)
447  if (vm.count("range") && f->m_declareExpansionAsContField)
448  {
449  ASSERTL0(false, "Can't use range option with module requiring "
450  "a continuous expansion.");
451  }
452 
453  bool verbose = (f->m_verbose && f->m_comm->TreatAsRankZero());
454  if(verbose)
455  {
456  PrintExecutionSequence(modules);
457  }
458 
459 
460  // Loop on partitions if required
461  LibUtilities::CommSharedPtr defComm = f->m_comm;
463  for(int p = MPIrank; p < nParts; p += MPInprocs)
464  {
465  // write out which partition is being processed and defined a
466  // new serial communicator
467  if(nParts > 1)
468  {
469  cout << endl << "Processing partition: " << p << endl;
470 
471  int rank = p;
472  f->ClearField();
473  partComm = std::shared_ptr<FieldConvertComm>(
474  new FieldConvertComm(argc, argv, nParts,rank));
475  }
476 
477  // Run field process.
478  for (int n = 0; n < SIZE_ModulePriority; ++n)
479  {
480  ModulePriority priority = static_cast<ModulePriority>(n);
481 
482  if(nParts > 1)
483  {
484  if(((priority == eCreateGraph)||(priority == eOutput)))
485  {
486  f->m_comm = partComm;
487  }
488  else
489  {
490  f->m_comm = defComm;
491  }
492  }
493 
494  for (int i = 0; i < modules.size(); ++i)
495  {
496  if(modules[i]->GetModulePriority() == priority)
497  {
498  RunModule(modules[i], vm, verbose);
499  }
500  }
501  }
502  }
503 
504  // write out Info file if required.
505  if (nParts > 1)
506  {
507  int i;
508  // check to see if we have created a fld file.
509  for (i = 0; i < modules.size(); ++i)
510  {
511  if (boost::iequals(modules[i]->GetModuleName(), "OutputFld"))
512  {
513  break;
514  }
515  }
516 
517  if (i != modules.size())
518  {
519  if (MPInprocs > 1)
520  {
521  MPIComm->Block();
522  }
523 
524  if (MPIrank == 0)
525  {
526  module.first = eOutputModule;
527  module.second = string("info");
528  mod = GetModuleFactory().CreateInstance(module, f);
529 
530  mod->RegisterConfig("nparts",
531  boost::lexical_cast<string>(nParts));
532  mod->SetDefaults();
533 
534  if (f->m_writeBndFld)
535  {
536  // find ending of output file and insert _b1, _b2
537  int dot = outfilename.find_last_of('.') + 1;
538  string ext =
539  outfilename.substr(dot, outfilename.length() - dot);
540  string name = outfilename.substr(0, dot - 1);
541 
542  for (int b = 0; b < f->m_bndRegionsToWrite.size(); ++b)
543  {
544  string outfilenew = name + "_b" +
545  boost::lexical_cast<string>(
546  f->m_bndRegionsToWrite[b]) +
547  "." + ext;
548  mod->RegisterConfig("outfile", outfilenew);
549  RunModule(mod, vm, verbose);
550  }
551  }
552  else
553  {
554  mod->RegisterConfig("outfile", outfilename);
555  RunModule(mod, vm, verbose);
556  }
557  }
558  }
559  }
560 
561  if(verbose)
562  {
563  timer.Stop();
564  NekDouble cpuTime = timer.TimePerTest(1);
565 
566  stringstream ss;
567  ss << cpuTime << "s";
568  cout << "Total CPU Time: " << setw(8) << left
569  << ss.str() << endl;
570  }
571 
572  if(MPInprocs > 1)
573  {
574  MPIComm->Block();
575  MPIComm->Finalise();
576  }
577 
578  return 0;
579 }
580 
581 // This function checks validity conditions for the list of modules provided
582 void CheckModules(vector<ModuleSharedPtr> &modules)
583 {
584  // Count number of modules by priority
585  Array< OneD, int> modulesCount(SIZE_ModulePriority,0);
586  for (int i = 0; i < modules.size(); ++i)
587  {
588  ++modulesCount[modules[i]->GetModulePriority()];
589  }
590 
591  // Modules of type eModifyFieldData require a eCreateFieldData module
592  if( modulesCount[eModifyFieldData] != 0 &&
593  modulesCount[eCreateFieldData] == 0)
594  {
595  stringstream ss;
596  ss << "Module(s): ";
597  for (int i = 0; i < modules.size(); ++i)
598  {
599  if(modules[i]->GetModulePriority() == eModifyFieldData)
600  {
601  ss << modules[i]->GetModuleName()<<" ";
602  }
603  }
604  ss << "require fld input.";
605  ASSERTL0(false, ss.str());
606  }
607 
608  // Modules of type eFillExp require eCreateGraph without eCreateFieldData
609  if( modulesCount[eFillExp] != 0)
610  {
611  if( modulesCount[eCreateGraph] == 0 ||
612  modulesCount[eCreateFieldData] != 0)
613  {
614  stringstream ss;
615  ss << "Module(s): ";
616  for (int i = 0; i < modules.size(); ++i)
617  {
618  if(modules[i]->GetModulePriority() == eFillExp)
619  {
620  ss << modules[i]->GetModuleName()<<" ";
621  }
622  }
623  ss << "require xml input without fld input.";
624  ASSERTL0(false, ss.str());
625  }
626  }
627 
628  // Modules of type eModifyExp and eBndExtraction
629  // require a eCreateGraph module
630  if( (modulesCount[eModifyExp] != 0 || modulesCount[eBndExtraction] != 0) &&
631  modulesCount[eCreateGraph] == 0)
632  {
633  stringstream ss;
634  ss << "Module(s): ";
635  for (int i = 0; i < modules.size(); ++i)
636  {
637  if(modules[i]->GetModulePriority() == eModifyExp ||
638  modules[i]->GetModulePriority() == eBndExtraction)
639  {
640  ss << modules[i]->GetModuleName()<<" ";
641  }
642  }
643  ss << "require xml input.";
644  ASSERTL0(false, ss.str());
645  }
646 
647  // Modules of type eCreatePts should not be used with xml or fld inputs
648  if( modulesCount[eCreatePts] != 0)
649  {
650  if(modulesCount[eCreateGraph]!=0 || modulesCount[eCreateFieldData]!=0)
651  {
652  stringstream ss;
653  ss << "Module(s): ";
654  for (int i = 0; i < modules.size(); ++i)
655  {
656  if(modules[i]->GetModulePriority() == eCreatePts)
657  {
658  ss << modules[i]->GetModuleName()<<" ";
659  }
660  }
661  ss << "should not use xml or fld inputs.";
662  ASSERTL0(false, ss.str());
663  }
664  }
665 
666  // Modules of type eConvertExpToPts require eCreateGraph, but are not
667  // compatible with eBndExtraction
668  if( modulesCount[eConvertExpToPts] != 0)
669  {
670  if( modulesCount[eCreateGraph] == 0)
671  {
672  stringstream ss;
673  ss << "Module(s): ";
674  for (int i = 0; i < modules.size(); ++i)
675  {
676  if(modules[i]->GetModulePriority() == eConvertExpToPts)
677  {
678  ss << modules[i]->GetModuleName()<<" ";
679  }
680  }
681  ss << "require xml input.";
682  ASSERTL0(false, ss.str());
683  }
684  if( modulesCount[eBndExtraction] != 0)
685  {
686  stringstream ss;
687  ss << "Module(s): ";
688  for (int i = 0; i < modules.size(); ++i)
689  {
690  if(modules[i]->GetModulePriority() == eBndExtraction)
691  {
692  ss << modules[i]->GetModuleName()<<" ";
693  }
694  }
695  ss << "is not compatible with module(s): ";
696  for (int i = 0; i < modules.size(); ++i)
697  {
698  if(modules[i]->GetModulePriority() == eConvertExpToPts)
699  {
700  ss << modules[i]->GetModuleName()<<" ";
701  }
702  }
703  ss << ".";
704  ASSERTL0(false, ss.str());
705  }
706  }
707 }
708 
709 void PrintExecutionSequence(vector<ModuleSharedPtr> &modules)
710 {
711  bool first = true;
712  cout << "Execution sequence:" << endl;
713  for (int n = 0; n < SIZE_ModulePriority; ++n)
714  {
715  ModulePriority priority = static_cast<ModulePriority>(n);
716  for (int i = 0; i < modules.size(); ++i)
717  {
718  if(modules[i]->GetModulePriority() == priority)
719  {
720  if(first)
721  {
722  cout << "\t" << modules[i]->GetModuleName();
723  first = false;
724  }
725  else
726  {
727  cout << " -> " << modules[i]->GetModuleName();
728  }
729  }
730  }
731  }
732  cout << endl;
733 }
734 
735 void RunModule(ModuleSharedPtr module, po::variables_map &vm, bool verbose)
736 {
737  LibUtilities::Timer moduleTimer;
738  if(verbose)
739  {
740  moduleTimer.Start();
741 
742  cout << module->GetModuleName() << ": "
743  << module->GetModuleDescription() << endl;
744  }
745  module->Process(vm);
746  cout.flush();
747  if(verbose)
748  {
749  moduleTimer.Stop();
750  NekDouble cpuTime = moduleTimer.TimePerTest(1);
751 
752  stringstream ss;
753  ss << cpuTime << "s";
754  cout << module->GetModuleName()
755  << " CPU Time: " << setw(8) << left
756  << ss.str() << endl;
757  }
758 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
NekDouble TimePerTest(unsigned int n)
Returns amount of seconds per iteration in a test with n iterations.
Definition: Timer.cpp:57
std::shared_ptr< Comm > CommSharedPtr
Pointer to a Communicator object.
Definition: Comm.h:53
FIELD_UTILS_EXPORT void AddFile(std::string fileType, std::string fileName)
STL namespace.
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:762
void PrintAvailableClasses(std::ostream &pOut=std::cout)
Prints the available classes to stdout.
Definition: NekFactory.hpp:235
CommFactory & GetCommFactory()
void RunModule(ModuleSharedPtr module, po::variables_map &vm, bool verbose)
void PrintExecutionSequence(vector< ModuleSharedPtr > &modules)
Abstract base class for input modules.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::pair< ModuleType, std::string > ModuleKey
bool ModuleExists(tKey idKey)
Checks if a particular module is available.
Definition: NekFactory.hpp:215
std::shared_ptr< InputModule > InputModuleSharedPtr
double NekDouble
std::shared_ptr< Module > ModuleSharedPtr
void CheckModules(vector< ModuleSharedPtr > &modules)
int main(int argc, char *argv[])
ModuleFactory & GetModuleFactory()