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-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 #include <set>
8 
9 #include "common/Builder.hpp"
10 
12 #include "common/Foreach.hpp"
13 
14 #include "common/PE/Comm.hpp"
15 #include "common/OptionList.hpp"
16 #include "common/PropertyList.hpp"
17 
19 
21 #include "mesh/Faces.hpp"
22 #include "mesh/Region.hpp"
23 #include "mesh/Space.hpp"
24 #include "mesh/Mesh.hpp"
25 #include "mesh/MeshAdaptor.hpp"
26 #include "mesh/MeshTransformer.hpp"
27 #include "mesh/Field.hpp"
28 #include "mesh/Functions.hpp"
29 #include "mesh/Connectivity.hpp"
30 #include "mesh/ElementData.hpp"
32 
33 #include "MeshInterpolator.hpp"
34 
36 
37 namespace cf3 {
38 namespace mesh {
39 namespace actions {
40 
42 
44 
46 
47 MeshInterpolator::MeshInterpolator(const std::string& name) : common::Action(name)
48 {
49  options().add("source_mesh", Handle<Mesh>())
50  .pretty_name("Source Mesh")
51  .description("Mesh to interpolate from. Warning: this is modified in parallel to make all elements known on each rank.")
52  .mark_basic();
53 
54  options().add("target_mesh", Handle<Mesh>())
55  .pretty_name("Target Mesh")
56  .description("Mesh to interpolate to")
57  .mark_basic();
58 
59  create_static_component<PointInterpolator>("PointInterpolator");
60 }
61 
63 {
64  Handle<Mesh> source_mesh = options().value< Handle<Mesh> >("source_mesh");
65  Handle<Mesh> target_mesh = options().value< Handle<Mesh> >("target_mesh");
66 
67  if(is_null(source_mesh))
68  throw common::SetupError(FromHere(), "MeshInterpolator source_mesh is not set");
69 
70  if(is_null(target_mesh))
71  throw common::SetupError(FromHere(), "MeshInterpolator target_mesh is not set");
72 
74  const Uint nb_procs = comm.size();
75  const Uint my_rank = comm.rank();
76 
77  Handle<PointInterpolator> point_interpolator(get_child("PointInterpolator"));
78  cf3_always_assert(is_not_null(point_interpolator));
79 
80  BOOST_FOREACH(const Handle<Dictionary>& source_dict, source_mesh->dictionaries())
81  {
82  if(source_dict->discontinuous())
83  continue;
84 
85  point_interpolator->options().set("dict", source_dict);
86 
87  Handle<Dictionary> target_dict(target_mesh->get_child(source_dict->name()));
88  if(is_null(target_dict))
89  {
90  target_dict = target_mesh->create_continuous_space(source_dict->name(), source_dict->properties().value<std::string>("space_lib_name")).handle<Dictionary>();
91  BOOST_FOREACH(const std::string& tag, source_dict->get_tags())
92  {
93  target_dict->add_tag(tag);
94  }
95  }
96 
97  const Field& source_coords = source_dict->coordinates();
98  const Field& target_coords = target_dict->coordinates();
99  const Uint nb_target_points = target_coords.size();
100  const Uint dim = target_coords.row_size();
101  std::vector<SpaceElem> space_elems(nb_target_points);
102  std::vector<Uint> points_begin_idxs(nb_target_points, 0);
103  std::vector<Uint> points_end_idxs(nb_target_points, 0);
104  std::vector<Uint> all_points; all_points.reserve(nb_target_points*8);
105  std::vector<Real> all_weights; all_weights.reserve(nb_target_points*8);
106  std::vector<Real> my_missing_points; my_missing_points.reserve(nb_target_points/10);
107 
108 
109  for(Uint i = 0; i != nb_target_points; ++i)
110  {
111  std::vector<Uint> points;
112  std::vector<Real> weights;
113  std::vector<SpaceElem> dummy_stencil;
114  Field::ConstRow coordrow = target_coords[i];
115  Eigen::Map<RealVector const> coord(&coordrow[0], dim);
116  bool found = point_interpolator->compute_storage(coord, space_elems[i], dummy_stencil, points, weights);
117  if(!found)
118  {
119  my_missing_points.insert(my_missing_points.end(), coordrow.begin(), coordrow.end());
120  }
121  }
122 
123  if(comm.size() > 1)
124  {
125  MeshAdaptor adaptor(*source_mesh);
126  adaptor.prepare();
127  std::vector< std::vector< std::vector<Uint> > > elements_to_send(nb_procs, std::vector< std::vector<Uint> > (source_mesh->elements().size()));
128 
129  std::vector< std::vector<Real> > recv_missing_points;
130  comm.all_gather(my_missing_points, recv_missing_points);
131  const Uint nb_ranks = comm.size();
132  cf3_assert(recv_missing_points.size() == nb_ranks);
133 
134  for(Uint rank = 0; rank != nb_ranks; ++rank)
135  {
136  if(rank == comm.rank())
137  continue;
138  const std::vector<Real>& other_missing_points = recv_missing_points[rank];
139  cf3_assert(other_missing_points.size() % dim == 0);
140  const Uint missing_end = other_missing_points.size() / dim;
141  for(Uint missing_idx = 0; missing_idx != missing_end; ++missing_idx)
142  {
143  std::vector<Uint> points;
144  std::vector<Real> weights;
145  std::vector<SpaceElem> dummy_stencil;
146  SpaceElem space_elem;
147  Eigen::Map<RealVector const> coord(&other_missing_points[missing_idx*dim], dim);
148  bool found = point_interpolator->compute_storage(coord, space_elem, dummy_stencil, points, weights);
149  if(found && !space_elem.is_ghost())
150  {
151  elements_to_send[rank][space_elem.comp->support().entities_idx()].push_back(space_elem.idx);
152  }
153  }
154  }
155 
156  std::vector< std::vector< std::vector<Uint> > > nodes_to_send;
157  adaptor.find_nodes_to_export(elements_to_send,nodes_to_send);
158 
159  std::vector< std::vector< std::vector<boost::uint64_t> > > imported_elements;
160  adaptor.send_elements(elements_to_send, imported_elements);
161 
162  adaptor.flush_elements();
163 
164  std::vector< std::vector< std::vector<boost::uint64_t> > > imported_nodes;
165  adaptor.send_nodes(nodes_to_send,imported_nodes);
166 
167  adaptor.flush_nodes();
168 
169  adaptor.finish();
170 
171  CFinfo << " + growing overlap layer ..." << CFendl;
172  common::build_component_abstract_type<MeshTransformer>("cf3.mesh.actions.GrowOverlap","grow_overlap")->transform(*source_mesh);
173  CFinfo << " + growing overlap layer ... done" << CFendl;
174 
175  point_interpolator->remove_tag(common::Tags::static_component());
176  remove_component(*point_interpolator);
177  source_mesh->remove_component("octtree");
178  point_interpolator = create_static_component<PointInterpolator>("PointInterpolator");
179  point_interpolator->options().set("function", std::string("cf3.mesh.ShapeFunctionInterpolation"));
180  point_interpolator->options().set("dict", source_dict);
181  }
182 
183  // Sometimes a point still is not found, so we slightly perturb the coordinates
184  std::vector<RealVector> perturbations(dim*2, RealVector(dim));
185  for(Uint i = 0; i != dim; ++i)
186  {
187  perturbations[2*i ].setZero();
188  perturbations[2*i+1].setZero();
189  perturbations[2*i ][i] = 1e-8;
190  perturbations[2*i+1][i] = -1e-8;
191  }
192 
193  for(Uint i = 0; i != nb_target_points; ++i)
194  {
195  std::vector<Uint> points;
196  std::vector<Real> weights;
197  std::vector<SpaceElem> dummy_stencil;
198  Field::ConstRow coordrow = target_coords[i];
199  Eigen::Map<RealVector const> coord(&coordrow[0], dim);
200  bool found = point_interpolator->compute_storage(coord, space_elems[i], dummy_stencil, points, weights);
201  if(!found)
202  {
203  BOOST_FOREACH(const RealVector& perturbation, perturbations)
204  {
205  found = point_interpolator->compute_storage(coord+perturbation, space_elems[i], dummy_stencil, points, weights);
206  if(found)
207  break;
208  }
209  }
210  if(!found && !target_dict->is_ghost(i))
211  {
212  CFerror << " Point " << coord.transpose() << " was not found in source mesh" << CFendl;
213  }
214  else
215  {
216  points_begin_idxs[i] = all_points.size();
217  all_points.insert(all_points.end(), points.begin(), points.end());
218  all_weights.insert(all_weights.end(), weights.begin(), weights.end());
219  points_end_idxs[i] = all_points.size();
220  }
221  }
222 
223  BOOST_FOREACH(const Handle<Field>& source_field, source_dict->fields())
224  {
225  if(source_field->has_tag(mesh::Tags::coordinates()))
226  continue;
227 
228  Handle<Field> target_field(target_dict->get_child(source_field->name()));
229  if(is_null(target_field))
230  {
231  target_field = target_dict->create_field(source_field->name(), source_field->descriptor().description()).handle<Field>();
232  BOOST_FOREACH(const std::string& tag, source_field->get_tags())
233  {
234  target_field->add_tag(tag);
235  }
236  }
237 
238  const Field::ArrayT& source_array = source_field->array();
239  Field::ArrayT& target_array = target_field->array();
240  const Uint row_size = source_field->row_size();
241  cf3_always_assert(row_size == target_field->row_size());
242  cf3_assert(nb_target_points == target_array.size());
243 
244  for(Uint i = 0; i != nb_target_points; ++i)
245  {
246  if(target_dict->is_ghost(i))
247  continue;
248  Eigen::Map<RealVector> target_row(&target_array[i][0], row_size);
249  target_row.setZero();
250  RealVector avg_row(target_row);
251  const Uint interp_begin = points_begin_idxs[i];
252  const Uint interp_end = points_end_idxs[i];
253  cf3_assert(interp_begin < all_points.size());
254  cf3_assert(interp_end <= all_points.size());
255  Real weightsum = 0;
256  for(Uint j = interp_begin; j != interp_end; ++j)
257  {
258  if(all_points[j] >= source_array.size())
259  {
260  throw common::SetupError(FromHere(), "Point " + common::to_str(all_points[j]) + " is outside the source point range");
261  }
262  Eigen::Map<RealVector const> source_row(&source_array[all_points[j]][0], row_size);
263  target_row += all_weights[j] * source_row;
264  avg_row += source_row;
265  weightsum += all_weights[j];
266  }
267  if(weightsum > 1. + 1e-10)
268  {
269  CFerror << "Bad weights found, using unweighted average on point " << i << CFendl;
270  target_row = avg_row;
271  }
272  }
273 
274  target_field->parallelize();
275  target_field->synchronize();
276  }
277  }
278 }
279 
281 
282 
283 } // actions
284 } // mesh
285 } // cf3
#define CFinfo
these are always defined
Definition: Log.hpp:104
std::string name(ComponentWrapper &self)
virtual void execute()
execute the action
bool is_null(T ptr)
predicate for comparison to nullptr
Definition: CF.hpp:151
TableArray< Real >::type ArrayT
the type of the internal structure of the table
Definition: Table.hpp:53
MeshInterpolator(const std::string &name)
Helper class to create the Builder and place it in the factory.
Definition: Builder.hpp:212
#define cf3_assert(a)
Definition: Assertions.hpp:93
static const char * static_component()
Tag to indicate that a component is static.
Definition: Tags.cpp:15
void flush_elements()
Apply all changes to elements.
Entities & support() const
Access the geometric support.
Definition: Space.hpp:102
#define CFendl
Definition: Log.hpp:109
Uint rank() const
Return rank, additionally, if is_init==0.
Definition: Comm.cpp:135
Real e()
Definition of the Unit charge [C].
Definition: Consts.hpp:30
Common_API std::string to_str(const T &v)
Converts to std::string.
Uint size() const
Return the number of processes, or 1 if is_init==0.
Definition: Comm.cpp:145
Uint size() const
Definition: Table.hpp:127
#define cf3_always_assert(a)
Definition: Assertions.hpp:81
void flush_nodes()
Apply all changes to nodes.
common::ComponentBuilder< MeshInterpolator, common::Action, mesh::actions::LibActions > MeshInterpolator_Builder
Eigen::Matrix< Real, Eigen::Dynamic, 1 > RealVector
Dynamic sized column vector.
Definition: MatrixTypes.hpp:25
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
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.
Uint row_size(Uint i=0) const
Definition: Table.hpp:133
boost::proto::terminal< SFOp< CoordinatesOp > >::type const coordinates
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.
Component that executes an action. Implementation of the IAction interface as a component, exposing the execute function as a signal.
Definition: Action.hpp:21
boost::shared_ptr< Component > remove_component(const std::string &name)
Remove a (sub)component of this component.
Definition: Component.cpp:357
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
bool is_ghost() const
Definition: Space.cpp:248
Uint entities_idx() const
Definition: Entities.hpp:98
void prepare()
Prepare the mesh adaptor for changes.
#define CFerror
Definition: Log.hpp:105
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
static Comm & instance()
Return a reference to the current PE.
Definition: Comm.cpp:44
T * all_gather(const T *in_values, const int in_n, T *out_values, const int stride=1)
Definition: Comm.hpp:192
bool is_not_null(T ptr)
predicate for comparison to nullptr
Definition: CF.hpp:147
#define FromHere()
Send comments to:
COOLFluiD Web Admin