Salome HOME
Merge from V6_main 01/04/2013
[modules/med.git] / src / MEDSPLITTER / medsplitter_para.cxx
1 // Copyright (C) 2007-2013  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.
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 //  MED medsplitter : tool to split n MED files into p separate 
21 //                    MED files with a partitioning specified 
22 //                    by an external tool
23 //  File   : medsplitter.cxx
24 //  Module : MED
25 //
26
27 #include "MEDSPLITTER_MESHCollection.hxx"
28 #include "MEDSPLITTER_Topology.hxx"
29 #include "MEDSPLITTER_ParaDomainSelector.hxx"
30
31 #include "MEDMEM_STRING.hxx"
32
33 #include <mpi.h>
34
35 #include <fstream>
36
37 #ifdef BOOST_PROGRAM_OPTIONS_LIB
38 #include <boost/program_options.hpp>
39 namespace po=boost::program_options;
40 #endif
41
42 using namespace std;
43
44
45
46 int main(int argc, char** argv)
47 {
48 #ifndef MED_ENABLE_PARMETIS
49 #ifndef ENABLE_PTSCOTCH
50   cout << "Sorry, no one split method is available. Please, compile with ParMETIS or PT-SCOTCH."<<endl;
51   return 1;
52 #endif
53 #endif
54
55   // Defining options
56   // by parsing the command line
57   //bool mesh_only = false;
58   //bool is_sequential = true;
59   bool xml_output_master=true;
60   bool creates_boundary_faces=false;  
61   bool split_family=false;
62   bool empty_groups=false;
63   bool mesure_memory=false;
64
65   string input;
66   string output;
67   string meshname;
68   string library;
69   int ndomains;
70
71 #ifdef BOOST_PROGRAM_OPTIONS_LIB
72
73   // Use boost::program_options for command-line options parsing
74
75   po::options_description desc("Available options");
76   desc.add_options()
77     ("help","produces this help message")
78     //("mesh-only","prevents the splitter from creating the fields contained in the original file(s)")
79     //("distributed","specifies that the input file is distributed")
80     ("input-file",po::value<string>(),"name of the input MED file")
81     ("output-file",po::value<string>(),"name of the resulting file")
82     //("meshname",po::value<string>(),"name of the input mesh")
83 #ifdef MED_ENABLE_PARMETIS
84 #ifdef ENABLE_PTSCOTCH
85     ("split-method",po::value<string>(&library)->default_value("metis"),"name of the splitting library (metis,scotch)")
86 #endif
87 #endif
88     ("ndomains",po::value<int>(&ndomains)->default_value(1),"number of subdomains in the output file")
89     ("plain-master","creates a plain masterfile instead of an XML file")
90     ("creates-boundary-faces","creates the necessary faces so that faces joints are created in the output files")
91     ("family-splitting","preserves the family names instead of focusing on the groups")
92     ("empty-groups","creates empty groups in zones that do not contain a group from the original domain")
93     ("dump-cpu-memory","dumps passed CPU time and maximal increase of used memory");
94
95   po::variables_map vm;
96   po::store(po::parse_command_line(argc,argv,desc),vm);
97   po::notify(vm);
98
99   if (vm.count("help"))
100   {
101     cout<<desc<<"\n";
102     return 1;
103   }
104
105   if (!vm.count("ndomains"))
106   {
107     cout << "ndomains must be specified !"<<endl;
108     return 1;
109   }
110
111   ndomains = vm["ndomains"].as<int>();
112   if (!vm.count("input-file") || !vm.count("output-file"))
113   {
114     cout << "input-file and output-file names must be specified"<<endl;
115     return 1;
116   }
117
118 //   if (!vm.count("distributed") && !vm.count("meshname") )
119 //   {
120 //     cout << "MEDSPLITTER : for a serial MED file, mesh name must be selected with --meshname=..."<<endl;
121 //     return 1;
122 //   }
123
124   input = vm["input-file"].as<string>();
125   output = vm["output-file"].as<string>();
126
127 //   if (vm.count("mesh-only"))
128 //     mesh_only=true;
129
130 //   if (vm.count("distributed"))
131 //     is_sequential=false;
132
133 //   if (is_sequential)
134 //     meshname = vm["meshname"].as<string>();
135
136   if (vm.count("plain-master"))
137     xml_output_master=false;
138
139   if (vm.count("creates-boundary-faces"))
140     creates_boundary_faces=true;
141
142   if (vm.count("split-families"))
143     split_family=true;
144
145   if (vm.count("empty-groups"))
146     empty_groups=true;
147
148   if (vm.count("dump-cpu-memory"))
149     mesure_memory=true;
150
151 #else // BOOST_PROGRAM_OPTIONS_LIB
152
153   // Primitive parsing of command-line options
154
155   string desc ("Available options:\n"
156                "\t--help                  : produces this help message\n"
157                //"\t--mesh-only            : do not create the fields contained in the original file(s)\n"
158                //"\t--distributed          : specifies that the input file is distributed\n"
159                "\t--input-file=<string>   : name of the input MED file\n"
160                "\t--output-file=<string>  : name of the resulting file\n"
161                //"\t--meshname=<string>    : name of the input mesh (not used with --distributed option)\n"
162                "\t--ndomains=<number>     : number of subdomains in the output file, default is 1\n"
163 #ifdef MED_ENABLE_PARMETIS
164 #ifdef ENABLE_PTSCOTCH
165                "\t--split-method=<string> : name of the splitting library (metis/scotch), default is metis\n"
166 #endif
167 #endif
168                "\t--plain-master          : creates a plain masterfile instead of an XML file\n"
169                "\t--creates-boundary-faces: creates the necessary faces so that faces joints are created in the output files\n"
170                "\t--family-splitting      : preserves the family names instead of focusing on the groups\n"
171                "\t--dump-cpu-memory       : dumps passed CPU time and maximal increase of used memory\n"
172                );
173
174   if (argc < 4) {
175     cout << desc.c_str() << endl;
176     return 1;
177   }
178
179   for (int i = 1; i < argc; i++) {
180     if (strlen(argv[i]) < 3) {
181       cout << desc.c_str() << endl;
182       return 1;
183     }
184
185 /*    if (strncmp(argv[i],"--m",3) == 0) {
186       if (strcmp(argv[i],"--mesh-only") == 0) {
187         mesh_only = true;
188         cout << "\tmesh-only = " << mesh_only << endl; // tmp
189       }
190       else if (strlen(argv[i]) > 11) { // "--meshname="
191         meshname = (argv[i] + 11);
192         cout << "\tmeshname = " << meshname << endl; // tmp
193       }
194     }
195     else if (strncmp(argv[i],"--d",3) == 0) {
196       is_sequential = false;
197       cout << "\tis_sequential = " << is_sequential << endl; // tmp
198     }
199     else */if (strncmp(argv[i],"--i",3) == 0) {
200       if (strlen(argv[i]) > 13) { // "--input-file="
201         input = (argv[i] + 13);
202         cout << "\tinput-file = " << input << endl; // tmp
203       }
204     }
205     else if (strncmp(argv[i],"--o",3) == 0) {
206       if (strlen(argv[i]) > 14) { // "--output-file="
207         output = (argv[i] + 14);
208         cout << "\toutput-file = " << output << endl; // tmp
209       }
210     }
211     else if (strncmp(argv[i],"--s",3) == 0) {
212       if (strlen(argv[i]) > 15) { // "--split-method="
213         library = (argv[i] + 15);
214         cout << "\tsplit-method = " << library << endl; // tmp
215       }
216     }
217     else if (strncmp(argv[i],"--f",3) == 0) { //"--family-splitting"
218       split_family=true;
219       cout << "\tfamily-splitting true" << endl; // tmp
220     }
221     else if (strncmp(argv[i],"--n",3) == 0) {
222       if (strlen(argv[i]) > 11) { // "--ndomains="
223         ndomains = atoi(argv[i] + 11);
224         cout << "\tndomains = " << ndomains << endl; // tmp
225       }
226     }
227     else if (strncmp(argv[i],"--p",3) == 0) { // "--plain-master"
228       xml_output_master = false;
229       cout << "\txml_output_master = " << xml_output_master << endl; // tmp
230     }
231     else if (strncmp(argv[i],"--c",3) == 0) { // "--creates-boundary-faces"
232       creates_boundary_faces = true;
233       cout << "\tcreates_boundary_faces = " << creates_boundary_faces << endl; // tmp
234     }
235     else if (strncmp(argv[i],"--e",3) == 0) { // "--empty-groups"
236       empty_groups = true;
237       cout << "\tempty_groups = true" << endl; // tmp
238     }
239     else if (strncmp(argv[i],"--d",3) == 0) { // "--dump-cpu-memory"
240       mesure_memory = true;
241       cout << "\tdump-cpu-memory = true" << endl; // tmp
242     }
243     else {
244       cout << desc.c_str() << endl;
245       return 1;
246     }
247   }
248
249 //   if (is_sequential && meshname.empty()) {
250 //     cout << "Mesh name must be given for sequential(not distributed) input file." << endl;
251 //     cout << desc << endl;
252 //     return 1;
253 //   }
254
255 #endif // BOOST_PROGRAM_OPTIONS_LIB
256
257
258   //testing whether it is possible to write a file at the specified location
259   string outputtest = output + ".testioms.";
260   ofstream testfile (outputtest.c_str());
261   if (testfile.fail())
262   { 
263     cout << "MEDSPLITTER : output-file directory does not exist or is in read-only access" << endl;
264     return 1;
265   }
266   //deletes test file
267   remove(outputtest.c_str());
268
269   // Beginning of the computation
270
271   MPI_Init(&argc,&argv);
272   
273
274   // Loading the mesh collection
275   cout << "MEDSPLITTER - reading input files "<<endl;
276   MEDSPLITTER::ParaDomainSelector parallelizer(mesure_memory);
277   MEDSPLITTER::MESHCollection collection(input,parallelizer);
278
279   // Creating the graph and partitioning it   
280   cout << "MEDSPLITTER - computing partition "<<endl;
281 #ifdef MED_ENABLE_PARMETIS
282 #ifndef ENABLE_PTSCOTCH
283   library = "metis";
284 #endif
285 #else
286   library = "scotch";
287 #endif
288   cout << "\tsplit-method = " << library << endl; // tmp
289
290   auto_ptr< MEDSPLITTER::Topology > new_topo;
291   if (library == "metis")
292     new_topo.reset( collection.createPartition(ndomains,MEDSPLITTER::Graph::METIS));
293   else
294     new_topo.reset( collection.createPartition(ndomains,MEDSPLITTER::Graph::SCOTCH));
295   parallelizer.evaluateMemory();
296
297   // Creating a new mesh collection from the partitioning
298   cout << "MEDSPLITTER - creating new meshes"<<endl;
299   MEDSPLITTER::MESHCollection new_collection(collection,new_topo.get(),split_family,empty_groups);
300   parallelizer.evaluateMemory();
301
302   if (!xml_output_master)
303     new_collection.setDriverType(MEDSPLITTER::MedAscii);
304
305   new_collection.setSubdomainBoundaryCreates(creates_boundary_faces);
306
307   cout << "MEDSPLITTER - writing output files "<<endl;
308   new_collection.write(output);
309
310   if ( mesure_memory )
311     if ( parallelizer.isOnDifferentHosts() || parallelizer.rank()==0 )
312     {
313       MEDMEM::STRING text("proc ");
314       text << parallelizer.rank() << ": elapsed time = " << parallelizer.getPassedTime()
315            << ", max memory usage = " << parallelizer.evaluateMemory() << " KB";
316       cout << text << endl;
317     }
318   // Casting the fields on the new collection
319 //   if (!mesh_only)
320 //     new_collection.castAllFields(*collection);
321
322   MPI_Finalize();
323
324   return 0;
325 }