]> SALOME platform Git repositories - modules/multipr.git/blob - src/MULTIPR/multipr.cxx
Salome HOME
*** empty log message ***
[modules/multipr.git] / src / MULTIPR / multipr.cxx
1 // Project MULTIPR, IOLS WP1.2.1 - EDF/CS
2 // Partitioning/decimation module for the SALOME v3.2 platform
3
4 /**
5  * \file    multipr.cxx
6  *
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.
14  *
15  *          Return 0 if application succeed, 1 otherwise (failure).
16  *
17  *          See http://www.salome-platform.org to learn more about Salome or MED.
18  *
19  * \author  Olivier LE ROUX - CS, Virtual Reality Dpt
20  * 
21  * \date    01/2007
22  */
23
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"
29
30 #include <iostream>
31 #include <vector>
32 #include <string>
33
34 using namespace std;
35
36
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
41
42
43 const int MULTIPR_APP_OK     = 0;
44 const int MULTIPR_APP_FAILED = 1;
45
46
47 /**
48  * Enumerates all the usages of this application.
49  */
50 enum Usage
51 {
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,
58     MULTIPR_USAGE_INFO
59 };
60
61
62 /**
63  * Enumerates all the possible errors.
64  */
65 enum Error
66 {
67     MULTIPR_APP_NO_ERROR,
68     MULTIPR_APP_UNKNOWN_USAGE,
69     MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS,
70     MULTIPR_APP_ILLEGAL_ARGUMENT,
71     MULTIPR_APP_FILE_NOT_FOUND,
72     MULTIPR_APP_IO_ERROR,
73     MULTIPR_APP_UNDEFINED_ERROR
74 };
75
76
77 // global variables used to configure the application
78 int   g_usage               = 0; 
79 int   g_errorCode           = MULTIPR_APP_NO_ERROR;
80 char* g_medFilename         = NULL;
81 char* g_meshName            = NULL;
82 char* g_partName            = NULL;
83 int   g_nbParts             = 0;
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;
91 int   g_boxing              = 100;
92
93
94 /**
95  * \fn     const char* getUsage(int usage)
96  * \brief  returns a string describing the usage of this application.
97  */
98 const char* getUsage(int usage)
99 {
100     switch(usage)
101     {
102         case MULTIPR_USAGE_DISPLAY_HELP:
103             return "--help: display help";
104             
105         case MULTIPR_USAGE_AUTOTEST:
106             return "--auto: perform all unit tests";
107
108         case MULTIPR_USAGE_PARTITION1:
109             return "--part1: extract all groups of a sequential MED file";
110
111         case MULTIPR_USAGE_PARTITION2:
112             return "--part2: split a part of a distributed MED file";
113
114         case MULTIPR_USAGE_DECIMATION:
115             return "--decim: generated level of details of a part of a distributed MED file";
116             
117         case MULTIPR_USAGE_INFO:
118             return "--info: prints all infos about a mesh in a sequential MED file";
119
120         default:
121             return "unknown";
122     }
123 }
124
125
126 /**
127  * \fn     void printDescription()
128  * \brief  prints a short description of this application.
129  */
130 void printDescription()
131 {
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;
139 }
140
141
142 /**
143  * \fn     void printUsage()
144  * \brief  prints "how to use" manual of this tools.2NbPart
145  */
146 void printUsage()
147 {
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;
164     cout << endl;
165 }
166
167
168 /**
169  * \fn     void printGlobals()
170  * \brief  print current state of all global variables.
171  */
172 void printGlobals()
173 {
174     cout << endl;
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;
192     cout << endl;
193 }
194
195
196 /**
197  * \fn     const char* getErrorMsg()
198  * \brief  returns the error message corresponding to current error code.
199  * \return the current error message.
200  */
201 const char* getErrorMsg()
202 {
203     switch (g_errorCode)
204     {
205         case MULTIPR_APP_NO_ERROR:
206             return "no error";
207         
208         case MULTIPR_APP_UNKNOWN_USAGE:
209             return "unknown usage";
210             
211         case MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS:
212             return "wrong number of arguments";
213         
214         case MULTIPR_APP_ILLEGAL_ARGUMENT:
215             return "illegal argument";
216         
217         case MULTIPR_APP_FILE_NOT_FOUND:
218             return "file not found";
219             
220         case MULTIPR_APP_IO_ERROR:
221             return "i/o error";
222             
223         default:
224             return "error (undefined)";
225     }
226 }
227
228
229 /**
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.
234  */
235 void parseCommandLine(int argc, char** argv)
236 {
237     if (argc == 1)
238     {
239         g_usage = MULTIPR_USAGE_UNKNOWN; 
240         return;
241     }
242     
243     if (strcmp(argv[1],"--help") == 0)
244     {
245         g_usage = MULTIPR_USAGE_DISPLAY_HELP;
246     }
247     else if (strcmp(argv[1],"--auto") == 0)
248     {
249         if (argc != 3)
250         {
251             g_usage = MULTIPR_USAGE_UNKNOWN; 
252             g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
253         }
254         else
255         {
256             g_usage = MULTIPR_USAGE_AUTOTEST;
257             g_medFilename = argv[2];
258         }
259     }
260     else if (strcmp(argv[1],"--part1") == 0)
261     {
262         if (argc != 4)
263         {
264             g_usage = MULTIPR_USAGE_UNKNOWN; 
265             g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
266         }
267         else
268         {
269             g_usage       = MULTIPR_USAGE_PARTITION1;
270             g_medFilename = argv[2];
271             g_meshName    = argv[3];
272         }
273     }
274     else if (strcmp(argv[1],"--part2") == 0)
275     {
276         if ((argc != 5) && (argc != 6))
277         {
278             g_usage = MULTIPR_USAGE_UNKNOWN; 
279             g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
280         }
281         else
282         {
283             g_usage       = MULTIPR_USAGE_PARTITION2; 
284             g_medFilename = argv[2];
285             g_partName    = argv[3];
286             g_nbParts     = atoi(argv[4]);
287             
288             if (argc == 6)
289             {
290                 g_splitter = atoi(argv[5]);
291             }
292         }
293     }
294     else if (strcmp(argv[1],"--decim") == 0)
295     {
296         if ((argc != 10) && (argc != 11))
297         {
298             g_usage = MULTIPR_USAGE_UNKNOWN; 
299             g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
300         }
301         else
302         {
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]);
312             
313             if (argc == 11)
314             {
315                 g_boxing = atoi(argv[10]);
316             }
317         }
318     }
319     else if (strcmp(argv[1],"--info") == 0)
320     {
321         if ((argc != 3) && (argc != 4))
322         {
323             g_usage = MULTIPR_USAGE_UNKNOWN; 
324             g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
325         }
326         else
327         {
328             g_usage        = MULTIPR_USAGE_INFO; 
329             g_medFilename  = argv[2];
330             
331             if (argc == 4)
332             {
333                 g_meshName = argv[3];
334             }
335         }
336     }
337     else
338     {
339         g_usage = MULTIPR_USAGE_UNKNOWN;
340         g_errorCode = MULTIPR_APP_UNKNOWN_USAGE;
341     }
342 }
343
344
345 /**
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.
349  */
350 int runAutotest()
351 {
352     cout << "Start autotest..." << endl;
353     
354     int ret = MULTIPR_APP_OK;
355     try
356     {
357         string strMEDfilename = g_medFilename;
358         strMEDfilename += "/agregat100grains_12pas.med";
359         
360         cout << "Test file: " << strMEDfilename << endl << endl;
361         
362         //---------------------------------------------------------------------
363         // Test partionneDomaine() = extract groups from a sequential MED file
364         //---------------------------------------------------------------------
365         multipr::partitionneDomaine(strMEDfilename.c_str(), "MAIL"); 
366         
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";
373         
374         multipr::partitionneGrain(
375             strDistributedMEDfilename.c_str(), 
376             "MAIL_1", 
377             4, 
378             multipr::MULTIPR_SCOTCH);
379             
380         multipr::partitionneGrain(
381             strDistributedMEDfilename.c_str(), 
382             "MAIL_97", 
383             3, 
384             multipr::MULTIPR_METIS);
385
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(), 
392             "MAIL_98",
393             "SIG_____SIEF_ELGA_______________",
394             12,
395             "Filtre_GradientMoyen",
396             10.0,
397             25.0,
398             0.3,
399             100);
400             
401         multipr::decimePartition(
402             strDistributedMEDfilename.c_str(), 
403             "MAIL_92",
404             "SIG_____SIEF_ELGA_______________",
405             11,
406             "Filtre_GradientMoyen",
407             10.0,
408             25.0,
409             0.5,
410             10);
411         
412         multipr::decimePartition(
413             strDistributedMEDfilename.c_str(), 
414             "MAIL_97_2",
415             "SIG_____SIEF_ELGA_______________",
416             10,
417             "Filtre_GradientMoyen",
418             10.0,
419             25.0,
420             0.4,
421             20);
422             
423         //---------------------------------------------------------------------
424         // Test passed: OK!
425         //---------------------------------------------------------------------
426         cout << endl;
427         cout << "Test passed: everything seems to be OK" << endl;
428         cout << "OK" << endl << endl;
429         
430     }
431     catch (multipr::RuntimeException& e)
432     {
433         e.dump(cout);
434         cout << endl;
435         cout << "Test failed" << endl;
436         cout << "Failure" << endl << endl;
437         ret = MULTIPR_APP_FAILED;
438     }
439     
440     return ret;
441 }
442
443
444 /**
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.
448  */
449 int runPartition1()
450 {
451     int ret = MULTIPR_APP_OK;
452     try
453     {
454         multipr::partitionneDomaine(g_medFilename, g_meshName);    
455     }
456     catch (multipr::RuntimeException& e)
457     {
458         e.dump(cout);
459         ret = MULTIPR_APP_FAILED;
460     }
461         
462     return ret;
463 }
464
465
466 /**
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.
470  */
471 int runPartition2()
472 {    
473     int ret = MULTIPR_APP_OK;
474     try
475     {
476         multipr::partitionneGrain(
477             g_medFilename, 
478             g_partName, 
479             g_nbParts, 
480             g_splitter);
481     }
482     catch (multipr::RuntimeException& e)
483     {
484         e.dump(cout);
485         ret = MULTIPR_APP_FAILED;
486     }
487         
488     return ret;
489 }
490
491
492 /**
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.
496  */
497 int runDecimation()
498 {    
499     int ret = MULTIPR_APP_OK;
500     try
501     {
502         multipr::decimePartition(
503             g_medFilename, 
504             g_partName,
505             g_fieldName,
506             g_fieldTimeStepIt,
507             g_filterName,
508             g_decimThresholdMed,
509             g_decimThresholdLow,
510             g_decimRadius,
511             g_boxing);
512     }
513     catch (multipr::RuntimeException& e)
514     {
515         e.dump(cout);
516         ret = MULTIPR_APP_FAILED;
517     }
518         
519     return ret;
520 }
521
522
523 /**
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.
527  */
528 int runDumpMED()
529 {
530 #ifdef MULTIPR_USE_OBJ_API
531     int ret = MULTIPR_APP_OK;
532     try
533     {
534         // if mesh is unknown, then list all the meshes in the given MED file
535         if (g_meshName == NULL)
536         {
537             multipr::Obj obj;
538             obj.create(g_medFilename);
539             
540             {
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++)
545                 {
546                     cout << "Mesh " << (i + 1) << ": \"" << res[i] << "\"" << endl;
547                 }
548             }
549             
550             cout << endl;
551             
552             {
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++)
557                 {
558                     cout << "Field " << (i + 1) << ": \"" << names[i] << "\"  #Time stamps=" << obj.getTimeStamps(names[i].c_str()) << endl;
559                 }
560             }
561         }
562         else
563         {
564             // display all infos about one mesh in a MED file
565             multipr::Mesh mesh;
566             mesh.readSequentialMED(g_medFilename, g_meshName);
567             mesh.setPrintAll(true);
568             cout << mesh << endl;
569         }
570         cout << "OK" << endl;
571     }
572     catch (multipr::RuntimeException& e)
573     {
574         e.dump(cout);
575         ret = MULTIPR_APP_FAILED;
576     }
577     
578     return ret;
579 #else
580     int ret = MULTIPR_APP_OK;
581     try
582     {
583         // if mesh is unknown, then list all the meshes in the given MED file
584         if (g_meshName == NULL)
585         {
586             {
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++)
591                 {
592                     cout << "Mesh " << (i + 1) << ": \"" << res[i] << "\"" << endl;
593                 }
594             }
595             
596             cout << endl;
597             
598             {
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++)
603                 {
604                     cout << "Field " << (i + 1) << ": \"" << res[i].first << "\"  #Time stamps=" << res[i].second << endl;
605                 }
606             }
607         }
608         else
609         {
610             // display all infos about one mesh in a MED file
611             multipr::Mesh mesh;
612             mesh.readSequentialMED(g_medFilename, g_meshName);
613             mesh.setPrintAll(true);
614             cout << mesh << endl;
615         }
616         cout << "OK" << endl;
617     }
618     catch (multipr::RuntimeException& e)
619     {
620         e.dump(cout);
621         ret = MULTIPR_APP_FAILED;
622     }
623     
624     return ret;
625 #endif
626 }
627
628
629 /**
630  * \fn     int run()
631  * \brief  applies partitioning/decimation according to global parameters.
632  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
633  */
634 int run()
635 {
636     printGlobals();
637
638     int ret = MULTIPR_APP_OK;
639     switch (g_usage)
640     {
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;
646         default:
647             cout << "ERROR: unknown usage" << endl;
648             ret = MULTIPR_APP_FAILED;
649             break;
650     }
651     
652     return ret;
653 }
654
655
656 /**
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.
662  */
663 int main(int argc, char** argv)
664 {
665     string strTitle = string("multipr v") + string(multipr::getVersion()) + string(" - by EDF/CS - 03/2007");    
666     string strUnderline = "";
667     
668     for (int i = 0, len = strTitle.length() ; i < len ; i++) strUnderline += '=';
669     
670     cout << strTitle << endl;
671     cout << strUnderline << endl;
672     
673     #ifdef MULTIPR_USE_OBJ_API
674         cout << "Version MULTIPR_Obj" << endl;
675     #else
676         cout << "Version MULTIPR_API" << endl;
677     #endif   
678
679     parseCommandLine(argc, argv);
680
681     int ret = MULTIPR_APP_OK; // assume no error at the beginning
682     
683     if (g_usage == MULTIPR_USAGE_UNKNOWN)
684     {
685         if (argc != 1)
686         {
687             // if usage is unknown and there are some arguments, print an error message 
688             cout << "ERROR: " << getErrorMsg() << endl;
689             cout << endl;
690             ret = MULTIPR_APP_FAILED;
691         }
692         else
693         {
694             // if no argument, print a description of this application
695             printDescription();
696         }
697
698         printUsage();
699     }
700     else if (g_usage == MULTIPR_USAGE_DISPLAY_HELP)
701     {
702         printDescription();
703         printUsage();
704     }
705     else
706     {
707         // the application seems to be configured properly: it can be executed
708         ret = run();
709     }
710     
711     return ret;
712 }
713
714 // EOF