1 // Project MULTIPR, IOLS WP1.2.1 - EDF/CS
2 // Partitioning/decimation module for the SALOME v3.2 platform
7 * \brief Standalone command line application of the MULTIPR component.
8 * The application aims to reduce large data set to allow interactive visualization.
9 * Its two main function are the following:
10 * 1. Splits any TETRA10 mesh contained in a MED file.
11 * a. Builds a distributed MED file by extracting all the groups from a sequential MED file.
12 * b. Splits a part of distributed MED file.
13 * 2. Decimates fields to produce multi-resolution data set.
15 * Return 0 if application succeed, 1 otherwise (failure).
17 * See http://www.salome-platform.org to learn more about Salome or MED.
19 * \author Olivier LE ROUX - CS, Virtual Reality Dpt
24 #include "MULTIPR_API.hxx"
25 #include "MULTIPR_Obj.hxx"
26 #include "MULTIPR_Mesh.hxx"
27 #include "MULTIPR_Exceptions.hxx"
28 #include "MULTIPR_Utils.hxx"
37 // This command line application can use 2 differents API to do the same work.
38 // If MULTIPR_USE_OBJ_API is defined then this command line application used the MULTIPR_Obj API;
39 // otherwise, it uses the MULTIPR_API
40 //#define MULTIPR_USE_OBJ_API
43 const int MULTIPR_APP_OK = 0;
44 const int MULTIPR_APP_FAILED = 1;
48 * Enumerates all the usages of this application.
52 MULTIPR_USAGE_UNKNOWN,
53 MULTIPR_USAGE_DISPLAY_HELP,
54 MULTIPR_USAGE_AUTOTEST,
55 MULTIPR_USAGE_PARTITION1,
56 MULTIPR_USAGE_PARTITION2,
57 MULTIPR_USAGE_DECIMATION,
63 * Enumerates all the possible errors.
68 MULTIPR_APP_UNKNOWN_USAGE,
69 MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS,
70 MULTIPR_APP_ILLEGAL_ARGUMENT,
71 MULTIPR_APP_FILE_NOT_FOUND,
73 MULTIPR_APP_UNDEFINED_ERROR
77 // global variables used to configure the application
79 int g_errorCode = MULTIPR_APP_NO_ERROR;
80 char* g_medFilename = NULL;
81 char* g_meshName = NULL;
82 char* g_partName = NULL;
84 int g_splitter = multipr::MULTIPR_METIS;
85 char* g_filterName = NULL;
86 char* g_fieldName = NULL;
87 int g_fieldTimeStepIt = 0;
88 float g_decimThresholdMed = 0.0f;
89 float g_decimThresholdLow = 0.0f;
90 float g_decimRadius = 0.0f;
95 * \fn const char* getUsage(int usage)
96 * \brief returns a string describing the usage of this application.
98 const char* getUsage(int usage)
102 case MULTIPR_USAGE_DISPLAY_HELP:
103 return "--help: display help";
105 case MULTIPR_USAGE_AUTOTEST:
106 return "--auto: perform all unit tests";
108 case MULTIPR_USAGE_PARTITION1:
109 return "--part1: extract all groups of a sequential MED file";
111 case MULTIPR_USAGE_PARTITION2:
112 return "--part2: split a part of a distributed MED file";
114 case MULTIPR_USAGE_DECIMATION:
115 return "--decim: generated level of details of a part of a distributed MED file";
117 case MULTIPR_USAGE_INFO:
118 return "--info: prints all infos about a mesh in a sequential MED file";
127 * \fn void printDescription()
128 * \brief prints a short description of this application.
130 void printDescription()
132 cout << "Keywords:" << endl;
133 cout << " Post-processing numerical simulation, Salome platform, " << endl;
134 cout << " Large data set visualization, 3D meshes and fields" << endl;
135 cout << "Description:" << endl;
136 cout << " multipr is a partitionning/decimation tool of MED files." << endl;
137 cout << " See http://www.salome-platform.org for information about MED or Salome." << endl;
138 cout << " Note: current version only accept TETRA10 meshes." << endl;
143 * \fn void printUsage()
144 * \brief prints "how to use" manual of this tools.2NbPart
148 cout << "Usages:" << endl;
149 cout << " --auto Autotest: performs some unit tests on the MULTIPR API" << endl;
150 cout << " * Usage: --auto path (path where to find test file \"agregat100grains_12pas.med\")" << endl;
151 cout << " --part1 Extracts all groups from a sequential MED file (V2.2 or higher)" << endl;
152 cout << " * Usage: --part1 file.med meshName" << endl;
153 cout << " --part2 Split a group of a distributed MED file (V2.3) produced with --part1" << endl;
154 cout << " * Usage: --part2 file.med partName nbParts [splitter (0=METIS 1=SCOTCH)]" << endl;
155 cout << " --decim Generates 3 level of details (full, medium and low) of a part" << endl;
156 cout << " of a distributed MED file (V2.3)" << endl;
157 cout << " * Usage: --decim file.med partName fieldName fieldIt filterName [...]" << endl;
158 cout << " * Only one filter is currently available: Filtre_GradientMoyen" << endl;
159 cout << " * Usage: --decim file.med partName fieldName fieldIt Filtre_GradientMoyen m l radius" << endl;
160 cout << " where m=threshold for medium res. and l=threshold for low res.; assume m < l" << endl;
161 cout << " --info Dumps all infos related to a mesh in a sequential MED file" << endl;
162 cout << " * Usage: --info file.med [meshName]" << endl;
163 cout << " --help Displays this help page" << endl;
169 * \fn void printGlobals()
170 * \brief print current state of all global variables.
175 cout << "********************************************************************************" << endl;
176 cout << "CONFIGURATION" << endl;
177 cout << "--------------------------------------------------------------------------------" << endl;
178 cout << "Mode : " << getUsage(g_usage) << endl;
179 cout << "Med filename : " << ((g_medFilename != NULL) ? g_medFilename : "UNDEFINED") << endl;
180 cout << "Mesh name : " << ((g_meshName != NULL) ? g_meshName : "UNDEFINED") << endl;
181 cout << "Part name : " << ((g_partName != NULL) ? g_partName : "UNDEFINED") << endl;
182 cout << "Nb parts : " << g_nbParts << endl;
183 cout << "Decimation:" << endl;
184 cout << " Field name : " << ((g_fieldName != NULL) ? g_fieldName : "UNDEFINED") << endl;
185 cout << " Time step iteration : " << g_fieldTimeStepIt << endl;
186 cout << " Filter name : " << ((g_filterName != NULL) ? g_filterName : "UNDEFINED") << endl;
187 cout << " Threshold for med. res. : " << g_decimThresholdMed << endl;
188 cout << " Threshold for low res. : " << g_decimThresholdLow << endl;
189 cout << " Radius : " << g_decimRadius << endl;
190 cout << " Boxing : " << g_boxing << endl;
191 cout << "********************************************************************************" << endl;
197 * \fn const char* getErrorMsg()
198 * \brief returns the error message corresponding to current error code.
199 * \return the current error message.
201 const char* getErrorMsg()
205 case MULTIPR_APP_NO_ERROR:
208 case MULTIPR_APP_UNKNOWN_USAGE:
209 return "unknown usage";
211 case MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS:
212 return "wrong number of arguments";
214 case MULTIPR_APP_ILLEGAL_ARGUMENT:
215 return "illegal argument";
217 case MULTIPR_APP_FILE_NOT_FOUND:
218 return "file not found";
220 case MULTIPR_APP_IO_ERROR:
224 return "error (undefined)";
230 * \fn void parseCommandLine(int argc, char** argv)
231 * \brief parses the command line and configure this application.
232 * \param argc number of arguments.
233 * \param argv array of arguments.
235 void parseCommandLine(int argc, char** argv)
239 g_usage = MULTIPR_USAGE_UNKNOWN;
243 if (strcmp(argv[1],"--help") == 0)
245 g_usage = MULTIPR_USAGE_DISPLAY_HELP;
247 else if (strcmp(argv[1],"--auto") == 0)
251 g_usage = MULTIPR_USAGE_UNKNOWN;
252 g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
256 g_usage = MULTIPR_USAGE_AUTOTEST;
257 g_medFilename = argv[2];
260 else if (strcmp(argv[1],"--part1") == 0)
264 g_usage = MULTIPR_USAGE_UNKNOWN;
265 g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
269 g_usage = MULTIPR_USAGE_PARTITION1;
270 g_medFilename = argv[2];
271 g_meshName = argv[3];
274 else if (strcmp(argv[1],"--part2") == 0)
276 if ((argc != 5) && (argc != 6))
278 g_usage = MULTIPR_USAGE_UNKNOWN;
279 g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
283 g_usage = MULTIPR_USAGE_PARTITION2;
284 g_medFilename = argv[2];
285 g_partName = argv[3];
286 g_nbParts = atoi(argv[4]);
290 g_splitter = atoi(argv[5]);
294 else if (strcmp(argv[1],"--decim") == 0)
296 if ((argc != 10) && (argc != 11))
298 g_usage = MULTIPR_USAGE_UNKNOWN;
299 g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
303 g_usage = MULTIPR_USAGE_DECIMATION;
304 g_medFilename = argv[2];
305 g_partName = argv[3];
306 g_fieldName = argv[4];
307 g_fieldTimeStepIt = atoi(argv[5]);
308 g_filterName = argv[6];
309 g_decimThresholdMed = atof(argv[7]);
310 g_decimThresholdLow = atof(argv[8]);
311 g_decimRadius = atof(argv[9]);
315 g_boxing = atoi(argv[10]);
319 else if (strcmp(argv[1],"--info") == 0)
321 if ((argc != 3) && (argc != 4))
323 g_usage = MULTIPR_USAGE_UNKNOWN;
324 g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
328 g_usage = MULTIPR_USAGE_INFO;
329 g_medFilename = argv[2];
333 g_meshName = argv[3];
339 g_usage = MULTIPR_USAGE_UNKNOWN;
340 g_errorCode = MULTIPR_APP_UNKNOWN_USAGE;
346 * \fn int runAutotest()
347 * \brief performs some unit tests on the MULTIPR API.
348 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
352 cout << "Start autotest..." << endl;
354 int ret = MULTIPR_APP_OK;
357 string strMEDfilename = g_medFilename;
358 strMEDfilename += "/agregat100grains_12pas.med";
360 cout << "Test file: " << strMEDfilename << endl << endl;
362 //---------------------------------------------------------------------
363 // Test partionneDomaine() = extract groups from a sequential MED file
364 //---------------------------------------------------------------------
365 multipr::partitionneDomaine(strMEDfilename.c_str(), "MAIL");
367 //---------------------------------------------------------------------
368 // Test partitionneGrain() = split a group from a distributed MED file
369 // using MEDSPLITTER (METIS)
370 //---------------------------------------------------------------------
371 string strDistributedMEDfilename = g_medFilename;
372 strDistributedMEDfilename += "/agregat100grains_12pas_grains_maitre.med";
374 multipr::partitionneGrain(
375 strDistributedMEDfilename.c_str(),
378 multipr::MULTIPR_SCOTCH);
380 multipr::partitionneGrain(
381 strDistributedMEDfilename.c_str(),
384 multipr::MULTIPR_METIS);
386 //---------------------------------------------------------------------
387 // Test decimePartition() = generate 2 lower resolution of a mesh
388 // using decimation based on gradient
389 //---------------------------------------------------------------------
390 multipr::decimePartition(
391 strDistributedMEDfilename.c_str(),
393 "SIG_____SIEF_ELGA_______________",
395 "Filtre_GradientMoyen",
401 multipr::decimePartition(
402 strDistributedMEDfilename.c_str(),
404 "SIG_____SIEF_ELGA_______________",
406 "Filtre_GradientMoyen",
412 multipr::decimePartition(
413 strDistributedMEDfilename.c_str(),
415 "SIG_____SIEF_ELGA_______________",
417 "Filtre_GradientMoyen",
423 //---------------------------------------------------------------------
425 //---------------------------------------------------------------------
427 cout << "Test passed: everything seems to be OK" << endl;
428 cout << "OK" << endl << endl;
431 catch (multipr::RuntimeException& e)
435 cout << "Test failed" << endl;
436 cout << "Failure" << endl << endl;
437 ret = MULTIPR_APP_FAILED;
445 * \fn void runPartition1()
446 * \brief builds a distributed MED file (v2.3) by extracting groups from a sequential MED file.
447 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
451 int ret = MULTIPR_APP_OK;
454 multipr::partitionneDomaine(g_medFilename, g_meshName);
456 catch (multipr::RuntimeException& e)
459 ret = MULTIPR_APP_FAILED;
467 * \fn void runPartition2()
468 * \brief builds a distributed MED file (v2.3) by splitting a part of a distributed MED file generated by runPartition1().
469 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
473 int ret = MULTIPR_APP_OK;
476 multipr::partitionneGrain(
482 catch (multipr::RuntimeException& e)
485 ret = MULTIPR_APP_FAILED;
493 * \fn int runDecimation()
494 * \brief creates 3 resolutions of a part of a distributed MED file.
495 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
499 int ret = MULTIPR_APP_OK;
502 multipr::decimePartition(
513 catch (multipr::RuntimeException& e)
516 ret = MULTIPR_APP_FAILED;
524 * \fn int runDumpMED()
525 * \brief dumps info about a sequential MED file.
526 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
530 #ifdef MULTIPR_USE_OBJ_API
531 int ret = MULTIPR_APP_OK;
534 // if mesh is unknown, then list all the meshes in the given MED file
535 if (g_meshName == NULL)
538 obj.create(g_medFilename);
541 // display list of meshes contained in the MED file
542 vector<string> res = obj.getMeshes();
543 cout << "List of meshes in this MED file:" << endl;
544 for (unsigned i = 0 ; i < res.size() ; i++)
546 cout << "Mesh " << (i + 1) << ": \"" << res[i] << "\"" << endl;
553 // display list of fields contained in the MED file
554 vector<string> names = obj.getFields();
555 cout << "List of scalar fields in this MED file:" << endl;
556 for (unsigned i = 0 ; i < names.size() ; i++)
558 cout << "Field " << (i + 1) << ": \"" << names[i] << "\" #Time stamps=" << obj.getTimeStamps(names[i].c_str()) << endl;
564 // display all infos about one mesh in a MED file
566 mesh.readSequentialMED(g_medFilename, g_meshName);
567 mesh.setPrintAll(true);
568 cout << mesh << endl;
570 cout << "OK" << endl;
572 catch (multipr::RuntimeException& e)
575 ret = MULTIPR_APP_FAILED;
580 int ret = MULTIPR_APP_OK;
583 // if mesh is unknown, then list all the meshes in the given MED file
584 if (g_meshName == NULL)
587 // display list of meshes contained in the MED file
588 vector<string> res = multipr::getListMeshes(g_medFilename);
589 cout << "List of meshes in this MED file:" << endl;
590 for (unsigned i = 0 ; i < res.size() ; i++)
592 cout << "Mesh " << (i + 1) << ": \"" << res[i] << "\"" << endl;
599 // display list of fields contained in the MED file
600 vector<pair<string,int> > res = multipr::getListScalarFields(g_medFilename);
601 cout << "List of scalar fields in this MED file:" << endl;
602 for (unsigned i = 0 ; i < res.size() ; i++)
604 cout << "Field " << (i + 1) << ": \"" << res[i].first << "\" #Time stamps=" << res[i].second << endl;
610 // display all infos about one mesh in a MED file
612 mesh.readSequentialMED(g_medFilename, g_meshName);
613 mesh.setPrintAll(true);
614 cout << mesh << endl;
616 cout << "OK" << endl;
618 catch (multipr::RuntimeException& e)
621 ret = MULTIPR_APP_FAILED;
631 * \brief applies partitioning/decimation according to global parameters.
632 * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
638 int ret = MULTIPR_APP_OK;
641 case MULTIPR_USAGE_AUTOTEST: ret = runAutotest(); break;
642 case MULTIPR_USAGE_PARTITION1: ret = runPartition1(); break;
643 case MULTIPR_USAGE_PARTITION2: ret = runPartition2(); break;
644 case MULTIPR_USAGE_DECIMATION: ret = runDecimation(); break;
645 case MULTIPR_USAGE_INFO: ret = runDumpMED(); break;
647 cout << "ERROR: unknown usage" << endl;
648 ret = MULTIPR_APP_FAILED;
657 * \fn int main(int argc, char** argv)
658 * \brief entry point of the application.
659 * \param argc number of arguments.
660 * \param argv list of arguments.
661 * \return 0 if OK, 1 if failed.
663 int main(int argc, char** argv)
665 string strTitle = string("multipr v") + string(multipr::getVersion()) + string(" - by EDF/CS - 03/2007");
666 string strUnderline = "";
668 for (int i = 0, len = strTitle.length() ; i < len ; i++) strUnderline += '=';
670 cout << strTitle << endl;
671 cout << strUnderline << endl;
673 #ifdef MULTIPR_USE_OBJ_API
674 cout << "Version MULTIPR_Obj" << endl;
676 cout << "Version MULTIPR_API" << endl;
679 parseCommandLine(argc, argv);
681 int ret = MULTIPR_APP_OK; // assume no error at the beginning
683 if (g_usage == MULTIPR_USAGE_UNKNOWN)
687 // if usage is unknown and there are some arguments, print an error message
688 cout << "ERROR: " << getErrorMsg() << endl;
690 ret = MULTIPR_APP_FAILED;
694 // if no argument, print a description of this application
700 else if (g_usage == MULTIPR_USAGE_DISPLAY_HELP)
707 // the application seems to be configured properly: it can be executed