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