COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-mesh-parallel-overlap.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2013 von Karman Institute for Fluid Dynamics, Belgium
2 //
3 // This software is distributed under the terms of the
4 // GNU Lesser General Public License version 3 (LGPLv3).
5 // See doc/lgpl.txt and doc/gpl.txt for the license text.
6 
7 #define BOOST_TEST_DYN_LINK
8 #define BOOST_TEST_MODULE "Test module for parallel fields"
9 
10 #include <iomanip>
11 #include <set>
12 
13 #include <boost/test/unit_test.hpp>
14 
15 #include "common/Log.hpp"
16 #include "common/OptionList.hpp"
17 #include "common/Core.hpp"
18 #include "common/Environment.hpp"
19 
20 #include "common/Foreach.hpp"
21 #include "common/OSystem.hpp"
22 #include "common/OSystemLayer.hpp"
23 
26 #include "common/PE/Buffer.hpp"
27 #include "common/PE/debug.hpp"
28 
29 #include "math/Consts.hpp"
30 
31 #include "mesh/Mesh.hpp"
32 #include "mesh/Cells.hpp"
33 #include "mesh/Faces.hpp"
34 #include "mesh/Elements.hpp"
35 #include "mesh/Region.hpp"
36 #include "mesh/Dictionary.hpp"
37 #include "mesh/Field.hpp"
38 #include "mesh/MeshReader.hpp"
39 #include "mesh/MeshElements.hpp"
40 #include "mesh/MeshWriter.hpp"
41 #include "mesh/MeshGenerator.hpp"
42 #include "mesh/MeshPartitioner.hpp"
43 #include "mesh/MeshTransformer.hpp"
44 #include "mesh/MeshAdaptor.hpp"
45 #include "mesh/CellFaces.hpp"
46 #include "mesh/Space.hpp"
47 
48 using namespace boost;
49 using namespace cf3;
50 using namespace cf3::mesh;
51 using namespace cf3::common;
52 using namespace cf3::common::PE;
53 using namespace cf3::math::Consts;
54 
55 template <typename T>
56 std::ostream& operator<< (std::ostream& out , const std::vector<T>& v)
57 {
58  for (Uint i=0; i<v.size()-1; ++i)
59  out << v[i] << " ";
60  if (v.size())
61  out << v.back();
62  return out;
63 }
64 
65 void my_all_to_all(const std::vector<PE::Buffer>& send, PE::Buffer& recv)
66 {
67  std::vector<int> send_strides(send.size());
68  std::vector<int> send_displs(send.size());
69  for (Uint i=0; i<send.size(); ++i)
70  send_strides[i] = send[i].size();
71 
72  if (send.size()) send_displs[0] = 0;
73  for (Uint i=1; i<send.size(); ++i)
74  send_displs[i] = send_displs[i-1] + send_strides[i-1];
75 
76  PE::Buffer send_linear;
77 
78  send_linear.reserve(send_displs.back()+send_strides.back());
79  for (Uint i=0; i<send.size(); ++i)
80  send_linear.pack(send[i].begin(),send[i].size());
81 
82  std::vector<int> recv_strides(PE::Comm::instance().size());
83  std::vector<int> recv_displs(PE::Comm::instance().size());
84  PE::Comm::instance().all_to_all(send_strides,recv_strides);
85  if (recv_displs.size()) recv_displs[0] = 0;
86  for (Uint i=1; i<PE::Comm::instance().size(); ++i)
87  recv_displs[i] = recv_displs[i-1] + recv_strides[i-1];
88  recv.reset();
89  recv.resize(recv_displs.back()+recv_strides.back());
90  MPI_CHECK_RESULT(MPI_Alltoallv, ((void*)send_linear.begin(), &send_strides[0], &send_displs[0], MPI_PACKED, (void*)recv.begin(), &recv_strides[0], &recv_displs[0], MPI_PACKED, PE::Comm::instance().communicator()));
91 }
92 
94 
95 void my_all_to_all(const PE::Buffer& send, std::vector<int>& send_strides, PE::Buffer& recv, std::vector<int>& recv_strides)
96 {
97  std::vector<int> send_displs(send_strides.size());
98  if (send_strides.size()) send_displs[0] = 0;
99  for (Uint i=1; i<send_strides.size(); ++i)
100  send_displs[i] = send_displs[i-1] + send_strides[i-1];
101 
102  recv_strides.resize(PE::Comm::instance().size());
103  std::vector<int> recv_displs(PE::Comm::instance().size());
104  PE::Comm::instance().all_to_all(send_strides,recv_strides);
105  if (recv_displs.size()) recv_displs[0] = 0;
106  for (Uint i=1; i<PE::Comm::instance().size(); ++i)
107  recv_displs[i] = recv_displs[i-1] + recv_strides[i-1];
108  recv.reset();
109  recv.resize(recv_displs.back()+recv_strides.back());
110  MPI_CHECK_RESULT(MPI_Alltoallv, ((void*)send.begin(), &send_strides[0], &send_displs[0], MPI_PACKED, (void*)recv.begin(), &recv_strides[0], &recv_displs[0], MPI_PACKED, PE::Comm::instance().communicator()));
111 }
112 
113 
115 {
116  bool sane = true;
117  std::map<Uint,Uint> glb_node_2_loc_node;
118  std::map<Uint,Uint>::iterator glb_node_not_found = glb_node_2_loc_node.end();
119  for (Uint n=0; n<nodes.size(); ++n)
120  {
121  if ( glb_node_2_loc_node.find(nodes.glb_idx()[n]) == glb_node_not_found )
122  {
123  glb_node_2_loc_node[nodes.glb_idx()[n]] = n;
124  }
125  else
126  {
127  std::cout << PERank << "glb idx " << nodes.glb_idx()[n] << " already exists... ("<<n<< "<-->"<<glb_node_2_loc_node[nodes.glb_idx()[n]] << ")" << std::endl;
128  sane = false;
129  }
130  }
131  return sane;
132 }
133 
135 {
136  bool sane = true;
137 
138  boost_foreach( Entities& entities, mesh.topology().elements_range())
139  {
140  Uint max_node_idx = entities.geometry_fields().size();
141 
142  for (Uint e=0; e<entities.size(); ++e)
143  {
144  boost_foreach(Uint node, entities.geometry_space().connectivity()[e])
145  {
146  if (node >=max_node_idx)
147  {
148  std::cout << PERank << "element " << e << " has node out of range : " << node << " >= " << max_node_idx << std::endl;
149  sane = false;
150  }
151  }
152  }
153  }
154 
155  return sane;
156 }
157 
158 
160 {
161  bool sane = true;
162  std::map<Uint,Uint> glb_elem_2_loc_elem;
163  std::map<Uint,Uint>::iterator glb_elem_not_found = glb_elem_2_loc_elem.end();
164  for (Uint e=0; e<entities.size(); ++e)
165  {
166  if ( glb_elem_2_loc_elem.find(entities.glb_idx()[e]) == glb_elem_not_found )
167  {
168  glb_elem_2_loc_elem[entities.glb_idx()[e]] = e;
169  }
170  else
171  {
172  std::cout << PERank << "glb elem idx " << entities.glb_idx()[e] << " already exists... ("<<e<< "<-->"<<glb_elem_2_loc_elem[entities.glb_idx()[e]] << ")" << std::endl;
173  sane = false;
174  }
175  }
176  return sane;
177 }
178 
179 
181 
183 {
186  {
187  // uncomment if you want to use arguments to the test executable
188  m_argc = boost::unit_test::framework::master_test_suite().argc;
189  m_argv = boost::unit_test::framework::master_test_suite().argv;
190 
191  }
192 
195  {
196  }
197 
199 
200  int m_argc;
201  char** m_argv;
202 };
203 
205 
206 BOOST_FIXTURE_TEST_SUITE( ParallelOverlapTests_TestSuite, ParallelOverlapTests_Fixture )
207 
208 
211 {
212  Core::instance().initiate(m_argc,m_argv);
213  PE::Comm::instance().init(m_argc,m_argv);
214 }
215 
217 
218 BOOST_AUTO_TEST_CASE( parallelize_and_synchronize )
219 {
220  CFinfo << "ParallelOverlap_test" << CFendl;
221  Core::instance().environment().options().set("log_level",(Uint)DEBUG);
222 
223 
224  // Create or read the mesh
225 
226 #define GEN
227 
228 #ifdef GEN
229  boost::shared_ptr< MeshGenerator > meshgenerator = build_component_abstract_type<MeshGenerator>("cf3.mesh.SimpleMeshGenerator","1Dgenerator");
230  meshgenerator->options().set("mesh",URI("//rect"));
231  std::vector<Uint> nb_cells(2);
232  std::vector<Real> lengths(2);
233  nb_cells[0] = 50;
234  nb_cells[1] = 50;
235  lengths[0] = nb_cells[0];
236  lengths[1] = nb_cells[1];
237  meshgenerator->options().set("nb_cells",nb_cells);
238  meshgenerator->options().set("lengths",lengths);
239  meshgenerator->options().set("bdry",true);
240  Mesh& mesh = meshgenerator->generate();
241 #endif
242 
243 #ifdef NEU
244  boost::shared_ptr< MeshReader > meshreader =
245  build_component_abstract_type<MeshReader>("cf3.mesh.neu.Reader","meshreader");
246 // meshreader->options().set("read_boundaries",false);
247  boost::shared_ptr< Mesh > mesh_ptr = meshreader->create_mesh_from("rotation-tg-p1.neu");
248 // Handle< Mesh > mesh_ptr = meshreader->create_mesh_from("../../resources/quadtriag.neu");
249  Mesh& mesh = *mesh_ptr;
250  Core::instance().root().add_component(mesh_ptr);
251 #endif
252 
253 #ifdef GMSH
254  boost::shared_ptr< MeshReader > meshreader =
255  build_component_abstract_type<MeshReader>("cf3.mesh.gmsh.Reader","meshreader");
256  boost::shared_ptr< Mesh > mesh_ptr = meshreader->create_mesh_from("../../resources/sinusbump-tg-p1.msh");
257 // Handle< Mesh > mesh_ptr = meshreader->create_mesh_from("../../resources/quadtriag.msh");
258 // Handle< Mesh > mesh_ptr = meshreader->create_mesh_from("../../resources/rectangle-tg-p1.msh");
259  Mesh& mesh = *mesh_ptr;
260  Core::instance().root().add_component(mesh_ptr);
261 #endif
262 
263  Dictionary& nodes = mesh.geometry_fields();
264 
265  boost::shared_ptr< MeshWriter > tec_writer =
266  build_component_abstract_type<MeshWriter>("cf3.mesh.tecplot.Writer","tec_writer");
267 
268  boost::shared_ptr< MeshWriter > gmsh_writer =
269  build_component_abstract_type<MeshWriter>("cf3.mesh.gmsh.Writer","gmsh_writer");
270 
271 
272  tec_writer->write_from_to(mesh,"parallel_overlap_before"+tec_writer->get_extensions()[0]);
273  CFinfo << "parallel_overlap_before_P*"+tec_writer->get_extensions()[0]+" written" << CFendl;
274 
275  gmsh_writer->write_from_to(mesh,"parallel_overlap_before"+gmsh_writer->get_extensions()[0]);
276  CFinfo << "parallel_overlap_before_P*"+gmsh_writer->get_extensions()[0]+" written" << CFendl;
277 
278  CFinfo << "Global Numbering..." << CFendl;
279 // build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.LoadBalance","load_balancer")->transform(mesh);
280  boost::shared_ptr< MeshTransformer > glb_numbering = build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.GlobalNumbering","glb_numbering");
281 // glb_numbering->options().set("debug",true);
282  glb_numbering->transform(mesh);
283  CFinfo << "Global Numbering... done" << CFendl;
284 
285  CFinfo << "Global Connectivity..." << CFendl;
286  build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.GlobalConnectivity","glb_node_elem_connectivity")->transform(mesh);
287  CFinfo << "Global Connectivity... done" << CFendl;
288 
289  CFinfo << "Partitioning..." << CFendl;
290  boost::shared_ptr< MeshPartitioner > partitioner_ptr = boost::dynamic_pointer_cast<MeshPartitioner>(build_component_abstract_type<MeshTransformer>("cf3.mesh.zoltan.Partitioner","partitioner"));
291  MeshPartitioner& p = *partitioner_ptr;
292  p.options().set("graph_package", std::string("PHG"));
293  p.initialize(mesh);
294  p.partition_graph();
295 // p.show_changes();
296  CFinfo << "Partitioning... done" << CFendl;
297 
298 
299  Field& glb_node = mesh.geometry_fields().create_field("glb_node");
300  for (Uint node=0; node<mesh.geometry_fields().size(); ++node)
301  glb_node[node][0] = mesh.geometry_fields().glb_idx()[node];
302 
303  // Create a field with glb element numbers
304  Dictionary& elems_P0 = mesh.create_discontinuous_space("elems_P0","cf3.mesh.LagrangeP0");
305  Field& glb_elem = elems_P0.create_field("glb_elem");
306  Field& elem_rank = elems_P0.create_field("elem_rank");
307 
308  BOOST_CHECK_EQUAL(mesh.dictionaries().size(),2u);
309  BOOST_CHECK_EQUAL(mesh.dictionaries()[1]->name() , mesh::Tags::geometry());
310 
311  BOOST_CHECK_EQUAL(mesh.elements().size(),5u);
312 
313  boost_foreach(const Handle<Space>& space, elems_P0.spaces())
314  {
315  for (Uint elem=0; elem<space->size(); ++elem)
316  {
317  const Uint field_idx = space->connectivity()[elem][0];
318  glb_elem[field_idx][0] = space->support().glb_idx()[elem]+1;
319  elem_rank[field_idx][0] = space->support().rank()[elem];
320  }
321  }
322 
323  CFinfo << glb_node.size() << CFendl;
324  CFinfo << glb_elem.size() << CFendl;
325  CFinfo << mesh.topology().recursive_elements_count(true) << CFendl;
326 
327  // Create a field with glb element numbers
328  Dictionary& continuous_P2 = mesh.create_discontinuous_space("continuous_P2","cf3.mesh.LagrangeP2");
329  const Field& P2coords = continuous_P2.coordinates();
330 
331  // NOTE that in this case migration happens AFTER fields and other spaces have been
332  // created
333  CFinfo << "Migration..." << CFendl;
334  p.migrate();
335  CFinfo << "Migration... done" << CFendl;
336 
337  MeshAdaptor mesh_adaptor(mesh);
338  mesh_adaptor.prepare();
339  mesh_adaptor.grow_overlap();
340  mesh_adaptor.finish();
341 
342  CFinfo << glb_node.size() << CFendl;
343  CFinfo << glb_elem.size() << CFendl;
344  CFinfo << mesh.topology().recursive_elements_count(true) << CFendl;
345 
346 
347 BOOST_CHECK(true);
348 
349  std::vector<URI> fields_to_output;
350  fields_to_output.push_back(glb_node.uri());
351  fields_to_output.push_back(glb_elem.uri());
352  fields_to_output.push_back(elem_rank.uri());
353  fields_to_output.push_back(P2coords.uri());
354 BOOST_CHECK(true);
355  tec_writer->options().set("fields",fields_to_output);
356  tec_writer->options().set("enable_overlap",true);
357  tec_writer->options().set("mesh",mesh.handle<Mesh>());
358  tec_writer->options().set("file",URI("parallel_overlap"+tec_writer->get_extensions()[0]));
359  tec_writer->execute();
360  CFinfo << "parallel_overlap_P*"+tec_writer->get_extensions()[0]+" written" << CFendl;
361 BOOST_CHECK(true);
362  gmsh_writer->options().set("fields",fields_to_output);
363  gmsh_writer->options().set("enable_overlap",true);
364  gmsh_writer->options().set("mesh",mesh.handle<Mesh>());
365  gmsh_writer->options().set("file",URI("parallel_overlap"+gmsh_writer->get_extensions()[0]));
366  gmsh_writer->execute();
367  CFinfo << "parallel_overlap_P*"+gmsh_writer->get_extensions()[0]+" written" << CFendl;
368 }
369 
370 BOOST_AUTO_TEST_CASE( finalize_mpi )
371 {
372  PE::Comm::instance().finalize();
373  Core::instance().terminate();
374 }
375 
377 
378 BOOST_AUTO_TEST_SUITE_END()
379 
380 
void reserve(const Uint size)
reserve the buffer to fit memory "size". The buffer gets allocated bigger than necessary in order to ...
Definition: Buffer.hpp:266
#define CFinfo
these are always defined
Definition: Log.hpp:104
Field & create_field(const std::string &name, const Uint cols)
Create a new field in this group.
Definition: Dictionary.cpp:178
virtual void partition_graph()=0
Uint recursive_elements_count(bool include_ghost_elems) const
Definition: Region.cpp:107
void my_all_to_all(const std::vector< PE::Buffer > &send, PE::Buffer &recv)
Safe pointer to an object. This is the supported method for referring to components.
Definition: Handle.hpp:39
Dictionary & create_discontinuous_space(const std::string &space_name, const std::string &space_lib_name, const std::vector< Handle< Entities > > &entities)
Definition: Mesh.cpp:316
const std::vector< Handle< Entities > > & elements() const
Definition: Mesh.hpp:70
external boost library namespace
Space & geometry_space() const
Definition: Entities.hpp:94
Parallel Communication Pattern. This class provides functionality to collect communication. For efficiency it works such a way that you submit your request via the constructor or the add/remove/move magic triangle and then call setup to modify the commpattern. The data needed to be kept synchronous can be registered via the insert function. The word node here means any kind of "point of storage", in this context it is not directly related with the computational mesh.
ConstElementsRange elements_range() const
Definition: Region.cpp:142
~ParallelOverlapTests_Fixture()
common tear-down for each test case
URI uri() const
Construct the full path.
Definition: Component.cpp:248
#define boost_foreach
lowercase version of BOOST_FOREACH
Definition: Foreach.hpp:16
const Field & coordinates() const
Definition: Dictionary.cpp:481
common::List< Uint > & rank()
Definition: Entities.hpp:71
Entities & support() const
Access the geometric support.
Definition: Space.hpp:102
#define CFendl
Definition: Log.hpp:109
Real e()
Definition of the Unit charge [C].
Definition: Consts.hpp:30
boost::proto::terminal< SFOp< NodesOp > >::type const nodes
Dictionary & geometry_fields() const
Const access to the coordinates.
Definition: Entities.hpp:63
Static functions for mathematical constants.
Definition: Consts.hpp:25
const std::vector< Handle< Space > > & spaces() const
Definition: Dictionary.cpp:360
Handle< Component const > root() const
Definition: Component.cpp:266
void reset()
reset the buffer, without resizing
Definition: Buffer.hpp:291
Uint size() const
Definition: Table.hpp:127
Uint size() const
return the number of elements
Definition: Entities.cpp:161
Buffer that can hold multiple data types, useful for MPI communication.
Definition: Buffer.hpp:34
void resize(const Uint size)
resize the buffer to fit memory "size". The buffer gets resized bigger than necessary in order to red...
Definition: Buffer.hpp:283
common::List< Uint > & glb_idx()
Mutable access to the list of nodes.
Definition: Entities.hpp:66
Basic Classes for Mesh applications used by COOLFluiD.
void pack(const T *data, const Uint data_size)
Pack data in the buffer. The data must be POD (plain old data).
Definition: Buffer.hpp:311
Class to adapt the mesh.
Definition: MeshAdaptor.hpp:45
Top-level namespace for coolfluid.
Definition: Action.cpp:18
common::List< Uint > & glb_idx()
Return the global index of every field row.
Definition: Dictionary.hpp:84
bool check_nodes_sanity(Dictionary &nodes)
void finish()
Apply the changes the mesh adaptor for changes and fix inconsistent state.
int m_argc
possibly common functions used on the tests below
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
void migrate()
Migrate the elements and nodes to corresponding processors.
Classes offering a MPI interface for COOLFluiD.
Definition: all_gather.hpp:39
void prepare()
Prepare the mesh adaptor for changes.
bool check_elements_sanity(Entities &entities)
const iterator begin() const
begin iterator
Definition: Buffer.hpp:107
Region & topology() const
Definition: Mesh.hpp:51
Handle< Component > handle()
Get a handle to the component.
Definition: Component.hpp:179
BOOST_AUTO_TEST_CASE(init_mpi)
#define MPI_CHECK_RESULT(MPIFunc, Args)
Macro for checking return values of any mpi calls and throws exception on error.
Definition: types.hpp:20
OptionList & options()
Definition: Component.cpp:856
bool check_element_nodes_sanity(Mesh &mesh)
void grow_overlap()
Create an additional cell-layer of overlap between pid's.
Dictionary & geometry_fields() const
Definition: Mesh.cpp:339
#define PERank
Definition: debug.hpp:36
ParallelOverlapTests_Fixture()
common setup for each test case
void set(const std::string &pname, const boost::any &val)
Definition: OptionList.cpp:132
MPI communication buffer for mixed data types.
Uint size() const
Number of rows of contained fields.
Definition: Dictionary.cpp:99
Uint size() const
The number of elements defined in this space.
Definition: Space.cpp:95
Most basic kernel library.
Definition: Action.cpp:19
Connectivity & connectivity()
connectivity table to dictionary entries
Definition: Space.hpp:110
const std::vector< Handle< Dictionary > > & dictionaries() const
Definition: Mesh.hpp:71
Send comments to:
COOLFluiD Web Admin