v0.14.0
ContactSearchKdTree.hpp
Go to the documentation of this file.
1 /* This file is part of MoFEM.
2  * MoFEM is free software: you can redistribute it and/or modify it under
3  * the terms of the GNU Lesser General Public License as published by the
4  * Free Software Foundation, either version 3 of the License, or (at your
5  * option) any later version.
6  *
7  * MoFEM is distributed in the hope that it will be useful, but WITHOUT
8  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  * License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with MoFEM. If not, see <http://www.gnu.org/licenses/>. */
14 
15 #ifndef __CONTACT_SEARCH_KD_TREE__
16 #define __CONTACT_SEARCH_KD_TREE__
17 
19 
22  : mField(m_field), kdTree(&m_field.get_moab()) {}
23 
25  AdaptiveKDTree kdTree;
27  // kd-tree from
28  MoFEMErrorCode buildTree(Range &range_surf_master) {
30  CHKERR kdTree.build_tree(range_surf_master, &kdTreeRootMeshset);
32  }
33 
34  // Definitition of multi-index containers consisting of prisms between master
35  // and slave trias and their corresponding triangles integration_tris
39  ContactCommonData(EntityHandle _prism, Range _common_integrated_triangle)
40  : pRism(_prism), commonIntegratedTriangle(_common_integrated_triangle) {
41  }
42  };
43 
44  struct Prism_tag {};
45 
46  typedef multi_index_container<
47  boost::shared_ptr<ContactCommonData>,
48  indexed_by<
49  ordered_unique<tag<Prism_tag>, member<ContactCommonData, EntityHandle,
52 
53  // Rotation matrix to transform the 3D triangle to 2D triangle (because
54  // clipper library only works in 2D)
57 
61 
62  VectorDouble3 v_s1(3), v_s2(3), v_n(3);
63  double diffN[6];
64  CHKERR ShapeDiffMBTRI(diffN);
65 
66  CHKERR ShapeFaceBaseMBTRI(diffN, &*v_coords.data().begin(),
67  &*v_n.data().begin(), &*v_s1.data().begin(),
68  &*v_s2.data().begin());
69 
70  FTensor::Tensor1<double *, 3> t_s1(&v_s1[0], &v_s1[1], &v_s1[2], 3);
71  FTensor::Tensor1<double *, 3> t_s2(&v_s2[0], &v_s2[1], &v_s2[2], 3);
72  FTensor::Tensor1<double *, 3> t_n(&v_n[0], &v_n[1], &v_n[2], 3);
73 
74  double s1_mag = sqrt(t_s1(i) * t_s1(i));
75  double n_mag = sqrt(t_n(i) * t_n(i));
76  v_s1 /= s1_mag;
77  v_n /= n_mag;
78 
79  t_s2(i) = FTensor::levi_civita(i, j, k) * t_n(j) * t_s1(k);
80 
81  for (int ii = 0; ii != 3; ++ii) {
82  m_rot(0, ii) = t_s1(ii);
83  m_rot(1, ii) = t_s2(ii);
84  m_rot(2, ii) = t_n(ii);
85  }
86 
88  }
89 
92 
94  double s1[3], s2[3];
95  double diffN[6];
96  CHKERR ShapeDiffMBTRI(diffN);
97 
98  CHKERR ShapeFaceBaseMBTRI(diffN, &*v_coords.data().begin(),
99  &*n_vec.data().begin(), s1, s2);
100 
101  FTensor::Tensor1<double *, 3> t_n(&n_vec[0], &n_vec[1], &n_vec[2], 3);
102  double n_mag = sqrt(t_n(i) * t_n(i));
103  n_vec /= n_mag;
104 
106  }
107 
108  // Searching for contacting triangles with the help of kdtree from MOAB
109  // fill the multi-index container (contact_commondata_multi_index) conissting
110  // of prism with corresponding integration triangles fill
111  // range_slave_master_prisms consisting of all the prisms (to be used for
112  // looping over all these finite elements)
113  PetscErrorCode
114  contactSearchAlgorithm(Range &range_surf_master, Range &range_surf_slave,
115  boost::shared_ptr<ContactCommonData_multiIndex>
116  contact_commondata_multi_index,
117  Range &range_slave_master_prisms) {
119 
122  auto get_tensor_vec = [](VectorDouble &v) {
124  &v(2));
125  };
126 
127  // clipper library way to define one master and one slave tri and the out
128  // put will store in solution
129  Paths path_slave(1), path_master(1), solution;
130 
131  // it is used to convert double to integer to be used in clipper library (as
132  // the library only works for integer) so we will convert all dimensions
133  // from double to integer and after finding common polygon will convert back
134  // to double
135  double roundfact = 1e6;
136 
137  // Ranges of polygons in each intersections and created tris
138  Range tris_in_polygon;
139 
140  VectorDouble v_slave_tri_cent;
141  v_slave_tri_cent.resize(3, false);
142 
143  VectorDouble v_coords_slave_new;
144  v_coords_slave_new.resize(9, false);
145 
146  MatrixDouble m_rot;
147  m_rot.resize(3, 3, false);
148 
149  VectorDouble n_vec;
150  n_vec.resize(3, false);
151 
152  VectorDouble v_coords_slave;
153  v_coords_slave.resize(9, false);
154 
155  // loop over slave triagles (to create prisms)
156  int slave_num = 0;
157  for (Range::iterator tri_it_slave = range_surf_slave.begin();
158  tri_it_slave != range_surf_slave.end(); ++tri_it_slave) {
159  ++slave_num;
160 
161  int num_nodes_slave;
162  const EntityHandle *conn_slave = NULL;
163  CHKERR mField.get_moab().get_connectivity(*tri_it_slave, conn_slave,
164  num_nodes_slave);
165 
166  // insert prisms between master and slave triangles, who have common
167  // polygons last three nodes belong to the slave tri and the other three
168  // belong to the master tris
169  EntityHandle slave_master_1prism;
170  EntityHandle prism_nodes[6];
171  // slave is the top tri so add it to the top tri of prism [ii+3]
172  for (int ii = 0; ii != 3; ++ii) {
173  prism_nodes[ii + 3] = conn_slave[ii];
174  }
175 
176  CHKERR mField.get_moab().get_coords(conn_slave, 3,
177  &*v_coords_slave.data().begin());
178 
179  auto t_coords_slave = get_tensor_vec(v_coords_slave);
180  // rotation matrix (3x3) which will be used to transform the tri to z
181  // plane (this is the same for both slave and master tris) so
182  // calculate it only once
183  CHKERR rotationMatrix(m_rot, v_coords_slave);
185  &m_rot(0, 0), &m_rot(0, 1), &m_rot(0, 2), &m_rot(1, 0), &m_rot(1, 1),
186  &m_rot(1, 2), &m_rot(2, 0), &m_rot(2, 1), &m_rot(2, 2)};
187 
188  CHKERR getNormalVector(n_vec, v_coords_slave);
189  auto t_slave_normal = get_tensor_vec(n_vec);
190 
191  // as we need to transfer the coordinate to z=0
192  double z_shift;
193 
194  auto t_coords_slave_new = get_tensor_vec(v_coords_slave_new);
195 
196  auto t_slave_tri_cent = get_tensor_vec(v_slave_tri_cent);
197  t_slave_tri_cent(i) = 0;
198 
199  // transfer the slave tri coordinates (n=3) one by one
200  for (int ii = 0; ii != 3; ++ii) {
201  t_coords_slave_new(i) = t_m_rot(i, j) * t_coords_slave(j);
202  t_slave_tri_cent(i) += t_coords_slave(i) / 3;
203  if (ii == 0)
204  z_shift = v_coords_slave_new[2];
205 
206  t_coords_slave_new(2) = 0;
207  ++t_coords_slave_new;
208  ++t_coords_slave;
209  }
210 
211  // multiply with roundfact to convert to integer
212  v_coords_slave_new = roundfact * v_coords_slave_new;
213 
214  // clear clipper vector for slave tri and fill it to be used in clipper
215  path_slave[0].clear();
216  path_slave[0] << IntPoint(v_coords_slave_new[0], v_coords_slave_new[1])
217  << IntPoint(v_coords_slave_new[3], v_coords_slave_new[4])
218  << IntPoint(v_coords_slave_new[6], v_coords_slave_new[7]);
219 
220  // find centroid of triangle based on original coordinates (this is
221  // created to search the nearest master tri) it is to be used in kd-tree
222 
223  // this range will be filled in recursive manner, starting from the
224  // nearset one and unitill there is no more intersecting master tris
225  Range range_closest_master_tris;
226  range_closest_master_tris.clear();
227  double closest_point[3];
228  EntityHandle closest_master_tri;
229  CHKERR kdTree.closest_triangle(kdTreeRootMeshset,
230  &*v_slave_tri_cent.data().begin(),
231  closest_point, closest_master_tri);
232 
233  range_closest_master_tris.insert(closest_master_tri);
234 
235  // this while loop will continue until there is no more master tri for
236  // slave tris
237  bool flag_first_master =
238  true; // for the first master, we will not find the adjacenency
239  int master_num = 0;
240  bool flag_end_of_search = false;
241  bool flag_temp = true;
242  while (flag_end_of_search == false) {
243 
244  Range range_master_tris_on_surf_new;
245  if (flag_first_master == true) { // first master
246  range_master_tris_on_surf_new = range_closest_master_tris;
247  flag_first_master = false;
248  } else { // the rest of master determine from adjacencies
249  flag_temp = false;
250  Range range_conn;
251  CHKERR mField.get_moab().get_connectivity(range_closest_master_tris,
252  range_conn);
253 
254  Range range_adj_entities;
255  // in the get_adjacencies, if moab::Interface::INTERSECT it will give
256  // only the tri, which is interesect of the adjacency of all nodes
257  // moab::Interface::UNION will give all the tri, even the one which
258  // are not on the surface, so then need to intersect with the master
259  // to get what we want
260  CHKERR mField.get_moab().get_adjacencies(
261  range_conn, 2, false, range_adj_entities, moab::Interface::UNION);
262 
263  // triangle on the surface, i.e. removing the tri inside the volume
264  Range range_master_tris_on_surf =
265  intersect(range_surf_master, range_adj_entities);
266 
267  // removing the tri from the range_tri_on_surf, which already exists
268  // in range_closest_master_tris
269  range_master_tris_on_surf_new =
270  subtract(range_master_tris_on_surf, range_closest_master_tris);
271  }
272 
273  // all used in master loop
274  VectorDouble v_coords_master;
275  v_coords_master.resize(9, false);
276 
277  VectorDouble n_vec_master;
278  n_vec_master.resize(3, false);
279 
280  // fill the master clipper vector
281  VectorDouble v_coords_master_new;
282  v_coords_master_new.resize(9, false);
283 
284  double coord[3];
285  // looping over all master range_master_tris_on_surf_new and discart
286  // those elements, which are not in contact with master (will do it with
287  // clipper library)
288  int num_intersections = 0;
289  for (Range::iterator tri_it_master =
290  range_master_tris_on_surf_new.begin();
291  tri_it_master != range_master_tris_on_surf_new.end();
292  ++tri_it_master) {
293  const EntityHandle *conn_master = NULL;
294  int num_nodes_master = 0;
295  CHKERR mField.get_moab().get_connectivity(*tri_it_master, conn_master,
296  num_nodes_master);
297 
298  CHKERR mField.get_moab().get_coords(conn_master, 3,
299  &*v_coords_master.data().begin());
300 
301  auto t_coords_master = get_tensor_vec(v_coords_master);
302 
303  CHKERR getNormalVector(n_vec_master, v_coords_master);
304 
305  auto t_master_normal = get_tensor_vec(n_vec_master);
306 
307  // 0.035 angle of 88 deg
308  if (fabs(t_slave_normal(i) * t_master_normal(i)) < 0.035)
309  continue;
310 
311  auto t_coords_master_new = get_tensor_vec(v_coords_master_new);
312 
313  // rotation matrix for this master element is the same as for the
314  // above slave element
315  for (int ii = 0; ii != 3; ++ii) {
316  t_coords_master_new(i) = t_m_rot(i, j) * t_coords_master(j);
317  t_coords_master_new(2) = 0;
318  ++t_coords_master_new;
319  ++t_coords_master;
320  }
321 
322  v_coords_master_new = roundfact * v_coords_master_new;
323  path_master[0].clear();
324  path_master[0]
325  << IntPoint(v_coords_master_new[0], v_coords_master_new[1])
326  << IntPoint(v_coords_master_new[3], v_coords_master_new[4])
327  << IntPoint(v_coords_master_new[6], v_coords_master_new[7]);
328 
329  // perform intersection in clipper
330  Clipper c;
331  c.AddPaths(path_master, ptSubject, true);
332  c.AddPaths(path_slave, ptClip, true);
333  c.Execute(ctIntersection, solution, pftNonZero, pftNonZero);
334 
335  if (solution.size() != 1 && flag_temp) {
336  double ray_dir[3];
337  CHKERR Tools::getTriNormal(&v_coords_slave(0), ray_dir);
338  double norm = cblas_dnrm2(3, ray_dir, 1);
339  cblas_dscal(3, 1. / norm, ray_dir, 1);
340  const double tol = 1e-6;
341  std::vector<double> distance;
342  std::vector<EntityHandle> triangles_out;
343  CHKERR kdTree.ray_intersect_triangles(kdTreeRootMeshset, tol, ray_dir,
344  &*v_slave_tri_cent.data().begin(),
345  triangles_out, distance);
346 
347  if (!triangles_out.empty()) {
348  range_closest_master_tris.clear();
349  range_closest_master_tris.insert(triangles_out.front());
350  flag_first_master = true;
351  num_intersections = -1;
352  break;
353  }
354  }
355 
356  if (solution.size() == 1) { // if it intersect
357  range_closest_master_tris.insert(
358  *tri_it_master); // update range_closest_master_tris
359  num_intersections += 1;
360 
361  int n_vertices_polygon = solution[0].size();
362  // the first three nodes for the prism are the master tri (insert
363  // prisms only if there is intersection between slave and master
364  // tris)
365  for (int ii = 0; ii != 3; ++ii) {
366  prism_nodes[ii] = conn_master[ii];
367  }
368 
369  // creating prism between master and slave tris
370  CHKERR mField.get_moab().create_element(MBPRISM, prism_nodes, 6,
371  slave_master_1prism);
372 
373  range_slave_master_prisms.insert(slave_master_1prism);
374 
375  // coordinates of intersection polygon between master and slave
376  // here we have only coordinates of polygon, so we will need to
377  // construct vertices and polygon from it
378  VectorDouble v_coord_polygon;
379  v_coord_polygon.resize(3 * n_vertices_polygon);
380 
381  // perform transfermation (tansfer all coordinates of polygon)
382  // create moab vertices with given coordinates (from clippper) and
383  // then create polygon from these vertices
384  VectorDouble v_coord_polygon_new;
385  v_coord_polygon_new.resize(3 * n_vertices_polygon);
386 
387  auto t_coord_polygon_new = get_tensor_vec(v_coord_polygon_new);
388  auto t_coord_polygon = get_tensor_vec(v_coord_polygon);
389 
390  std::vector<EntityHandle> conn_polygon(n_vertices_polygon);
391  for (int ii = 0; ii != n_vertices_polygon; ++ii) {
392  t_coord_polygon(0) = solution[0][ii].X / roundfact;
393  t_coord_polygon(1) = solution[0][ii].Y / roundfact;
394  t_coord_polygon(2) += z_shift;
395 
396  t_coord_polygon_new(i) = t_m_rot(j, i) * t_coord_polygon(j);
397 
398  coord[0] = t_coord_polygon_new(0);
399  coord[1] = t_coord_polygon_new(1);
400  coord[2] = t_coord_polygon_new(2);
401  CHKERR mField.get_moab().create_vertex(coord, conn_polygon[ii]);
402 
403  ++t_coord_polygon_new;
404  ++t_coord_polygon;
405  }
406 
407  EntityHandle polygon;
408  CHKERR mField.get_moab().create_element(
409  MBPOLYGON, &conn_polygon[0], n_vertices_polygon, polygon);
410 
411  // triangulate the polygon (if it only have 3 vertices, so it is
412  // triangle, so don't need to triangulate)
413  tris_in_polygon.clear();
414  if (n_vertices_polygon == 3) {
415  // tris_in_polygon.insert(polygon);
416  EntityHandle new_tri_conn[3];
417  new_tri_conn[0] = conn_polygon[0];
418  new_tri_conn[1] = conn_polygon[1];
419  new_tri_conn[2] = conn_polygon[2];
420  EntityHandle new_tri;
421  CHKERR mField.get_moab().create_element(MBTRI, new_tri_conn, 3,
422  new_tri);
423 
424  tris_in_polygon.insert(new_tri);
425  } else {
426  EntityHandle new_tri_conn[3];
427  new_tri_conn[0] = conn_polygon[0];
428  for (int ii = 0; ii != n_vertices_polygon - 2; ++ii) {
429  new_tri_conn[1] = conn_polygon[ii + 1];
430  new_tri_conn[2] = conn_polygon[ii + 2];
431  // create tri in polygon
432  EntityHandle new_tri;
433  CHKERR mField.get_moab().create_element(MBTRI, new_tri_conn, 3,
434  new_tri);
435 
436  tris_in_polygon.insert(new_tri);
437  }
438  }
439 
440  // fill the multi-index container with pair (prism between slave and
441  // master, triangles in the common polygon)
442  contact_commondata_multi_index->insert(
443  boost::shared_ptr<ContactCommonData>(new ContactCommonData(
444  slave_master_1prism, tris_in_polygon)));
445  }
446  } // master loop for new layer arrond the previous layer
447 
448  if (num_intersections == 0)
449  flag_end_of_search = true; // this will stop further searching for the
450  // current slave and will go to next one
451  } // while loop
452  } // slave loop
453 
455  }
456 };
457 #endif
ClipperLib::Paths
std::vector< Path > Paths
Definition: clipper.hpp:107
ContactSearchKdTree::ContactCommonData
Definition: ContactSearchKdTree.hpp:36
ContactSearchKdTree::ContactSearchKdTree
ContactSearchKdTree(MoFEM::Interface &m_field)
Definition: ContactSearchKdTree.hpp:21
MoFEM::Types::VectorDouble3
VectorBoundedArray< double, 3 > VectorDouble3
Definition: Types.hpp:92
FTensor::Tensor1
Definition: Tensor1_value.hpp:8
EntityHandle
ContactSearchKdTree::ContactCommonData_multiIndex
multi_index_container< boost::shared_ptr< ContactCommonData >, indexed_by< ordered_unique< tag< Prism_tag >, member< ContactCommonData, EntityHandle, &ContactCommonData::pRism > > > > ContactCommonData_multiIndex
Definition: ContactSearchKdTree.hpp:51
ContactSearchKdTree::mField
MoFEM::Interface & mField
Definition: ContactSearchKdTree.hpp:20
MoFEM::Exceptions::MoFEMErrorCode
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
Definition: Exceptions.hpp:56
MoFEM::Types::MatrixDouble
UBlasMatrix< double > MatrixDouble
Definition: Types.hpp:77
ContactSearchKdTree
Definition: ContactSearchKdTree.hpp:18
ClipperLib::ptSubject
@ ptSubject
Definition: clipper.hpp:65
FTensor::levi_civita
constexpr std::enable_if<(Dim0<=2 &&Dim1<=2), Tensor2_Expr< Levi_Civita< T >, T, Dim0, Dim1, i, j > >::type levi_civita(const Index< i, Dim0 > &, const Index< j, Dim1 > &)
levi_civita functions to make for easy adhoc use
Definition: Levi_Civita.hpp:617
ContactSearchKdTree::ContactCommonData::pRism
EntityHandle pRism
Definition: ContactSearchKdTree.hpp:37
FTensor::Tensor2< double *, 3, 3 >
MoFEM::DeprecatedCoreInterface
Deprecated interface functions.
Definition: DeprecatedCoreInterface.hpp:16
ContactSearchKdTree::rotationMatrix
MoFEMErrorCode rotationMatrix(MatrixDouble &m_rot, VectorDouble &v_coords)
Definition: ContactSearchKdTree.hpp:55
ShapeDiffMBTRI
PetscErrorCode ShapeDiffMBTRI(double *diffN)
calculate derivatives of shape functions
Definition: fem_tools.c:194
c
const double c
speed of light (cm/ns)
Definition: initial_diffusion.cpp:39
CHKERR
#define CHKERR
Inline error check.
Definition: definitions.h:548
MoFEM::CoreInterface::get_moab
virtual moab::Interface & get_moab()=0
ClipperLib::ptClip
@ ptClip
Definition: clipper.hpp:65
ContactSearchKdTree::kdTreeRootMeshset
EntityHandle kdTreeRootMeshset
Definition: ContactSearchKdTree.hpp:24
ContactSearchKdTree::ContactCommonData::commonIntegratedTriangle
Range commonIntegratedTriangle
Definition: ContactSearchKdTree.hpp:38
ContactSearchKdTree::Prism_tag
Definition: ContactSearchKdTree.hpp:44
ContactSearchKdTree::kdTree
AdaptiveKDTree kdTree
Definition: ContactSearchKdTree.hpp:25
i
FTensor::Index< 'i', SPACE_DIM > i
Definition: hcurl_divergence_operator_2d.cpp:27
ContactSearchKdTree::contactSearchAlgorithm
PetscErrorCode contactSearchAlgorithm(Range &range_surf_master, Range &range_surf_slave, boost::shared_ptr< ContactCommonData_multiIndex > contact_commondata_multi_index, Range &range_slave_master_prisms)
Definition: ContactSearchKdTree.hpp:114
FTensor::Index< 'i', 3 >
v
const double v
phase velocity of light in medium (cm/ns)
Definition: initial_diffusion.cpp:40
Range
ContactSearchKdTree::ContactCommonData::ContactCommonData
ContactCommonData(EntityHandle _prism, Range _common_integrated_triangle)
Definition: ContactSearchKdTree.hpp:39
ContactSearchKdTree::buildTree
MoFEMErrorCode buildTree(Range &range_surf_master)
Definition: ContactSearchKdTree.hpp:28
j
FTensor::Index< 'j', 3 > j
Definition: matrix_function.cpp:19
ClipperLib::pftNonZero
@ pftNonZero
Definition: clipper.hpp:70
ShapeFaceBaseMBTRI
PetscErrorCode ShapeFaceBaseMBTRI(double *diffN, const double *coords, double *normal, double *s1, double *s2)
Definition: fem_tools.c:204
ContactSearchKdTree::nullTriRange
Range nullTriRange
Definition: ContactSearchKdTree.hpp:26
MoFEM::Types::VectorDouble
UBlasVector< double > VectorDouble
Definition: Types.hpp:68
ClipperLib::ctIntersection
@ ctIntersection
Definition: clipper.hpp:64
ContactSearchKdTree::getNormalVector
MoFEMErrorCode getNormalVector(VectorDouble &n_vec, VectorDouble &v_coords)
Definition: ContactSearchKdTree.hpp:90
k
FTensor::Index< 'k', 3 > k
Definition: matrix_function.cpp:20
MoFEMFunctionReturn
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
Definition: definitions.h:429
MoFEMFunctionBegin
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
Definition: definitions.h:359
tol
double tol
Definition: mesh_smoothing.cpp:26