GetFEM++  5.3
getfem_interpolation_on_deformed_domains.cc
1 /*===========================================================================
2 
3  Copyright (C) 2013-2017 Yves Renard, Konstantinos Poulios and Andriy Andreykiv.
4 
5  This file is a part of GetFEM++
6 
7  GetFEM++ is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
23 #include "getfem/getfem_models.h"
24 
25 namespace getfem {
26 
27 // Structure describing a contact boundary (or contact body)
28 struct contact_boundary {
29  size_type region; // boundary region for the slave (source)
30  // and volume region for the master (target)
31  const getfem::mesh_fem *mfu; // F.e.m. for the displacement.
32  std::string dispname; // Variable name for the displacement
33  mutable const model_real_plain_vector *U;// Displacement
34  mutable model_real_plain_vector U_unred; // Unreduced displacement
35 
36  contact_boundary(size_type r, const mesh_fem *mf, const std::string &dn)
37  : region(r), mfu(mf), dispname(dn)
38  {}
39 };
40 
41 //extract element displacements from a contact boundary object
42 base_small_vector element_U(const contact_boundary &cb, size_type cv)
43 {
44  auto U_elm = base_small_vector{};
45  slice_vector_on_basic_dof_of_element(*(cb.mfu), *cb.U, cv, U_elm);
46  return U_elm;
47 }
48 
49 //Returns an iterator of a box which centre is closest to the given point
50 auto most_central_box(const bgeot::rtree::pbox_set &bset,
51  const bgeot::base_node &pt) -> decltype(begin(bset))
52 {
53  using namespace std;
54 
55  auto itmax = begin(bset);
56 
57  auto it = itmax;
58  if (bset.size() > 1) {
59  auto rate_max = scalar_type{-1};
60  for (; it != end(bset); ++it) {
61  auto rate_box = scalar_type{1};
62  for (size_type i = 0; i < pt.size(); ++i) {
63  auto h = (*it)->max[i] - (*it)->min[i];
64  if (h > 0.) {
65  auto rate = min((*it)->max[i] - pt[i], pt[i] - (*it)->min[i]) / h;
66  rate_box = min(rate, rate_box);
67  }
68  }
69  if (rate_box > rate_max) {
70  itmax = it;
71  rate_max = rate_box;
72  }
73  }
74  }
75 
76  return itmax;
77 }
78 
79 //Transformation that creates identity mapping between two contact boundaries,
80 //deformed with provided displacement fields
81 class interpolate_transformation_on_deformed_domains
82  : public virtual_interpolate_transformation {
83 
84  contact_boundary master;//also marked with a target or Y prefix/suffix
85  contact_boundary slave; //also marked with a source or X prefix/suffix
86 
87  mutable bgeot::rtree element_boxes;
88  mutable std::vector<size_type> box_to_convex; //index to obtain
89  //a convex number from a box number
90  mutable bgeot::geotrans_inv_convex gic;
91  mutable fem_precomp_pool fppool;
92 
93  //Create a box tree based on the deformed elements of the master (target)
94  void compute_element_boxes() const { // called by init
95  base_matrix G;
96  model_real_plain_vector Uelm; //element displacement
97  element_boxes.clear();
98 
99  auto bnum = master.region;
100  auto &mfu = *(master.mfu);
101  auto &U = *(master.U);
102  auto &m = mfu.linked_mesh();
103  auto N = m.dim();
104 
105  base_node Xdeformed(N), bmin(N), bmax(N);
106  auto region = m.region(bnum);
107 
108  //the box tree creation and subsequent transformation inversion
109  //should be done for all elements of the master, while integration
110  //will be performed only on a thread partition of the slave
111  region.prohibit_partitioning();
112 
113  GMM_ASSERT1(mfu.get_qdim() == N, "Wrong mesh_fem qdim");
114 
115  dal::bit_vector points_already_interpolated;
116  std::vector<base_node> transformed_points(m.nb_max_points());
117  box_to_convex.clear();
118  box_to_convex.reserve(region.size());
119 
120  for (getfem::mr_visitor v(region, m); !v.finished(); ++v) {
121  auto cv = v.cv();
122  auto pgt = m.trans_of_convex(cv);
123  auto pf_s = mfu.fem_of_element(cv);
124  auto pfp = fppool(pf_s, pgt->pgeometric_nodes());
125 
126  slice_vector_on_basic_dof_of_element(mfu, U, cv, Uelm);
127  mfu.linked_mesh().points_of_convex(cv, G);
128 
129  auto ctx = fem_interpolation_context{pgt, pfp, size_type(-1), G, cv};
130  auto nb_pt = pgt->structure()->nb_points();
131 
132  for (size_type k = 0; k < nb_pt; ++k) {
133  auto ind = m.ind_points_of_convex(cv)[k];
134 
135  // computation of a transformed vertex
136  ctx.set_ii(k);
137  if (points_already_interpolated.is_in(ind)) {
138  Xdeformed = transformed_points[ind];
139  } else {
140  pf_s->interpolation(ctx, Uelm, Xdeformed, dim_type{N});
141  Xdeformed += ctx.xreal(); //Xdeformed = U + Xo
142  transformed_points[ind] = Xdeformed;
143  points_already_interpolated.add(ind);
144  }
145 
146  if (k == 0) // computation of bounding box
147  bmin = bmax = Xdeformed;
148  else {
149  for (size_type l = 0; l < N; ++l) {
150  bmin[l] = std::min(bmin[l], Xdeformed[l]);
151  bmax[l] = std::max(bmax[l], Xdeformed[l]);
152  }
153  }
154  }
155 
156  // Store the bounding box and additional information.
157  element_boxes.add_box(bmin, bmax, box_to_convex.size());
158  box_to_convex.push_back(cv);
159  }
160  }
161 
162  fem_interpolation_context deformed_master_context(size_type cv) const
163  {
164  auto &mfu = *(master.mfu);
165  auto G = base_matrix{};
166  auto pfu = mfu.fem_of_element(cv);
167  auto pgt = master.mfu->linked_mesh().trans_of_convex(cv);
168  auto pfp = fppool(pfu, pgt->pgeometric_nodes());
169  master.mfu->linked_mesh().points_of_convex(cv, G);
170  return {pgt, pfp, size_type(-1), G, cv};
171  }
172 
173  std::vector<bgeot::base_node> deformed_master_nodes(size_type cv) const {
174  using namespace bgeot;
175  using namespace std;
176 
177  auto nodes = vector<base_node>{};
178 
179  auto U_elm = element_U(master, cv);
180  auto &mfu = *(master.mfu);
181  auto G = base_matrix{};
182  auto pfu = mfu.fem_of_element(cv);
183  auto pgt = master.mfu->linked_mesh().trans_of_convex(cv);
184  auto pfp = fppool(pfu, pgt->pgeometric_nodes());
185  auto N = mfu.linked_mesh().dim();
186  auto pt = base_node(N);
187  auto U = base_small_vector(N);
188  master.mfu->linked_mesh().points_of_convex(cv, G);
189  auto ctx = fem_interpolation_context{pgt, pfp, size_type(-1), G, cv};
190  auto nb_pt = pgt->structure()->nb_points();
191  nodes.reserve(nb_pt);
192  for (size_type k = 0; k < nb_pt; ++k) {
193  ctx.set_ii(k);
194  pfu->interpolation(ctx, U_elm, U, dim_type{N});
195  gmm::add(ctx.xreal(), U, pt);
196  nodes.push_back(pt);
197  }
198 
199  return nodes;
200  }
201 
202 public:
203 
204  interpolate_transformation_on_deformed_domains(
205  size_type source_region,
206  const getfem::mesh_fem &mf_source,
207  const std::string &source_displacements,
208  size_type target_region,
209  const getfem::mesh_fem &mf_target,
210  const std::string &target_displacements)
211  :
212  slave{source_region, &mf_source, source_displacements},
213  master{target_region, &mf_target, target_displacements}
214 {}
215 
216 
217  void extract_variables(const ga_workspace &workspace,
218  std::set<var_trans_pair> &vars,
219  bool ignore_data,
220  const mesh &m_x,
221  const std::string &interpolate_name) const override {
222  if (!ignore_data || !(workspace.is_constant(master.dispname))){
223  vars.emplace(master.dispname, interpolate_name);
224  vars.emplace(slave.dispname, "");
225  }
226  }
227 
228  void init(const ga_workspace &workspace) const override {
229 
230  for (auto pcb : std::list<const contact_boundary*>{&master, &slave}) {
231  auto &mfu = *(pcb->mfu);
232  if (mfu.is_reduced()) {
233  gmm::resize(pcb->U_unred, mfu.nb_basic_dof());
234  mfu.extend_vector(workspace.value(pcb->dispname), pcb->U_unred);
235  pcb->U = &(pcb->U_unred);
236  } else {
237  pcb->U = &(workspace.value(pcb->dispname));
238  }
239  }
240  compute_element_boxes();
241  };
242 
243  void finalize() const override {
244  element_boxes.clear();
245  box_to_convex.clear();
246  master.U_unred.clear();
247  slave.U_unred.clear();
248  fppool.clear();
249  }
250 
251  int transform(const ga_workspace &workspace,
252  const mesh &m_x,
253  fem_interpolation_context &ctx_x,
254  const base_small_vector &/*Normal*/,
255  const mesh **m_t,
256  size_type &cv,
257  short_type &face_num,
258  base_node &P_ref,
259  base_small_vector &N_y,
260  std::map<var_trans_pair, base_tensor> &derivatives,
261  bool compute_derivatives) const override {
262 
263  auto &target_mesh = master.mfu->linked_mesh();
264  *m_t = &target_mesh;
265  auto transformation_success = false;
266 
267  using namespace gmm;
268  using namespace bgeot;
269  using namespace std;
270 
271  //compute a deformed point of the slave
272  auto cv_x = ctx_x.convex_num();
273  auto U_elm_x = element_U(slave, cv_x);
274  auto &mfu_x = *(slave.mfu);
275  auto pfu_x = mfu_x.fem_of_element(cv_x);
276  auto N = mfu_x.linked_mesh().dim();
277  auto U_x = base_small_vector(N);
278  auto G_x = base_matrix{}; //coordinates of the source element nodes
279  m_x.points_of_convex(cv_x, G_x);
280  ctx_x.set_pf(pfu_x);
281  pfu_x->interpolation(ctx_x, U_elm_x, U_x, dim_type{N});
282  auto pt_x = base_small_vector(N); //deformed point of the slave
283  add(ctx_x.xreal(), U_x, pt_x);
284 
285  //Find the best box from the master (target) that
286  //corresponds to this point (The box which centre is the closest to the point).
287  //Obtain the corresponding element number using the box id and box_to_convex
288  //indices. Compute deformed nodes of the target element. Invert the geometric
289  //transformation of the target element with deformed nodes, obtaining this way
290  //reference coordinates of the target element
291  auto bset = rtree::pbox_set{};
292  element_boxes.find_boxes_at_point(pt_x, bset);
293  while (!bset.empty())
294  {
295  auto itmax = most_central_box(bset, pt_x);
296  cv = box_to_convex[(*itmax)->id];
297  auto deformed_nodes_y = deformed_master_nodes(cv);
298  gic.init(deformed_nodes_y, target_mesh.trans_of_convex(cv));
299  auto converged = true;
300  auto is_in = gic.invert(pt_x, P_ref, converged);
301  if (is_in && converged) {
302  face_num = static_cast<short_type>(-1);
303  transformation_success = true;
304  break;
305  }
306  if (bset.size() == 1) break;
307  bset.erase(itmax);
308  }
309 
310  //Since this transformation can be seen as Xsource + Usource - Utarget,
311  //the corresponding stiffnesses are identity matrix for Usource and
312  //minus identity for Utarget. The required answer in this function is
313  //stiffness X shape function. Hence, returning shape function for Usource
314  //and min shape function for Utarget
315  if (compute_derivatives && transformation_success) {
316  GMM_ASSERT2(derivatives.size() == 2,
317  "Expecting to return derivatives only for Umaster and Uslave");
318 
319  for (auto &pair : derivatives)
320  {
321  if (pair.first.varname == slave.dispname)
322  {
323  auto base_ux = base_tensor{};
324  auto vbase_ux = base_matrix{} ;
325  ctx_x.base_value(base_ux);
326  auto qdim_ux = pfu_x->target_dim();
327  auto ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
328  vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
329  pair.second.adjust_sizes(ndof_ux, N);
330  copy(vbase_ux.as_vector(), pair.second.as_vector());
331  }
332  else
333  if (pair.first.varname == master.dispname)
334  {
335  auto ctx_y = deformed_master_context(cv);
336  ctx_y.set_xref(P_ref);
337  auto base_uy = base_tensor{};
338  auto vbase_uy = base_matrix{} ;
339  ctx_y.base_value(base_uy);
340  auto pfu_y = master.mfu->fem_of_element(cv);
341  auto dim_y = master.mfu->linked_mesh().dim();
342  auto qdim_uy = pfu_y->target_dim();
343  auto ndof_uy = pfu_y->nb_dof(cv) * dim_y / qdim_uy;
344  vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, dim_y);
345  pair.second.adjust_sizes(ndof_uy, dim_y);
346  copy(vbase_uy.as_vector(), pair.second.as_vector());
347  scale(pair.second.as_vector(), -1.);
348  }
349  else GMM_ASSERT2(false, "unexpected derivative variable");
350  }
351  }
352 
353  return transformation_success ? 1 : 0;
354  }
355 
356 };
357 
359  (ga_workspace &workspace, const std::string &transname,
360  const mesh &source_mesh, const std::string &source_displacements,
361  const mesh_region &source_region, const mesh &target_mesh,
362  const std::string &target_displacements, const mesh_region &target_region)
363  {
364  auto pmf_source = workspace.associated_mf(source_displacements);
365  auto pmf_target = workspace.associated_mf(target_displacements);
366  auto p_transformation
367  = std::make_shared<interpolate_transformation_on_deformed_domains>(source_region.id(),
368  *pmf_source,
369  source_displacements,
370  target_region.id(),
371  *pmf_target,
372  target_displacements);
373  workspace.add_interpolate_transformation(transname, p_transformation);
374  }
375 
377  (model &md, const std::string &transname,
378  const mesh &source_mesh, const std::string &source_displacements,
379  const mesh_region &source_region, const mesh &target_mesh,
380  const std::string &target_displacements, const mesh_region &target_region)
381  {
382  auto &mf_source = md.mesh_fem_of_variable(source_displacements);
383  auto mf_target = md.mesh_fem_of_variable(target_displacements);
384  auto p_transformation
385  = std::make_shared<interpolate_transformation_on_deformed_domains>(source_region.id(),
386  mf_source,
387  source_displacements,
388  target_region.id(),
389  mf_target,
390  target_displacements);
391  md.add_interpolate_transformation(transname, p_transformation);
392  }
393 
394 } /* end of namespace getfem. */
structure used to hold a set of convexes and/or convex faces.
void add_interpolate_transformation_on_deformed_domains(ga_workspace &workspace, const std::string &transname, const mesh &source_mesh, const std::string &source_displacements, const mesh_region &source_region, const mesh &target_mesh, const std::string &target_displacements, const mesh_region &target_region)
Add a transformation to the workspace that creates an identity mapping between two meshes in deformed...
void slice_vector_on_basic_dof_of_element(const mesh_fem &mf, const VEC1 &vec, size_type cv, VEC2 &coeff, size_type qmult1=size_type(-1), size_type qmult2=size_type(-1))
Given a mesh_fem.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:95
does the inversion of the geometric transformation for a given convex
const mesh_fem & mesh_fem_of_variable(const std::string &name) const
Gives the access to the mesh_fem of a variable if any.
``Model&#39;&#39; variables store the variables, the data and the description of a model. ...
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
void copy(const L1 &l1, L2 &l2)
*/
Definition: gmm_blas.h:977
Model representation in Getfem.
bool invert(const base_node &n, base_node &n_ref, scalar_type IN_EPS=1e-12)
given the node on the real element, returns the node on the reference element (even if it is outside ...
"iterator" class for regions.
void add_interpolate_transformation(const std::string &name, pinterpolate_transformation ptrans)
Add a interpolate transformation to the model to be used with the generic assembly.
A langage for generic assembly of pde boundary value problems.
GEneric Tool for Finite Element Methods.
Describe a finite element method linked to a mesh.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
Basic Geometric Tools.
Balanced tree of n-dimensional rectangles.
Definition: bgeot_rtree.h:66
void resize(M &v, size_type m, size_type n)
*/
Definition: gmm_blas.h:231
void add(const L1 &l1, L2 &l2)
*/
Definition: gmm_blas.h:1268