libMesh
splitter.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2017 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // Read in a Mesh file and write out partitionings of it that are suitable
20 // for reading into a DistributedMesh
21 #include "libmesh/libmesh.h"
22 #include "libmesh/replicated_mesh.h"
23 #include "libmesh/checkpoint_io.h"
24 #include "libmesh/metis_partitioner.h"
25 #include "libmesh/getpot.h"
26 
27 using namespace libMesh;
28 
29 // From: http://stackoverflow.com/a/6417908/2042320
30 std::string remove_extension (const std::string & filename)
31 {
32  size_t lastdot = filename.find_last_of(".");
33 
34  if (lastdot == std::string::npos)
35  return filename;
36 
37  return filename.substr(0, lastdot);
38 }
39 
40 int main (int argc, char ** argv)
41 {
42  LibMeshInit init (argc, argv);
43 
44  if (libMesh::on_command_line("--help") || argc < 3)
45  {
46  libMesh::out << "Example: " << argv[0] << " --mesh=filename.e --n-procs='4 8 16' [--dry-run] [--ascii]\n\n"
47  << "--mesh Full name of the mesh file to read in. \n"
48  << "--n-procs Vector of number of processors.\n"
49  << "--dry-run Only test the partitioning, don't write any files.\n"
50  << "--ascii Write ASCII cpa files rather than binary cpr files.\n"
51  << std::endl;
52 
53  return 0;
54  }
55 
56  std::string filename = libMesh::command_line_value("--mesh", std::string());
57 
58  std::vector<int> all_n_procs;
59  libMesh::command_line_vector("--n-procs", all_n_procs);
60 
61  Parallel::Communicator & comm = init.comm();
62 
63  ReplicatedMesh mesh(init.comm());
64 
65  libMesh::out << "Reading " << filename << std::endl;
66 
67  mesh.read(filename);
68 
69  MetisPartitioner partitioner;
70 
71  for (std::size_t i = 0; i < all_n_procs.size(); i++)
72  {
73  processor_id_type n_procs = all_n_procs[i];
74 
75  libMesh::out << "\nWriting out files for " << n_procs << " processors...\n\n" << std::endl;
76 
77  // Reset the partitioning each time after the first one
78  if (i > 0)
79  {
80  libMesh::out << "Resetting Partitioning" << std::endl;
81  partitioner.partition(mesh, 1);
82  }
83 
84  libMesh::out << "Partitioning" << std::endl;
85 
86  // Partition it to how we want it
87  partitioner.partition(mesh, n_procs);
88 
89  mesh.print_info();
90 
91  // When running in parallel each processor will write out a portion of the mesh files
92 
93  processor_id_type num_chunks = n_procs / comm.size();
94  processor_id_type remaining_chunks = n_procs % comm.size();
95 
96  processor_id_type my_num_chunks = num_chunks;
97 
98  processor_id_type my_first_chunk = 0;
99 
100  processor_id_type rank = comm.rank();
101  processor_id_type comm_size = comm.size();
102 
103  if (n_procs >= comm_size) // More partitions than processors
104  {
105  if (remaining_chunks) // Means that it doesn't split up evenly
106  {
107  // Spread the remainder over the first few processors
108  // There will be "remaining_chunks" number of processors that will each
109  // get one extra chunk
110  if (rank < remaining_chunks)
111  {
112  my_num_chunks += 1;
113  my_first_chunk = my_num_chunks * rank;
114  }
115  else // The processors beyond the "first" set that don't get an extra chunk
116  {
117  // The number of chunks dealt with by the first processors
118  // num chunks // num procs
119  processor_id_type num_chunks_in_first_procs = (my_num_chunks + 1) * remaining_chunks;
120  processor_id_type distance_to_first_procs = rank - remaining_chunks;
121 
122  my_first_chunk = num_chunks_in_first_procs + (my_num_chunks * distance_to_first_procs);
123  }
124  }
125  else // Splits evenly
126  my_first_chunk = my_num_chunks * rank;
127  }
128  else // More processors than partitions
129  {
130  if (rank < n_procs)
131  {
132  my_num_chunks = 1;
133  my_first_chunk = rank;
134  }
135  else
136  {
137  my_num_chunks = 0;
139  }
140  }
141 
142  if (!libMesh::on_command_line("--dry-run"))
143  {
144  libMesh::out << "Writing " << my_num_chunks << " Files" << std::endl;
145 
146  const bool binary = !libMesh::on_command_line("--ascii");
147 
148  CheckpointIO cpr(mesh);
149  cpr.current_processor_ids().clear();
150  for (unsigned int i = my_first_chunk; i < my_first_chunk + my_num_chunks; i++)
151  cpr.current_processor_ids().push_back(i);
152  cpr.current_n_processors() = n_procs;
153  cpr.parallel() = true;
154  cpr.binary() = binary;
155  std::ostringstream outputname;
156  outputname << remove_extension(filename) << '.' << n_procs
157  << (binary ? ".cpr" : ".cpa");
158  cpr.write(outputname.str());
159  }
160  }
161 
162  return 0;
163 }
The CheckpointIO class can be used to write simplified restart files that can be used to restart simu...
Definition: checkpoint_io.h:50
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
Encapsulates the MPI_Comm object.
Definition: parallel.h:657
int main(int argc, char **argv)
Definition: splitter.C:40
std::string remove_extension(const std::string &filename)
Definition: splitter.C:30
unsigned int size() const
Definition: parallel.h:726
const std::vector< processor_id_type > & current_processor_ids() const
Get/Set the processor id or processor ids to use.
MeshBase & mesh
uint8_t processor_id_type
Definition: id_types.h:99
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:62
The MetisPartitioner uses the Metis graph partitioner to partition the elements.
The libMesh namespace provides an interface to certain functionality in the library.
long double max(long double a, double b)
bool parallel() const
Get/Set the flag indicating if we should read/write binary.
T command_line_value(const std::string &, T)
Definition: libmesh.C:932
void init(triangulateio &t)
Initializes the fields of t to NULL/0 as necessary.
const processor_id_type & current_n_processors() const
Get/Set the n_processors to use.
const Parallel::Communicator & comm() const
Definition: libmesh.h:81
void command_line_vector(const std::string &, std::vector< T > &)
Definition: libmesh.C:978
bool on_command_line(const std::string &arg)
Definition: libmesh.C:921
virtual void partition(MeshBase &mesh, const unsigned int n)
Partitions the MeshBase into n parts by setting processor_id() on Nodes and Elems.
Definition: partitioner.C:49
OStreamProxy out
unsigned int rank() const
Definition: parallel.h:724
virtual void read(const std::string &name, void *mesh_data=libmesh_nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false)=0
Interfaces for reading/writing a mesh to/from a file.
virtual void write(const std::string &) libmesh_override
This method implements writing a mesh to a specified file.
Definition: checkpoint_io.C:83
bool binary() const
Get/Set the flag indicating if we should read/write binary.
Definition: checkpoint_io.h:99
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the mesh.
Definition: mesh_base.C:448