1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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
27 #include "MEDSPLITTER_MESHCollection.hxx"
28 #include "MEDSPLITTER_Topology.hxx"
29 #include "MEDSPLITTER_ParaDomainSelector.hxx"
31 #include "MEDMEM_STRING.hxx"
37 #ifdef BOOST_PROGRAM_OPTIONS_LIB
38 #include <boost/program_options.hpp>
39 namespace po=boost::program_options;
46 int main(int argc, char** argv)
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;
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;
71 #ifdef BOOST_PROGRAM_OPTIONS_LIB
73 // Use boost::program_options for command-line options parsing
75 po::options_description desc("Available 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)")
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");
96 po::store(po::parse_command_line(argc,argv,desc),vm);
105 if (!vm.count("ndomains"))
107 cout << "ndomains must be specified !"<<endl;
111 ndomains = vm["ndomains"].as<int>();
112 if (!vm.count("input-file") || !vm.count("output-file"))
114 cout << "input-file and output-file names must be specified"<<endl;
118 // if (!vm.count("distributed") && !vm.count("meshname") )
120 // cout << "MEDSPLITTER : for a serial MED file, mesh name must be selected with --meshname=..."<<endl;
124 input = vm["input-file"].as<string>();
125 output = vm["output-file"].as<string>();
127 // if (vm.count("mesh-only"))
130 // if (vm.count("distributed"))
131 // is_sequential=false;
133 // if (is_sequential)
134 // meshname = vm["meshname"].as<string>();
136 if (vm.count("plain-master"))
137 xml_output_master=false;
139 if (vm.count("creates-boundary-faces"))
140 creates_boundary_faces=true;
142 if (vm.count("split-families"))
145 if (vm.count("empty-groups"))
148 if (vm.count("dump-cpu-memory"))
151 #else // BOOST_PROGRAM_OPTIONS_LIB
153 // Primitive parsing of command-line options
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"
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"
175 cout << desc.c_str() << endl;
179 for (int i = 1; i < argc; i++) {
180 if (strlen(argv[i]) < 3) {
181 cout << desc.c_str() << endl;
185 /* if (strncmp(argv[i],"--m",3) == 0) {
186 if (strcmp(argv[i],"--mesh-only") == 0) {
188 cout << "\tmesh-only = " << mesh_only << endl; // tmp
190 else if (strlen(argv[i]) > 11) { // "--meshname="
191 meshname = (argv[i] + 11);
192 cout << "\tmeshname = " << meshname << endl; // tmp
195 else if (strncmp(argv[i],"--d",3) == 0) {
196 is_sequential = false;
197 cout << "\tis_sequential = " << is_sequential << endl; // tmp
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
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
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
217 else if (strncmp(argv[i],"--f",3) == 0) { //"--family-splitting"
219 cout << "\tfamily-splitting true" << endl; // tmp
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
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
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
235 else if (strncmp(argv[i],"--e",3) == 0) { // "--empty-groups"
237 cout << "\tempty_groups = true" << endl; // tmp
239 else if (strncmp(argv[i],"--d",3) == 0) { // "--dump-cpu-memory"
240 mesure_memory = true;
241 cout << "\tdump-cpu-memory = true" << endl; // tmp
244 cout << desc.c_str() << endl;
249 // if (is_sequential && meshname.empty()) {
250 // cout << "Mesh name must be given for sequential(not distributed) input file." << endl;
251 // cout << desc << endl;
255 #endif // BOOST_PROGRAM_OPTIONS_LIB
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());
263 cout << "MEDSPLITTER : output-file directory does not exist or is in read-only access" << endl;
267 remove(outputtest.c_str());
269 // Beginning of the computation
271 MPI_Init(&argc,&argv);
274 // Loading the mesh collection
275 cout << "MEDSPLITTER - reading input files "<<endl;
276 MEDSPLITTER::ParaDomainSelector parallelizer(mesure_memory);
277 MEDSPLITTER::MESHCollection collection(input,parallelizer);
279 // Creating the graph and partitioning it
280 cout << "MEDSPLITTER - computing partition "<<endl;
281 #ifdef MED_ENABLE_PARMETIS
282 #ifndef ENABLE_PTSCOTCH
288 cout << "\tsplit-method = " << library << endl; // tmp
290 auto_ptr< MEDSPLITTER::Topology > new_topo;
291 if (library == "metis")
292 new_topo.reset( collection.createPartition(ndomains,MEDSPLITTER::Graph::METIS));
294 new_topo.reset( collection.createPartition(ndomains,MEDSPLITTER::Graph::SCOTCH));
295 parallelizer.evaluateMemory();
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();
302 if (!xml_output_master)
303 new_collection.setDriverType(MEDSPLITTER::MedAscii);
305 new_collection.setSubdomainBoundaryCreates(creates_boundary_faces);
307 cout << "MEDSPLITTER - writing output files "<<endl;
308 new_collection.write(output);
311 if ( parallelizer.isOnDifferentHosts() || parallelizer.rank()==0 )
313 MEDMEM::STRING text("proc ");
314 text << parallelizer.rank() << ": elapsed time = " << parallelizer.getPassedTime()
315 << ", max memory usage = " << parallelizer.evaluateMemory() << " KB";
316 cout << text << endl;
318 // Casting the fields on the new collection
320 // new_collection.castAllFields(*collection);