COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
MeshInterpolator.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2011 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 #include <set>
8 
9 #include <vtkCellType.h>
10 #include <vtkIdList.h>
11 #include <vtkGenericCell.h>
12 #include <vtkPoints.h>
13 #include <vtkSmartPointer.h>
14 #include <vtkUnstructuredGrid.h>
15 #include <vtkCell.h>
16 #include <vtkDoubleArray.h>
17 #include <vtkPointData.h>
18 #include <vtkPolyData.h>
19 #include <vtkProbeFilter.h>
20 
21 #include "common/Builder.hpp"
22 
24 #include "common/Foreach.hpp"
25 
26 #include "common/PE/Comm.hpp"
27 #include "common/OptionList.hpp"
28 #include "common/PropertyList.hpp"
29 
31 
33 #include "mesh/Faces.hpp"
34 #include "mesh/Region.hpp"
35 #include "mesh/Space.hpp"
36 #include "mesh/Mesh.hpp"
37 #include "mesh/MeshAdaptor.hpp"
38 #include "mesh/MeshTransformer.hpp"
39 #include "mesh/Field.hpp"
40 #include "mesh/Functions.hpp"
41 #include "mesh/Connectivity.hpp"
42 #include "mesh/ElementData.hpp"
43 #include "mesh/BoundingBox.hpp"
44 
45 #include "vtk/MeshInterpolator.hpp"
46 
48 
49 using namespace cf3;
50 
52 
53 namespace cf3 {
54 namespace vtk {
55 
57 
59 
61 
62 MeshInterpolator::MeshInterpolator ( const std::string& name ) : common::Action ( name )
63 {
64  options().add("source_mesh", Handle<mesh::Mesh>())
65  .pretty_name("Source Mesh")
66  .description("Mesh to interpolate from. Warning: this is modified in parallel to make all elements known on each rank.")
67  .mark_basic();
68 
69  options().add("target_mesh", Handle<mesh::Mesh>())
70  .pretty_name("Target Mesh")
71  .description("Mesh to interpolate to")
72  .mark_basic();
73 
74  create_static_component<mesh::BoundingBox>("BoundingBox");
75 }
76 
78 {
79 }
80 
82 {
83 
86 
87  if(is_null(source_mesh))
88  throw common::SetupError(FromHere(), "MeshInterpolator source_mesh is not set");
89 
90  if(is_null(target_mesh))
91  throw common::SetupError(FromHere(), "MeshInterpolator target_mesh is not set");
92 
93  if(source_mesh->dimension() != 3)
94  throw common::SetupError(FromHere(), "VTK MeshInterpolator only works in 3D");
95 
96  Handle<mesh::Dictionary> source_dict(source_mesh->geometry_fields().handle());
97  Handle<mesh::Dictionary> target_dict(target_mesh->geometry_fields().handle());
98 
100  const Uint nb_procs = comm.size();
101  const Uint my_rank = comm.rank();
102 
103  const Uint nb_target_points = target_dict->size();
104 
105  Handle<mesh::BoundingBox> bounding_box(get_child("BoundingBox"));
106  cf3_assert(is_not_null(bounding_box));
107 
108  const Uint dim = source_mesh->dimension();
109 
110  if(comm.size() > 1)
111  {
112  bounding_box->build(*target_mesh);
113  std::vector<Real> my_bbox(dim*2);
114  for(Uint i = 0; i != dim; ++i)
115  {
116  my_bbox[i] = bounding_box->min()[i];
117  my_bbox[dim+i] = bounding_box->max()[i];
118  }
119 
120  std::vector< std::vector<Real> > recv_bbox;
121  comm.all_gather(my_bbox, recv_bbox);
122  const Uint nb_ranks = comm.size();
123  cf3_assert(recv_bbox.size() == nb_ranks);
124  std::vector<RealVector> box_mins(nb_ranks);
125  std::vector<RealVector> box_maxs(nb_ranks);
126  for(Uint rank = 0; rank != nb_ranks; ++rank)
127  {
128  const std::vector<Real>& other_bbox = recv_bbox[rank];
129  const Eigen::Map<RealVector const> b_min(&other_bbox[0], dim);
130  const Eigen::Map<RealVector const> b_max(&other_bbox[dim], dim);
131  box_mins[rank] = b_min;
132  box_maxs[rank] = b_max;
133  }
134 
135  const mesh::Field& source_coords = source_dict->coordinates();
136 
137  mesh::MeshAdaptor adaptor(*source_mesh);
138  adaptor.prepare();
139  std::vector< std::vector< std::vector<Uint> > > elements_to_send(nb_procs, std::vector< std::vector<Uint> > (source_mesh->elements().size()));
140  BOOST_FOREACH(mesh::Elements& elements, common::find_components_recursively_with_filter<mesh::Elements>(source_mesh->topology(), mesh::IsElementsVolume()))
141  {
142  const mesh::Connectivity& conn = elements.geometry_space().connectivity();
143  const Uint nb_elems = elements.size();
144  for(Uint elem_idx = 0; elem_idx != nb_elems; ++elem_idx)
145  {
146  for(Uint rank = 0; rank != nb_ranks; ++rank)
147  {
148  if(rank == comm.rank())
149  continue;
150  BOOST_FOREACH(const Uint node_idx, conn[elem_idx])
151  {
152  const Eigen::Map<RealVector const> coord(&source_coords[node_idx][0], dim);
153  if((coord.array() <= box_maxs[rank].array()).all() && (coord.array() >= box_mins[rank].array()).all())
154  {
155  elements_to_send[rank][elements.entities_idx()].push_back(elem_idx);
156  break;
157  }
158  }
159  }
160  }
161  }
162 
163  std::vector< std::vector< std::vector<Uint> > > nodes_to_send;
164  adaptor.find_nodes_to_export(elements_to_send,nodes_to_send);
165 
166  std::vector< std::vector< std::vector<boost::uint64_t> > > imported_elements;
167  adaptor.send_elements(elements_to_send, imported_elements);
168 
169  adaptor.flush_elements();
170 
171  std::vector< std::vector< std::vector<boost::uint64_t> > > imported_nodes;
172  adaptor.send_nodes(nodes_to_send,imported_nodes);
173 
174  adaptor.flush_nodes();
175 
176  adaptor.finish();
177  }
178 
179  const Uint nb_source_points = source_dict->size();
180  const mesh::Field& source_coords = source_dict->coordinates();
181 
182  // Build the input mesh
183  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
184  points->Allocate(nb_source_points);
185  BOOST_FOREACH(const mesh::Field::ConstRow coord, source_coords.array())
186  {
187  points->InsertNextPoint(coord[XX], coord[YY], coord[ZZ]);
188  }
189 
190  vtkSmartPointer<vtkUnstructuredGrid> vtk_unstruc_grid = vtkSmartPointer<vtkUnstructuredGrid>::New();
191  vtk_unstruc_grid->SetPoints(points);
192 
193  Real nb_scalars = 0;
194  std::vector<mesh::Field*> source_fields, target_fields;
195  BOOST_FOREACH(const Handle<mesh::Field>& source_field, source_dict->fields())
196  {
197  if(source_field->has_tag(mesh::Tags::coordinates()))
198  continue;
199 
200  Handle<mesh::Field> target_field(target_dict->get_child(source_field->name()));
201  if(is_null(target_field))
202  {
203  target_field = target_dict->create_field(source_field->name(), source_field->descriptor().description()).handle<mesh::Field>();
204  BOOST_FOREACH(const std::string& tag, source_field->get_tags())
205  {
206  target_field->add_tag(tag);
207  }
208  }
209  nb_scalars += source_field->row_size();
210 
211  source_fields.push_back(source_field.get());
212  target_fields.push_back(target_field.get());
213  }
214 
215  vtkSmartPointer<vtkDoubleArray> source_data = vtkSmartPointer<vtkDoubleArray>::New();
216  source_data->SetNumberOfComponents(nb_scalars);
217  source_data->SetName("SourceData");
218  source_data->Allocate(nb_source_points);
219  std::vector<Real> field_values_row(nb_scalars);
220  for(Uint i = 0; i != nb_source_points; ++i)
221  {
222  int offset = 0;
223  BOOST_FOREACH(const mesh::Field* source_field, source_fields)
224  {
225  const mesh::Field::ConstRow fd_row = source_field->array()[i];
226  std::copy(fd_row.begin(), fd_row.end(), field_values_row.begin()+offset);
227  offset += source_field->row_size();
228  }
229  source_data->InsertNextTuple(&field_values_row[0]);
230  }
231  vtk_unstruc_grid->GetPointData()->SetScalars(source_data);
232 
233  BOOST_FOREACH(mesh::Elements& elems, common::find_components_recursively_with_filter<mesh::Elements>(*source_mesh, mesh::IsElementsVolume()))
234  {
235  int cell_type = 0;
236  mesh::GeoShape::Type shape = elems.element_type().shape();
237 
238  if(shape == mesh::GeoShape::TETRA)
239  cell_type = VTK_TETRA;
240  else if(shape == mesh::GeoShape::HEXA)
241  cell_type = VTK_HEXAHEDRON;
242  else if(shape == mesh::GeoShape::PRISM)
243  cell_type = VTK_WEDGE;
244  else
245  throw common::NotImplemented(FromHere(), "Cells of type " + elems.element_type().name() + " are not supported as interpolation source");
246 
247  const mesh::Connectivity& connectivity = elems.geometry_space().connectivity();
248  const Uint nb_elems = connectivity.size();
249  const Uint nb_elem_nodes = connectivity.row_size();
250  vtkSmartPointer<vtkIdList> id_list = vtkSmartPointer<vtkIdList>::New();
251  id_list->SetNumberOfIds(nb_elem_nodes);
252  for(Uint i = 0; i != nb_elems; ++i)
253  {
254  const mesh::Connectivity::ConstRow row = connectivity[i];
255  for(int j = 0; j != nb_elem_nodes; ++j)
256  id_list->SetId(j, row[j]);
257  vtk_unstruc_grid->InsertNextCell(cell_type, id_list);
258  }
259  }
260 
261  // Build the probing mesh
262  vtkSmartPointer<vtkPolyData> probe_poly = vtkSmartPointer<vtkPolyData>::New();
263  vtkSmartPointer<vtkPoints> probe_points = vtkSmartPointer<vtkPoints>::New();
264  probe_points->Allocate(nb_target_points);
265  BOOST_FOREACH(const mesh::Field::ConstRow coord, target_dict->coordinates().array())
266  {
267  probe_points->InsertNextPoint(coord[XX], coord[YY], coord[ZZ]);
268  }
269  probe_poly->SetPoints(probe_points);
270 
271  // Probe at the point locations of the probing mesh
272  vtkSmartPointer<vtkProbeFilter> prober = vtkSmartPointer<vtkProbeFilter>::New();
273  prober->SetInputData(probe_poly);
274  prober->SetSourceData(vtk_unstruc_grid);
275  prober->Update();
276 
277  if(is_null(prober->GetOutput()))
278  throw common::SetupError(FromHere(), "Mesh interpolation failed");
279 
280  vtkDataArray* interpolated_scalars = prober->GetOutput()->GetPointData()->GetScalars();
281  cf3_assert(is_not_null(interpolated_scalars));
282 
283  // Store the field data
284  for(Uint i = 0; i != nb_target_points; ++i)
285  {
286  int offset = 0;
287  interpolated_scalars->GetTuple(i, &field_values_row[0]);
288  BOOST_FOREACH(mesh::Field* target_field, target_fields)
289  {
290  mesh::Field::Row fd_row = target_field->array()[i];
291  std::copy(field_values_row.begin()+offset, field_values_row.begin()+offset+target_field->row_size(), fd_row.begin());
292  offset += target_field->row_size();
293  }
294  }
295 
296  BOOST_FOREACH(mesh::Field* target_field, target_fields)
297  {
298  target_field->parallelize();
299  target_field->synchronize();
300  }
301 }
302 
303 
305 
306 } // namespace vtk
307 } // namespace cf3
308 
const RealVector & min() const
minimum coordinates, defining one corner of the bounding box
Definition: BoundingBox.hpp:61
void build(const Region &region)
Build bounding box with a mesh.
Definition: BoundingBox.cpp:42
std::string name(ComponentWrapper &self)
bool is_null(T ptr)
predicate for comparison to nullptr
Definition: CF.hpp:151
ArrayT & array()
Definition: Table.hpp:92
const std::vector< Handle< Entities > > & elements() const
Definition: Mesh.hpp:70
Helper class to create the Builder and place it in the factory.
Definition: Builder.hpp:212
Space & geometry_space() const
Definition: Entities.hpp:94
Type
Enumeration of the Shapes recognized in CF.
Definition: GeoShape.hpp:27
void copy(const std::vector< Real > &vector, RealMatrix &realmatrix)
Copy std::vector to dynamic RealMatrix types.
const RealVector & max() const
maximum coordinates, defining one corner of the bounding box
Definition: BoundingBox.hpp:64
#define cf3_assert(a)
Definition: Assertions.hpp:93
ElementType & element_type() const
return the elementType
Definition: Entities.cpp:116
MeshInterpolator(const std::string &name)
const std::string & name() const
Access the name of the component.
Definition: Component.hpp:146
void flush_elements()
Apply all changes to elements.
Definition: Defs.hpp:17
Definition: Defs.hpp:17
Uint size() const
Definition: Table.hpp:127
Uint dimension() const
Definition: Mesh.hpp:86
virtual void execute()
execute the action
void flush_nodes()
Apply all changes to nodes.
Uint size() const
return the number of elements
Definition: Entities.cpp:161
common::PE::CommPattern & parallelize()
Definition: Field.cpp:149
GeoShape::Type shape() const
Definition: ElementType.hpp:64
void find_nodes_to_export(const std::vector< std::vector< std::vector< Uint > > > &exported_elements_loc_id, std::vector< std::vector< std::vector< Uint > > > &exported_nodes_loc_id)
Assemble a change-set of nodes to be sent together with elements.
Handle< Component > get_child(const std::string &name)
Definition: Component.cpp:441
Class to adapt the mesh.
Definition: MeshAdaptor.hpp:45
void synchronize()
Definition: Field.cpp:162
TableConstRow< Real >::type ConstRow
the const type of a row in the internal structure of the table
Definition: Table.hpp:59
Top-level namespace for coolfluid.
Definition: Action.cpp:18
const TYPE value(const std::string &opt_name) const
Get the value of the option with given name.
Definition: OptionList.hpp:104
void finish()
Apply the changes the mesh adaptor for changes and fix inconsistent state.
void add_tag(const std::string &tag)
TableRow< Real >::type Row
the type of a row in the internal structure of the table
Definition: Table.hpp:56
Uint row_size(Uint i=0) const
Definition: Table.hpp:133
boost::proto::terminal< SFOp< CoordinatesOp > >::type const coordinates
std::vector< std::string > get_tags() const
void send_nodes(const std::vector< std::vector< std::vector< Uint > > > &exported_nodes_loc_id, std::vector< std::vector< std::vector< boost::uint64_t > > > &imported_nodes_glb_id)
Send/Receive nodes according to an nodes-changeset.
std::string description() const
Get the string description for all the variables.
common::ComponentBuilder< MeshInterpolator, common::Action, LibVTK > MeshInterpolator_Builder
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
bool has_tag(const std::string &tag) const
Uint entities_idx() const
Definition: Entities.hpp:98
void prepare()
Prepare the mesh adaptor for changes.
Region & topology() const
Definition: Mesh.hpp:51
Handle< Component > handle()
Get a handle to the component.
Definition: Component.hpp:179
math::VariablesDescriptor & descriptor() const
Definition: Field.hpp:127
Definition: Defs.hpp:17
void send_elements(const std::vector< std::vector< std::vector< Uint > > > &exported_elements_loc_id, std::vector< std::vector< std::vector< boost::uint64_t > > > &imported_elements_glb_id)
Send/Receive elements according to an elements-changeset.
OptionList & options()
Definition: Component.cpp:856
SelectOptionType< T >::type & add(const std::string &name, const T &default_value=T())
Definition: OptionList.hpp:45
Dictionary & geometry_fields() const
Definition: Mesh.cpp:339
static Comm & instance()
Return a reference to the current PE.
Definition: Comm.cpp:44
Uint size() const
Number of rows of contained fields.
Definition: Dictionary.cpp:99
Connectivity & connectivity()
connectivity table to dictionary entries
Definition: Space.hpp:110
T * get() const
Raw pointer to the stored value, or null if there is none.
Definition: Handle.hpp:65
bool is_not_null(T ptr)
predicate for comparison to nullptr
Definition: CF.hpp:147
#define FromHere()
Send comments to:
COOLFluiD Web Admin