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 char* g_filterName          = NULL;
85 char* g_fieldName           = NULL;
86 int   g_fieldTimeStepIt     = 0;
87 float g_decimThresholdMed   = 0.0f;
88 float g_decimThresholdLow   = 0.0f;
89 float g_decimRadius         = 0.0f;
90 int   g_boxing              = 100;
91
92
93 /**
94  * \fn     const char* getUsage(int usage)
95  * \brief  returns a string describing the usage of this application.
96  */
97 const char* getUsage(int usage)
98 {
99         switch(usage)
100         {
101                 case MULTIPR_USAGE_DISPLAY_HELP:
102                         return "--help: display help";
103                         
104                 case MULTIPR_USAGE_AUTOTEST:
105                         return "--auto: unit tests";
106
107                 case MULTIPR_USAGE_PARTITION1:
108                         return "--part1: extract all groups of a sequential MED file";
109
110                 case MULTIPR_USAGE_PARTITION2:
111                         return "--part2: split a part of a distributed MED file";
112
113                 case MULTIPR_USAGE_DECIMATION:
114                         return "--decim: generated level of details of a part of a distributed MED file";
115                         
116                 case MULTIPR_USAGE_INFO:
117                         return "--info: prints all infos about a mesh in a sequential MED file";
118
119                 default:
120                         return "unknown";
121         }
122 }
123
124
125 /**
126  * \fn     void printDescription()
127  * \brief  prints a short description of this application.
128  */
129 void printDescription()
130 {
131         cout << "Keywords:" << endl;          
132         cout << "    Post-processing numerical simulation, Salome platform, " << endl;
133         cout << "    Large data set visualization, 3D meshes and fields" << endl;
134         cout << "Description:" << endl;
135         cout << "    multipr is a partitionning/decimation tool of MED files." << endl;
136         cout << "    See http://www.salome-platform.org for information about MED or Salome." << endl;
137         cout << "    Note: current version only accept TETRA10 meshes." << endl;
138 }
139
140
141 /**
142  * \fn     void printUsage()
143  * \brief  prints "how to use" manual of this tools.2NbPart
144  */
145 void printUsage()
146 {
147         cout << "Usages:" << endl;
148         cout << "    --auto   Autotest: performs some unit tests on the MULTIPR API" << endl;
149         cout << "                 * Usage: --auto path (path where to find test file \"agregat100grains_12pas.med\")" << endl;
150         cout << "    --part1  Extracts all groups from a sequential MED file (V2.2 or higher)" << endl;
151         cout << "                 * Usage: --part1 file.med meshName" << endl; 
152         cout << "    --part2  Split a group of a distributed MED file (V2.3) produced with --part1" << endl;
153         cout << "                 * Usage: --part2 file.med partName nbParts" << endl;
154         cout << "    --decim  Generates 3 level of details (full, medium and low) of a part" << endl;
155         cout << "             of a distributed MED file (V2.3)" << endl;     
156         cout << "                 * Usage: --decim file.med partName fieldName fieldIt filterName [...]" << endl;
157         cout << "                 * Only one filter is currently available: Filtre_GradientMoyen" << endl;
158         cout << "                 * Usage: --decim file.med partName fieldName fieldIt Filtre_GradientMoyen m l radius" << endl;
159         cout << "                   where m=threshold for medium res. and l=threshold for low res.; assume m < l" << endl;
160         cout << "    --info   Dumps all infos related to a mesh in a sequential MED file" << endl;
161         cout << "                 * Usage: --info file.med [meshName]" << endl;
162         cout << "    --help   Displays this help page" << endl;
163         cout << endl;
164 }
165
166
167 /**
168  * \fn     void printGlobals()
169  * \brief  print current state of all global variables.
170  */
171 void printGlobals()
172 {
173         cout << endl;
174         cout << "********************************************************************************" << endl;
175         cout << "CONFIGURATION" << endl;
176         cout << "--------------------------------------------------------------------------------" << endl;
177         cout << "Mode                        : " << getUsage(g_usage) << endl;
178         cout << "Med filename                : " << ((g_medFilename != NULL) ? g_medFilename : "UNDEFINED") << endl;
179         cout << "Mesh name                   : " << ((g_meshName != NULL) ? g_meshName : "UNDEFINED") << endl;
180         cout << "Part name                   : " << ((g_partName != NULL) ? g_partName : "UNDEFINED") << endl;
181         cout << "Nb parts                    : "  << g_nbParts << endl;
182         cout << "Decimation:" << endl;
183         cout << "    Field name              : " << ((g_fieldName != NULL) ? g_fieldName : "UNDEFINED") << endl;
184         cout << "    Time step iteration     : " << g_fieldTimeStepIt << endl;
185         cout << "    Filter name             : " << ((g_filterName != NULL) ? g_filterName : "UNDEFINED") << endl;
186         cout << "    Threshold for med. res. : " << g_decimThresholdMed << endl;
187         cout << "    Threshold for low res.  : " << g_decimThresholdLow << endl;
188         cout << "    Radius                  : " << g_decimRadius << endl;
189         cout << "    Boxing                  : " << g_boxing << endl;
190         cout << "********************************************************************************" << endl;
191         cout << endl;
192 }
193
194
195 /**
196  * \fn     const char* getErrorMsg()
197  * \brief  returns the error message corresponding to current error code.
198  * \return the current error message.
199  */
200 const char* getErrorMsg()
201 {
202         switch (g_errorCode)
203         {
204                 case MULTIPR_APP_NO_ERROR:
205                         return "no error";
206                 
207                 case MULTIPR_APP_UNKNOWN_USAGE:
208                         return "unknown usage";
209                         
210                 case MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS:
211                         return "wrong number of arguments";
212                 
213                 case MULTIPR_APP_ILLEGAL_ARGUMENT:
214                         return "illegal argument";
215                 
216                 case MULTIPR_APP_FILE_NOT_FOUND:
217                         return "file not found";
218                         
219                 case MULTIPR_APP_IO_ERROR:
220                         return "i/o error";
221                         
222                 default:
223                         return "error (undefined)";
224         }
225 }
226
227
228 /**
229  * \fn     void parseCommandLine(int argc, char** argv)
230  * \brief  parses the command line and configure this application.
231  * \param  argc number of arguments.
232  * \param  argv array of arguments.
233  */
234 void parseCommandLine(int argc, char** argv)
235 {
236         if (argc == 1)
237         {
238                 g_usage = MULTIPR_USAGE_UNKNOWN; 
239                 return;
240         }
241         
242         if (strcmp(argv[1],"--help") == 0)
243         {
244                 g_usage = MULTIPR_USAGE_DISPLAY_HELP;
245         }
246         else if (strcmp(argv[1],"--auto") == 0)
247         {
248                 if (argc != 3)
249                 {
250                         g_usage = MULTIPR_USAGE_UNKNOWN; 
251                         g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
252                 }
253                 else
254                 {
255                         g_usage = MULTIPR_USAGE_AUTOTEST;
256                         g_medFilename = argv[2];
257                 }
258         }
259         else if (strcmp(argv[1],"--part1") == 0)
260         {
261                 if (argc != 4)
262                 {
263                         g_usage = MULTIPR_USAGE_UNKNOWN; 
264                         g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
265                 }
266                 else
267                 {
268                         g_usage       = MULTIPR_USAGE_PARTITION1;
269                         g_medFilename = argv[2];
270                         g_meshName    = argv[3];
271                 }
272         }
273         else if (strcmp(argv[1],"--part2") == 0)
274         {
275                 if (argc != 5)
276                 {
277                         g_usage = MULTIPR_USAGE_UNKNOWN; 
278                         g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
279                 }
280                 else
281                 {
282                         g_usage       = MULTIPR_USAGE_PARTITION2; 
283                         g_medFilename = argv[2];
284                         g_partName    = argv[3];
285                         g_nbParts     = atoi(argv[4]);
286                 }
287         }
288         else if (strcmp(argv[1],"--decim") == 0)
289         {
290                 if ((argc != 10) && (argc != 11))
291                 {
292                         g_usage = MULTIPR_USAGE_UNKNOWN; 
293                         g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
294                 }
295                 else
296                 {
297                         g_usage               = MULTIPR_USAGE_DECIMATION; 
298                         g_medFilename         = argv[2];
299                         g_partName            = argv[3];
300                         g_fieldName           = argv[4];
301                         g_fieldTimeStepIt     = atoi(argv[5]);
302                         g_filterName          = argv[6];
303                         g_decimThresholdMed   = atof(argv[7]);
304                         g_decimThresholdLow   = atof(argv[8]);
305                         g_decimRadius         = atof(argv[9]);
306                         
307                         if (argc == 11)
308                         {
309                                 g_boxing      = atoi(argv[10]);
310                         }
311                 }
312         }
313         else if (strcmp(argv[1],"--info") == 0)
314         {
315                 if ((argc != 3) && (argc != 4))
316                 {
317                         g_usage = MULTIPR_USAGE_UNKNOWN; 
318                         g_errorCode = MULTIPR_APP_WRONG_NUMBER_OF_ARGUMENTS;
319                 }
320                 else
321                 {
322                         g_usage               = MULTIPR_USAGE_INFO; 
323                         g_medFilename         = argv[2];
324                         
325                         if (argc == 4)
326                         {
327                                 g_meshName    = argv[3];
328                         }
329                 }
330         }
331         else
332         {
333                 g_usage = MULTIPR_USAGE_UNKNOWN;
334                 g_errorCode = MULTIPR_APP_UNKNOWN_USAGE;
335         }
336 }
337
338
339 /**
340  * \fn     int runAutotest()
341  * \brief  performs some unit tests on the MULTIPR API. 
342  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
343  */
344 int runAutotest()
345 {
346         cout << "Start autotest..." << endl;
347         
348         int ret = MULTIPR_APP_OK;
349         try
350         {
351                 string strMEDfilename = g_medFilename;
352                 strMEDfilename += "/agregat100grains_12pas.med";
353                 
354                 cout << "Test file: " << strMEDfilename << endl << endl;
355                 
356                 //---------------------------------------------------------------------
357                 // Test partionneDomaine() = extract groups from a sequential MED file
358                 //---------------------------------------------------------------------
359                 multipr::partitionneDomaine(strMEDfilename.c_str(), "MAIL"); 
360                 
361                 //---------------------------------------------------------------------
362                 // Test partitionneGrain() = split a group from a distributed MED file
363                 // using MEDSPLITTER (METIS)
364                 //---------------------------------------------------------------------
365                 string strDistributedMEDfilename = g_medFilename;
366                 strDistributedMEDfilename += "/agregat100grains_12pas_grains_maitre.med";
367                 
368                 multipr::partitionneGrain(
369                         strDistributedMEDfilename.c_str(), 
370                         "MAIL_1", 
371                         4, 
372                         multipr::MULTIPR_SCOTCH);
373                         
374                 multipr::partitionneGrain(
375                         strDistributedMEDfilename.c_str(), 
376                         "MAIL_97", 
377                         3, 
378                         multipr::MULTIPR_METIS);
379
380                 //---------------------------------------------------------------------
381                 // Test decimePartition() = generate 2 lower resolution of a mesh
382                 // using decimation based on gradient
383                 //---------------------------------------------------------------------
384                 multipr::decimePartition(
385                         strDistributedMEDfilename.c_str(), 
386                         "MAIL_98",
387                         "SIG_____SIEF_ELGA_______________",
388                         12,
389                         "Filtre_GradientMoyen",
390                         10.0,
391                         25.0,
392                         0.3,
393                         100);
394                         
395                 multipr::decimePartition(
396                         strDistributedMEDfilename.c_str(), 
397                         "MAIL_92",
398                         "SIG_____SIEF_ELGA_______________",
399                         11,
400                         "Filtre_GradientMoyen",
401                         10.0,
402                         25.0,
403                         0.5,
404                         10);
405                 
406                 multipr::decimePartition(
407                         strDistributedMEDfilename.c_str(), 
408                         "MAIL_97_2",
409                         "SIG_____SIEF_ELGA_______________",
410                         10,
411                         "Filtre_GradientMoyen",
412                         10.0,
413                         25.0,
414                         0.4,
415                         20);
416                         
417                 //---------------------------------------------------------------------
418                 // Test passed: OK!
419                 //---------------------------------------------------------------------
420                 cout << endl;
421                 cout << "Test passed: everything seems to be OK" << endl;
422                 cout << "OK" << endl << endl;
423                 
424         }
425         catch (multipr::RuntimeException& e)
426         {
427                 e.dump(cout);
428                 cout << endl;
429                 cout << "Test failed" << endl;
430                 cout << "Failure" << endl << endl;
431                 ret = MULTIPR_APP_FAILED;
432         }
433         
434         return ret;
435 }
436
437
438 /**
439  * \fn     void runPartition1()
440  * \brief  builds a distributed MED file (v2.3) by extracting groups from a sequential MED file. 
441  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
442  */
443 int runPartition1()
444 {
445         int ret = MULTIPR_APP_OK;
446         try
447         {
448                 multipr::partitionneDomaine(g_medFilename, g_meshName); 
449         }
450         catch (multipr::RuntimeException& e)
451         {
452                 e.dump(cout);
453                 ret = MULTIPR_APP_FAILED;
454         }
455                 
456         return ret;
457 }
458
459
460 /**
461  * \fn     void runPartition2()
462  * \brief  builds a distributed MED file (v2.3) by splitting a part of a distributed MED file generated by runPartition1().  
463  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
464  */
465 int runPartition2()
466 {       
467         int ret = MULTIPR_APP_OK;
468         try
469         {
470                 multipr::partitionneGrain(
471                         g_medFilename, 
472                         g_partName, 
473                         g_nbParts, 
474                         multipr::MULTIPR_METIS);
475         }
476         catch (multipr::RuntimeException& e)
477         {
478                 e.dump(cout);
479                 ret = MULTIPR_APP_FAILED;
480         }
481                 
482         return ret;
483 }
484
485
486 /**
487  * \fn     int runDecimation()
488  * \brief  creates 3 resolutions of a part of a distributed MED file. 
489  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
490  */
491 int runDecimation()
492 {       
493         int ret = MULTIPR_APP_OK;
494         try
495         {
496                 multipr::decimePartition(
497                         g_medFilename, 
498                         g_partName,
499                         g_fieldName,
500                         g_fieldTimeStepIt,
501                         g_filterName,
502                         g_decimThresholdMed,
503                         g_decimThresholdLow,
504                         g_decimRadius,
505                         g_boxing);
506         }
507         catch (multipr::RuntimeException& e)
508         {
509                 e.dump(cout);
510                 ret = MULTIPR_APP_FAILED;
511         }
512                 
513         return ret;
514 }
515
516
517 /**
518  * \fn     int runDumpMED()
519  * \brief  dumps info about a sequential MED file.
520  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
521  */
522 int runDumpMED()
523 {
524 #ifdef MULTIPR_USE_OBJ_API
525         int ret = MULTIPR_APP_OK;
526         try
527         {
528                 // if mesh is unknown, then list all the meshes in the given MED file
529                 if (g_meshName == NULL)
530                 {
531                         multipr::Obj obj;
532                         obj.create(g_medFilename);
533                         
534                         {
535                                 // display list of meshes contained in the MED file
536                                 vector<string> res = obj.getMeshes();
537                                 cout << "List of meshes in this MED file:" << endl;
538                                 for (unsigned i = 0 ; i < res.size() ; i++)
539                                 {
540                                         cout << "Mesh " << (i + 1) << ": " << res[i] << endl;
541                                 }
542                         }
543                         
544                         cout << endl;
545                         
546                         {
547                                 // display list of fields contained in the MED file
548                                 vector<string> names = obj.getFields();
549                                 cout << "List of fields in this MED file:" << endl;
550                                 for (unsigned i = 0 ; i < names.size() ; i++)
551                                 {
552                                         cout << "Field " << (i + 1) << ": " << names[i] << " #it=" << obj.getTimeStamps(names[i].c_str()) << endl;
553                                 }
554                         }
555                 }
556                 else
557                 {
558                         // display all infos about one mesh in a MED file
559                         multipr::Mesh mesh;
560                         mesh.readSequentialMED(g_medFilename, g_meshName);
561                         mesh.setPrintAll(true);
562                         cout << mesh << endl;
563                 }
564                 cout << "OK" << endl;
565         }
566         catch (multipr::RuntimeException& e)
567         {
568                 e.dump(cout);
569                 ret = MULTIPR_APP_FAILED;
570         }
571         
572         return ret;
573 #else
574         int ret = MULTIPR_APP_OK;
575         try
576         {
577                 // if mesh is unknown, then list all the meshes in the given MED file
578                 if (g_meshName == NULL)
579                 {
580                         {
581                                 // display list of meshes contained in the MED file
582                                 vector<string> res = multipr::getListMeshes(g_medFilename);
583                                 cout << "List of meshes in this MED file:" << endl;
584                                 for (unsigned i = 0 ; i < res.size() ; i++)
585                                 {
586                                         cout << "Mesh " << (i + 1) << ": " << res[i] << endl;
587                                 }
588                         }
589                         
590                         cout << endl;
591                         
592                         {
593                                 // display list of fields contained in the MED file
594                                 vector<pair<string,int> > res = multipr::getListScalarFields(g_medFilename);
595                                 cout << "List of fields in this MED file:" << endl;
596                                 for (unsigned i = 0 ; i < res.size() ; i++)
597                                 {
598                                         cout << "Field " << (i + 1) << ": " << res[i].first << " #it=" << res[i].second << endl;
599                                 }
600                         }
601                 }
602                 else
603                 {
604                         // display all infos about one mesh in a MED file
605                         multipr::Mesh mesh;
606                         mesh.readSequentialMED(g_medFilename, g_meshName);
607                         mesh.setPrintAll(true);
608                         cout << mesh << endl;
609                 }
610                 cout << "OK" << endl;
611         }
612         catch (multipr::RuntimeException& e)
613         {
614                 e.dump(cout);
615                 ret = MULTIPR_APP_FAILED;
616         }
617         
618         return ret;
619 #endif
620 }
621
622
623 /**
624  * \fn     int run()
625  * \brief  applies partitioning/decimation according to global parameters.
626  * \return MULTIPR_APP_OK if successful, MULTIPR_APP_FAILED if failure.
627  */
628 int run()
629 {
630         printGlobals();
631
632         int ret = MULTIPR_APP_OK;
633         switch (g_usage)
634         {
635                 case MULTIPR_USAGE_AUTOTEST:   ret = runAutotest();   break;
636                 case MULTIPR_USAGE_PARTITION1: ret = runPartition1(); break;
637                 case MULTIPR_USAGE_PARTITION2: ret = runPartition2(); break;
638                 case MULTIPR_USAGE_DECIMATION: ret = runDecimation(); break;
639                 case MULTIPR_USAGE_INFO:       ret = runDumpMED();    break;
640                 default:
641                         cout << "ERROR: unknown usage" << endl;
642                         ret = MULTIPR_APP_FAILED;
643                         break;
644         }
645         
646         return ret;
647 }
648
649
650 /**
651  * \fn     int main(int argc, char** argv)
652  * \brief  entry point of the application.
653  * \param  argc number of arguments.
654  * \param  argv list of arguments.
655  * \return 0 if OK, 1 if failed.
656  */
657 int main(int argc, char** argv)
658 {
659         cout << "multipr v" << multipr::getVersion() << " - by EDF/CS - 01/2007" << endl;
660         cout << "==================================" << endl;
661         
662         #ifdef MULTIPR_USE_OBJ_API
663                 cout << "Version MULTIPR_Obj" << endl;
664         #else
665                 cout << "Version MULTIPR_API" << endl;
666         #endif   
667
668         parseCommandLine(argc, argv);
669
670         int ret = MULTIPR_APP_OK; // assume no error at the beginning
671         
672         if (g_usage == MULTIPR_USAGE_UNKNOWN)
673         {
674                 if (argc != 1)
675                 {
676                         // if usage is unknown and there are some arguments, print an error message 
677                         cout << "ERROR: " << getErrorMsg() << endl;
678                         cout << endl;
679                         ret = MULTIPR_APP_FAILED;
680                 }
681                 else
682                 {
683                         // if no argument, print a description of this application
684                         printDescription();
685                 }
686
687                 printUsage();
688         }
689         else if (g_usage == MULTIPR_USAGE_DISPLAY_HELP)
690         {
691                 printDescription();
692                 printUsage();
693         }
694         else
695         {
696                 // the application seems to be configured properly: it can be executed
697                 ret = run();
698         }
699         
700         return ret;
701 }
702
703 // EOF