COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-parallel-field.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 <boost/test/unit_test.hpp>
12 
13 #include "coolfluid-packages.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/debug.hpp"
27 
28 #include "mesh/Mesh.hpp"
29 #include "mesh/Elements.hpp"
30 #include "mesh/Region.hpp"
31 #include "mesh/Dictionary.hpp"
32 #include "mesh/Field.hpp"
33 #include "mesh/MeshReader.hpp"
34 #include "mesh/MeshWriter.hpp"
35 #include "mesh/MeshGenerator.hpp"
36 #include "mesh/MeshPartitioner.hpp"
37 #include "mesh/MeshTransformer.hpp"
38 #include "mesh/Space.hpp"
39 #include "mesh/Interpolator.hpp"
40 
41 #ifdef GNUPLOT_FOUND
42  #include "Tools/Gnuplot/Gnuplot.hpp"
43 #endif
44 
45 using namespace boost;
46 using namespace cf3;
47 using namespace cf3::mesh;
48 using namespace cf3::common;
49 using namespace cf3::common::PE;
50 
52 
54 {
57  {
58  // uncomment if you want to use arguments to the test executable
59  m_argc = boost::unit_test::framework::master_test_suite().argc;
60  m_argv = boost::unit_test::framework::master_test_suite().argv;
61 
62  }
63 
66  {
67 
68  }
69 
71 
72  int m_argc;
73  char** m_argv;
74 };
75 
76 
78 
79 BOOST_FIXTURE_TEST_SUITE( ParallelFieldsTests_TestSuite, ParallelFieldsTests_Fixture )
80 
81 
84 {
85  Core::instance().initiate(m_argc,m_argv);
86  PE::Comm::instance().init(m_argc,m_argv);
87 
88 }
90 
91 BOOST_AUTO_TEST_CASE( parallelize_and_synchronize )
92 {
93  CFinfo << "ParallelFields_test" << CFendl;
94  Core::instance().environment().options().set("log_level",(Uint)DEBUG);
95 
96  // Create or read the mesh
97 
98 #define GMSH
99 
100 #ifdef GEN
101  boost::shared_ptr< MeshGenerator > meshgenerator = build_component_abstract_type<MeshGenerator>("cf3.mesh.SimpleMeshGenerator","1Dgenerator");
102  meshgenerator->options().set("mesh",URI("//rect"));
103  std::vector<Uint> nb_cells(2);
104  std::vector<Real> lengths(2);
105  nb_cells[0] = 10;
106  nb_cells[1] = 5;
107  lengths[0] = nb_cells[0];
108  lengths[1] = nb_cells[1];
109  meshgenerator->options().set("nb_cells",nb_cells);
110  meshgenerator->options().set("lengths",lengths);
111  meshgenerator->options().set("bdry",false);
112  Mesh& mesh = meshgenerator->generate();
113 #endif
114 
115 #ifdef NEU
116  boost::shared_ptr< MeshReader > meshreader =
117  build_component_abstract_type<MeshReader>("cf3.mesh.neu.Reader","meshreader");
118  Handle< Mesh > mesh_ptr = meshreader->create_mesh_from("rotation-tg-p1.neu");
119  Mesh& mesh = *mesh_ptr;
120  Core::instance().root().add_component(mesh_ptr):
121 #endif
122 
123 #ifdef GMSH
124  boost::shared_ptr< MeshReader > meshreader =
125  build_component_abstract_type<MeshReader>("cf3.mesh.gmsh.Reader","meshreader");
126  Handle< Mesh > mesh_ptr = Core::instance().root().create_component<Mesh>("mesh");
127  meshreader->options().set("mesh",mesh_ptr);
128  meshreader->options().set("file",URI("../../resources/rectangle-tg-p1.msh"));
129  meshreader->execute();
130  Mesh& mesh = *mesh_ptr;
131 
132  boost::shared_ptr< MeshWriter > mesh_writer =
133  build_component_abstract_type<MeshWriter>("cf3.mesh.gmsh.Writer","msh_writer");
134 
135 // mesh_writer->options().set("fields",fields);
136  mesh_writer->options().set("file",URI("parallel_fields.msh"));
137  mesh_writer->options().set("mesh",mesh.handle<Mesh>());
138  mesh_writer->execute();
139 
140 #endif
141 
142 build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.LoadBalance","load_balancer")->transform(mesh);
143 
144  // create a field and assign it to the comm pattern
145 
146  Field& field = mesh.geometry_fields().create_field("node_rank");
147 
148  BOOST_CHECK_NO_THROW( field.parallelize() );
149 
150  for (Uint n=0; n<field.size(); ++n)
151  for (Uint j=0; j<field.row_size(); ++j)
152  field[n][j] = PE::Comm::instance().rank();
153 
154  // Synchronize
155 
156  // comm_pattern.synchronize(); // via the comm_pattern
157 
158  field.synchronize(); // via the field
159 
160 
161  BOOST_CHECK(true); // Tadaa
162 
163  // Create a field with glb element numbers
164  Dictionary& elems_P0 = mesh.create_discontinuous_space("elems_P0","cf3.mesh.LagrangeP0");
165  Field& glb_elem_idx = elems_P0.create_field("glb_elem");
166  Field& elem_rank = elems_P0.create_field("elem_rank");
167 
168 
169  Dictionary& nodes_P1 = mesh.create_continuous_space("nodes_P1","cf3.mesh.LagrangeP2");
170  Field& nodes_P1_node_rank = nodes_P1.create_field("node_rank");
171  nodes_P1_node_rank.parallelize();
172  for (Uint n=0; n<nodes_P1_node_rank.size(); ++n)
173  nodes_P1_node_rank[n][0] = nodes_P1.rank()[n];
174 
175  boost_foreach(const Handle<Entities>& elements_handle, elems_P0.entities_range())
176  {
177  const Entities& elements = *elements_handle;
178  const Space& space = elems_P0.space(elements);
179  for (Uint elem=0; elem<elements.size(); ++elem)
180  {
181  Uint field_idx = space.connectivity()[elem][0];
182  glb_elem_idx[field_idx][0] = elems_P0.glb_idx()[field_idx];
183  elem_rank[field_idx][0] = elems_P0.rank()[field_idx];
184  }
185  }
186 
187  // Create a field with glb node numbers
188  Field& glb_node_idx = mesh.geometry_fields().create_field("glb_node_idx");
189 
190  List<Uint>& glb_idx = mesh.geometry_fields().glb_idx();
191  {
192  for (Uint n=0; n<glb_node_idx.size(); ++n)
193  glb_node_idx[n][0] = glb_idx[n];
194  }
195 
196  // Create a field with glb node numbers
197  Field& P1_node_rank = mesh.geometry_fields().create_field("P1_node_rank");
198 
199  Handle<AInterpolator> interpolator (mesh.create_component("interpolator","cf3.mesh.SpaceInterpolator"));
200  interpolator->interpolate(nodes_P1_node_rank,P1_node_rank);
201 
202  // Write the mesh with the fields
203 
204  std::vector<URI> fields;
205  fields.push_back(field.uri());
206  fields.push_back(P1_node_rank.uri());
207  fields.push_back(glb_elem_idx.uri());
208  fields.push_back(elem_rank.uri());
209  fields.push_back(glb_node_idx.uri());
210 
211  boost::shared_ptr< MeshWriter > tec_writer =
212  build_component_abstract_type<MeshWriter>("cf3.mesh.tecplot.Writer","tec_writer");
213 
214  tec_writer->options().set("fields",fields);
215  tec_writer->options().set("cell_centred",true);
216  tec_writer->options().set("file",URI("parallel_fields.plt"));
217  tec_writer->options().set("mesh",mesh.handle<Mesh>());
218  tec_writer->execute();
219 
220  CFinfo << "parallel_fields_P*.plt written" << CFendl;
221 
222  boost::shared_ptr< MeshWriter > msh_writer =
223  build_component_abstract_type<MeshWriter>("cf3.mesh.gmsh.Writer","msh_writer");
224 
225  msh_writer->options().set("fields",fields);
226  msh_writer->options().set("file",URI("parallel_fields.msh"));
227  msh_writer->options().set("mesh",mesh.handle<Mesh>());
228  msh_writer->execute();
229 
230  CFinfo << "parallel_fields_P*.msh written" << CFendl;
231 
232 
233 }
234 
236 
238 {
239  CFinfo << "ParallelFields_test" << CFendl;
240  Core::instance().environment().options().set("log_level",(Uint)DEBUG);
241 
242  boost::shared_ptr< MeshGenerator > meshgenerator = build_component_abstract_type<MeshGenerator>("cf3.mesh.SimpleMeshGenerator","1Dgenerator");
243  meshgenerator->options().set("mesh",URI("//line"));
244  meshgenerator->options().set("nb_cells",std::vector<Uint>(1,10));
245  meshgenerator->options().set("lengths",std::vector<Real>(1,10.));
246  meshgenerator->options().set("bdry",false);
247  Mesh& mesh = meshgenerator->generate();
248 
249  build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.LoadBalance","load_balancer")->transform(mesh);
250 
251  // create a field and assign it to the comm pattern
252 
253  Field& node_rank = mesh.geometry_fields().create_field("node_rank");
254  node_rank.parallelize();
255 
256 
257  CFinfo << "Node test" << CFendl;
258  for (Uint n=0; n<node_rank.size(); ++n)
259  for (Uint j=0; j<node_rank.row_size(); ++j)
260  node_rank[n][j] = PE::Comm::instance().rank();
261  node_rank.synchronize();
262 
263  if (0)
264  {
265  if (Comm::instance().size() == 2)
266  {
267  if (Comm::instance().rank() == 0)
268  {
269  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[0][XX] , 0.);
270  BOOST_CHECK_EQUAL( node_rank[0][0] , 0. );
271  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[1][XX] , 1.);
272  BOOST_CHECK_EQUAL( node_rank[1][0] , 0. );
273  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[2][XX] , 2.);
274  BOOST_CHECK_EQUAL( node_rank[2][0] , 0. );
275  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[3][XX] , 3.);
276  BOOST_CHECK_EQUAL( node_rank[3][0] , 0. );
277  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[4][XX] , 4.);
278  BOOST_CHECK_EQUAL( node_rank[4][0] , 0. );
279 
280  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[5][XX] , 5.);
281  BOOST_CHECK_EQUAL( node_rank[5][0] , 1. );
282  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[6][XX] , 6.);
283  BOOST_CHECK_EQUAL( node_rank[6][0] , 1. );
284  }
285  else if (Comm::instance().rank() == 1)
286  {
287  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[0][XX] , 5.);
288  BOOST_CHECK_EQUAL( node_rank[0][0] , 1. );
289  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[1][XX] , 6.);
290  BOOST_CHECK_EQUAL( node_rank[1][0] , 1. );
291  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[2][XX] , 7.);
292  BOOST_CHECK_EQUAL( node_rank[2][0] , 1. );
293  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[3][XX] , 8.);
294  BOOST_CHECK_EQUAL( node_rank[3][0] , 1. );
295  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[4][XX] , 9.);
296  BOOST_CHECK_EQUAL( node_rank[4][0] , 1. );
297  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[5][XX] , 10.);
298  BOOST_CHECK_EQUAL( node_rank[5][0] , 1. );
299 
300  BOOST_CHECK_EQUAL( mesh.geometry_fields().coordinates()[6][XX] , 4.);
301  BOOST_CHECK_EQUAL( node_rank[6][0] , 0. );
302  }
303  }
304  else
305  CFwarn << "Checks only performed when run with 2 procs" << CFendl;
306  }
307 
308 
309  Dictionary& elems = mesh.create_discontinuous_space("elems_P0","cf3.mesh.LagrangeP0");
310  Field& elem_rank = elems.create_field("elem_rank");
311  elem_rank.parallelize();
312 
313  CFinfo << "Elem test" << CFendl;
314  for (Uint n=0; n<elem_rank.size(); ++n)
315  for (Uint j=0; j<elem_rank.row_size(); ++j)
316  elem_rank[n][j] = PE::Comm::instance().rank();
317  elem_rank.synchronize();
318 
319  if (0)
320  {
321  if (Comm::instance().size() == 2)
322  {
323  if (Comm::instance().rank() == 0)
324  {
325  BOOST_CHECK_EQUAL( elems.coordinates()[0][XX] , 0.5 );
326  BOOST_CHECK_EQUAL( elem_rank[0][0] , 0 );
327  BOOST_CHECK_EQUAL( elems.coordinates()[1][XX] , 1.5 );
328  BOOST_CHECK_EQUAL( elem_rank[1][0] , 0 );
329  BOOST_CHECK_EQUAL( elems.coordinates()[2][XX] , 2.5 );
330  BOOST_CHECK_EQUAL( elem_rank[2][0] , 0 );
331  BOOST_CHECK_EQUAL( elems.coordinates()[3][XX] , 3.5 );
332  BOOST_CHECK_EQUAL( elem_rank[3][0] , 0 );
333  BOOST_CHECK_EQUAL( elems.coordinates()[4][XX] , 4.5 );
334  BOOST_CHECK_EQUAL( elem_rank[4][0] , 0 );
335  BOOST_CHECK_EQUAL( elems.coordinates()[5][XX] , 5.5 );
336  BOOST_CHECK_EQUAL( elem_rank[5][0] , 1 );
337  }
338  else if (Comm::instance().rank() == 1)
339  {
340  BOOST_CHECK_EQUAL( elems.coordinates()[0][XX] , 5.5 );
341  BOOST_CHECK_EQUAL( elem_rank[0][0] , 1 );
342  BOOST_CHECK_EQUAL( elems.coordinates()[1][XX] , 6.5 );
343  BOOST_CHECK_EQUAL( elem_rank[1][0] , 1 );
344  BOOST_CHECK_EQUAL( elems.coordinates()[2][XX] , 7.5 );
345  BOOST_CHECK_EQUAL( elem_rank[2][0] , 1 );
346  BOOST_CHECK_EQUAL( elems.coordinates()[3][XX] , 8.5 );
347  BOOST_CHECK_EQUAL( elem_rank[3][0] , 1 );
348  BOOST_CHECK_EQUAL( elems.coordinates()[4][XX] , 9.5 );
349  BOOST_CHECK_EQUAL( elem_rank[4][0] , 1 );
350  BOOST_CHECK_EQUAL( elems.coordinates()[5][XX] , 4.5 );
351  BOOST_CHECK_EQUAL( elem_rank[5][0] , 0 );
352  }
353  }
354  }
355 
356 #ifdef GNUPLOT_FOUND
357 // Gnuplot gp(std::string(GNUPLOT_COMMAND)+std::string(" -persist"));
358  Gnuplot gp(std::string(GNUPLOT_COMMAND));
359  gp << "set terminal png" << std::endl;
360  gp << "set output 'ranks_P"<<Comm::instance().rank()<<".png'" << std::endl;
361  gp << "set yrange [-0.5:1.5]" << std::endl;
362  gp << "set title 'Rank "<<Comm::instance().rank()<<"'" << std::endl;
363  gp << "plot ";
364  gp << "'-' with points title 'node-rank'" << ", ";
365  gp << "'-' with points title 'elem-rank'" << "\n";
366  gp.send( mesh.geometry_fields().coordinates().array() , node_rank.array() );
367  gp.send( elems.coordinates().array() , elem_rank.array() );
368 
369 // Following works too, if coordinates need to be in sequence
370 // std::map<Real,Real> nodes_xy;
371 // for (Uint i=0; i<node_rank.size(); ++i)
372 // nodes_xy[mesh.geometry_fields().coordinates()[i][XX]] = node_rank[i][0];
373 
374 // std::map<Real,Real> elems_xy;
375 // for (Uint i=0; i<elem_rank.size(); ++i)
376 // elems_xy[elems.coordinates()[i][XX]] = elem_rank[i][0];
377 
378 // gp.send(nodes_xy);
379 // gp.send(elems_xy);
380 #endif
381 }
382 
384 
385 BOOST_AUTO_TEST_CASE( finalize_mpi )
386 {
387  PE::Comm::instance().finalize();
388 
389  Core::instance().terminate();
390 }
391 
393 
394 BOOST_AUTO_TEST_SUITE_END()
395 
396 
#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
const std::vector< Handle< Entities > > & entities_range() const
Definition: Dictionary.cpp:353
ArrayT & array()
Definition: Table.hpp:92
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
external boost library namespace
int m_argc
possibly common functions used on the tests below
Dictionary & create_continuous_space(const std::string &space_name, const std::string &space_lib_name, const std::vector< Handle< Entities > > &entities)
Definition: Mesh.cpp:269
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.
ParallelFieldsTests_Fixture()
common setup for each test case
URI uri() const
Construct the full path.
Definition: Component.cpp:248
Gnuplot & send(T p, T last)
Definition: Gnuplot.hpp:143
common::List< Uint > & rank()
Return the rank of every field row.
Definition: Dictionary.hpp:90
#define boost_foreach
lowercase version of BOOST_FOREACH
Definition: Foreach.hpp:16
const Field & coordinates() const
Definition: Dictionary.cpp:481
#define CFendl
Definition: Log.hpp:109
Handle< Component const > root() const
Definition: Component.cpp:266
Definition: Defs.hpp:17
Uint size() const
Definition: Table.hpp:127
Uint size() const
return the number of elements
Definition: Entities.cpp:161
common::PE::CommPattern & parallelize()
Definition: Field.cpp:149
Basic Classes for Mesh applications used by COOLFluiD.
void synchronize()
Definition: Field.cpp:162
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
#define CFwarn
Definition: Log.hpp:106
~ParallelFieldsTests_Fixture()
common tear-down for each test case
const Space & space(const Entities &entities) const
Return the space of given entities.
Definition: Dictionary.cpp:161
Uint row_size(Uint i=0) const
Definition: Table.hpp:133
std::vector< URI > fields
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
Classes offering a MPI interface for COOLFluiD.
Definition: all_gather.hpp:39
common::List< Uint > & rank() const
Definition: Field.cpp:221
Handle< Component > handle()
Get a handle to the component.
Definition: Component.hpp:179
BOOST_AUTO_TEST_CASE(init_mpi)
OptionList & options()
Definition: Component.cpp:856
Dictionary & geometry_fields() const
Definition: Mesh.cpp:339
Space component class.
Definition: Space.hpp:59
void set(const std::string &pname, const boost::any &val)
Definition: OptionList.cpp:132
Handle< Component > create_component(const std::string &name, const std::string &builder)
Build a (sub)component of this component using the extended type_name of the component.
Definition: Component.cpp:568
Most basic kernel library.
Definition: Action.cpp:19
Connectivity & connectivity()
connectivity table to dictionary entries
Definition: Space.hpp:110
Send comments to:
COOLFluiD Web Admin