Salome HOME
42a4ae9a72d9295aeaec2aa58053d549d0acdc04
[tools/medcoupling.git] / src / MEDPartitioner / medpartitioner.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 /*
21   examples of launch
22   export verb=1
23   medpartitioner --input-file=blade.med --output-file=ttmp1_ --ndomains=2 --dump-cpu-memory --verbose=$verb
24   medpartitioner --input-file=medpartitioner_blade.xml --output-file=ttmp1_ --ndomains=2 --dump-cpu-memory --verbose=$verb
25   medpartitioner --input-file=ttmp1_.xml --output-file=tttmp1_ --ndomains=4 --dump-cpu-memory --verbose=$verb
26 */
27
28 /*
29 #include "MEDPARTITIONER_Graph.hxx"
30 #include "MEDPARTITIONER_Topology.hxx"
31 #include "MEDPARTITIONER_ParaDomainSelector.hxx"
32 #include "MEDPARTITIONER_MeshCollection.hxx"
33 #include "MEDPARTITIONER_Utils.hxx"
34 */
35
36 #include "MEDPARTITIONER_MeshCollection.hxx"
37 #include "MEDPARTITIONER_ParallelTopology.hxx"
38 #include "MEDPARTITIONER_ParaDomainSelector.hxx"
39 #include "MEDPARTITIONER_Utils.hxx"
40
41 #include <string>
42 #include <fstream>
43 #include <cstring>
44 #include <cstdlib>
45 #include <iostream>
46
47 using namespace std;
48 using namespace MEDPARTITIONER;
49
50 int main(int argc, char** argv)
51 {
52 #if !defined(MED_ENABLE_METIS) && !defined(MED_ENABLE_SCOTCH)
53   std::cout << "Sorry, no one split method is available. Please, compile with METIS or SCOTCH." << std::endl;
54   return 1;
55 #else
56
57   // Defining options
58   // by parsing the command line
59   
60   bool split_family=false;
61   bool empty_groups=false;
62   bool mesure_memory=false;
63   bool filter_face=true;
64
65   string input;
66   string output;
67   string meshname;
68   string library="metis";  //default
69   int ndomains;
70   int help=0;
71   
72   //sequential : no MPI
73   MyGlobals::_World_Size=1;
74   MyGlobals::_Rank=0;
75   MyGlobals::_Create_Boundary_Faces=0;
76   MyGlobals::_Create_Joints=0;
77
78   // Primitive parsing of command-line options
79   string desc ("Available options of medpartitioner V1.0:\n"
80                "\t--help                   : produces this help message\n"
81                "\t--verbose                : echoes arguments\n"
82                "\t--input-file=<string>    : name of the input .med file or .xml master file\n"
83                "\t--output-file=<string>   : name of the resulting file (without extension)\n"
84                "\t--ndomains=<number>      : number of subdomains in the output file, default is 1\n"
85 #if defined(MED_ENABLE_METIS) && defined(MED_ENABLE_SCOTCH)
86   //user can choose!
87                "\t--split-method=<string>  : name of the splitting library (metis/scotch), default is metis\n"
88 #endif
89                "\t--create-boundary-faces  : creates boundary faces mesh in the output files\n"
90                "\t--create-joints          : creates joints in the output files\n"
91                "\t--dump-cpu-memory        : dumps passed CPU time and maximal increase of used memory\n"
92                );
93
94   if (argc<=1) help=1;
95   string value;
96   for (int i = 1; i < argc; i++)
97     {
98       if (strlen(argv[i]) < 3) 
99         {
100           cerr << "bad argument : "<< argv[i] << endl;
101           return 1;
102         }
103     
104       if (TestArg(argv[i],"--verbose",value)) 
105         {
106           MyGlobals::_Verbose=1;
107           if (value!="") MyGlobals::_Verbose = atoi(value.c_str());
108         }
109       else if (TestArg(argv[i],"--help",value)) help=1;
110 //      else if (TestArg(argv[i],"--test",value)) test=1;
111       else if (TestArg(argv[i],"--input-file",value)) input=value;
112       else if (TestArg(argv[i],"--output-file",value)) output=value;
113       else if (TestArg(argv[i],"--split-method",value)) library=value;
114       else if (TestArg(argv[i],"--ndomains",value)) ndomains=atoi(value.c_str());
115       else if (TestArg(argv[i],"--create-boundary-faces",value)) MyGlobals::_Create_Boundary_Faces=1;
116       else if (TestArg(argv[i],"--create-joints",value)) MyGlobals::_Create_Joints=1;
117       else if (TestArg(argv[i],"--dump-cpu-memory",value)) mesure_memory=true;
118       else 
119         {
120           cerr << "unknown argument : "<< argv[i] << endl;
121           return 1;
122         }
123     }
124
125   MyGlobals::_Is0verbose=MyGlobals::_Verbose;
126   
127 //no choice
128 #if defined(MED_ENABLE_METIS) && !defined(MED_ENABLE_SCOTCH)
129   library = "metis";
130 #endif
131 #if !defined(MED_ENABLE_METIS) && defined(MED_ENABLE_SCOTCH)
132   library = "scotch";
133 #endif
134 //user choice
135 #if defined(MED_ENABLE_METIS) && defined(MED_ENABLE_SCOTCH)
136   if ((library!="metis") && (library!="scotch"))
137     {
138       cerr << "split-method only available : metis, scotch" << endl;
139       return 1;
140     }
141 #endif
142  
143   if (help==1)
144     {
145       cout<<desc<<"\n";
146       return 0;
147     }
148   
149   if (MyGlobals::_Is0verbose)
150     {
151       cout << "medpartitioner V1.0 :" << endl;
152       cout << "  input-file = " << input << endl;
153       cout << "  output-file = " << output << endl;
154       cout << "  split-method = " << library << endl;
155       cout << "  ndomains = " << ndomains << endl;
156       cout << "  create_boundary_faces = " << MyGlobals::_Create_Boundary_Faces << endl;
157       cout << "  create-joints = " << MyGlobals::_Create_Joints<< endl;
158       cout << "  dump-cpu-memory = " << mesure_memory<< endl;
159       cout << "  verbose = " << MyGlobals::_Verbose << endl;
160     }
161   //testing whether it is possible to write a file at the specified location
162   if (MyGlobals::_Rank==0)
163     {
164       string outputtest = output + ".testioms.";
165       ofstream testfile (outputtest.c_str());
166       if (testfile.fail())
167         { 
168           cerr << "output-file directory does not exist or is in read-only access" << endl;
169           return 1;
170         }
171       //deletes test file
172       remove(outputtest.c_str());
173     }
174   
175   // Beginning of the computation
176
177   // Loading the mesh collection
178   if (MyGlobals::_Is0verbose) cout << "Reading input files "<<endl;
179   
180   try
181     {
182       /*MEDPARTITIONER::ParaDomainSelector parallelizer(mesure_memory);
183       MEDPARTITIONER::MeshCollection collection(input,parallelizer);
184       MEDPARTITIONER::ParallelTopology* aPT = (MEDPARTITIONER::ParallelTopology*) collection.getTopology();
185       aPT->setGlobalNumerotationDefault(collection.getParaDomainSelector());
186       //int nbfiles=MyGlobals::_fileMedNames->size(); //nb domains
187       //to have unique valid fields names/pointers/descriptions for partitionning
188       collection.prepareFieldDescriptions();
189       //int nbfields=collection.getFieldDescriptions().size(); //on all domains
190       //cout<<ReprVectorOfString(collection.getFieldDescriptions());
191     
192       if (MyGlobals::_Is0verbose)
193         {
194           cout<<"fileNames :"<<endl
195               <<ReprVectorOfString(MyGlobals::_File_Names);
196           cout<<"fieldDescriptions :"<<endl
197               <<ReprFieldDescriptions(collection.getFieldDescriptions()," "); //cvwat07
198           cout<<"familyInfo :\n"
199               <<ReprMapOfStringInt(collection.getFamilyInfo())<<endl;
200           cout<<"groupInfo :\n"
201               <<ReprMapOfStringVectorOfString(collection.getGroupInfo())<<endl;
202         }*/
203       MEDPARTITIONER::ParaDomainSelector parallelizer(mesure_memory);
204       MEDPARTITIONER::MeshCollection collection(input,parallelizer);
205       MEDPARTITIONER::ParallelTopology* aPT = (MEDPARTITIONER::ParallelTopology*) collection.getTopology();
206       aPT->setGlobalNumerotationDefault(collection.getParaDomainSelector());
207       //to have unique valid fields names/pointers/descriptions for partitionning
208       collection.prepareFieldDescriptions();
209       
210       //MEDPARTITIONER::MeshCollection collection(input);
211
212       //Creating the graph and partitioning it
213       if (MyGlobals::_Is0verbose) cout << "Computing partition with " << library << endl;
214   
215       auto_ptr< MEDPARTITIONER::Topology > new_topo;
216       if (library == "metis")
217         new_topo.reset( collection.createPartition(ndomains,MEDPARTITIONER::Graph::METIS));
218       else
219         new_topo.reset( collection.createPartition(ndomains,MEDPARTITIONER::Graph::SCOTCH));
220       parallelizer.evaluateMemory();
221   
222       //Creating a new mesh collection from the partitioning
223       if (MyGlobals::_Is0verbose)  cout << "Creating new meshes"<< endl;
224       MEDPARTITIONER::MeshCollection new_collection(collection,new_topo.get(),split_family,empty_groups);
225   
226       if (filter_face) new_collection.filterFaceOnCell();
227     
228       //to get infos on all procs
229     
230       //see meshName
231       vector<string> finalInformations;
232       vector<string> r1,r2;
233       //r1=AllgathervVectorOfString(MyGlobals::_General_Informations);
234       r1=MyGlobals::_General_Informations;
235       //if (MyGlobals::_Is0verbose>1000) cout << "generalInformations : \n"<<ReprVectorOfString(r1);
236       r2=SelectTagsInVectorOfString(r1,"ioldDomain=");
237       r2=SelectTagsInVectorOfString(r2,"meshName=");
238       if (r2.size()==(collection.getMesh()).size())
239         {
240           for (std::size_t i=0; i<r2.size(); i++)
241             r2[i]=EraseTagSerialized(r2[i],"ioldDomain=");
242           r2=DeleteDuplicatesInVectorOfString(r2);
243           if (r2.size()==1)
244             {
245               string finalMesh="finalMeshName="+ExtractFromDescription(r2[0], "meshName=");
246               finalInformations.push_back(SerializeFromString(finalMesh));
247             }
248         }
249       if (finalInformations.size()==0)
250         {
251           if (MyGlobals::_Rank==0)
252             cerr<<"Problem on final meshName : set at 'Merge'"<<endl;
253           finalInformations.push_back(SerializeFromString("finalMeshName=Merge"));
254         }
255     
256       //see field info nbComponents & componentInfo (if fields present)
257       r2=SelectTagsInVectorOfString(r1,"fieldName=");
258       r2=SelectTagsInVectorOfString(r2,"nbComponents=");
259       //may be yes? or not?
260       for (std::size_t i=0; i<r2.size(); i++)
261         r2[i]=EraseTagSerialized(r2[i],"ioldFieldDouble=");
262       r2=DeleteDuplicatesInVectorOfString(r2);
263       for (std::size_t i=0; i<r2.size(); i++)
264         finalInformations.push_back(r2[i]);
265     
266       MyGlobals::_General_Informations=finalInformations;
267       if (MyGlobals::_Is0verbose) 
268         cout << "generalInformations : \n"<<ReprVectorOfString(finalInformations);
269     
270       //new_collection.setSubdomainBoundaryCreates(create_boundary_faces);
271       if (MyGlobals::_Is0verbose) cout << "Writing "<<ndomains<<" output files "<<output<<"xx.med"<<" and "<<output<<".xml"<<endl;
272       new_collection.write(output);
273   
274       /*if ( mesure_memory )
275         if ( parallelizer.isOnDifferentHosts() || MyGlobals::_Rank==0 )
276           {
277             cout << "Elapsed time = " << parallelizer.getPassedTime()
278                  << ", max memory usage = " << parallelizer.evaluateMemory() << " KB"
279                  << endl;
280           }*/
281       
282       if (MyGlobals::_Is0verbose>0) cout<<"OK END"<< endl;
283       return 0;
284     }
285   catch(const char *mess)
286     {
287       cerr<<mess<<endl;
288       fflush(stderr);
289       return 1;
290     }
291   catch(INTERP_KERNEL::Exception& e)
292     {
293       cerr<<"INTERP_KERNEL_Exception : "<<e.what()<<endl;
294       fflush(stderr);
295       return 1;
296     }
297   catch(std::exception& e)
298     {
299       cerr<<"std_Exception : "<<e.what()<<endl;
300       fflush(stderr);
301       return 1;
302     }
303   catch(...)
304     {
305       cerr<<"an unknown type exception error has occurred"<<endl;
306       fflush(stderr);
307       return 1;
308     }
309 #endif
310 }