GetFEM  5.4.3
getfem_projected_fem.cc
1 /*===========================================================================
2 
3  Copyright (C) 2012-2020 Yves Renard, Konstantinos Poulios
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 
24 namespace getfem {
25 
26  typedef bgeot::convex<base_node>::dref_convex_pt_ct dref_convex_pt_ct;
27 // typedef bgeot::basic_mesh::ref_mesh_face_pt_ct ref_mesh_face_pt_ct;
28 
29  /* calculates the projection of a point on the face of a convex
30  * Input:
31  * pgt : the geometric transformation of the convex
32  * G_cv: the nodes of the convex, stored in columns
33  * fc : the face of the convex to project on
34  * pt : the point to be projected
35  * Output:
36  * proj_ref: the projected point in the reference element
37  * proj : the projected point in the real element
38  */
39  void projection_on_convex_face
40  (const bgeot::pgeometric_trans pgt, const base_matrix &G_cv,
41  const short_type fc, const base_node &pt,
42  base_node &proj_ref, base_node &proj) {
43 
44  size_type N = gmm::mat_nrows(G_cv); // dimension of the target space
45  size_type P = pgt->dim(); // dimension of the reference element space
46 
47  size_type nb_pts_cv = gmm::mat_ncols(G_cv);
48  size_type nb_pts_fc = pgt->structure()->nb_points_of_face(fc);
49 
50  GMM_ASSERT1( N == pt.size(), "Dimensions mismatch");
51  GMM_ASSERT1( nb_pts_cv == pgt->nb_points(), "Dimensions mismatch");
52 
53  bgeot::convex_ind_ct ind_pts_fc = pgt->structure()->ind_points_of_face(fc);
54 
55  base_matrix G_fc(N, nb_pts_fc);
56  for (size_type i=0; i < nb_pts_fc; i++)
57  gmm::copy(gmm::mat_col(G_cv,ind_pts_fc[i]),gmm::mat_col(G_fc,i));
58 
59  // Local base on reference face
60  base_matrix base_ref_fc(P,P-1);
61  {
62  dref_convex_pt_ct dref_pts_fc = pgt->convex_ref()->dir_points_of_face(fc);
63  GMM_ASSERT1( dref_pts_fc.size() == P, "Dimensions mismatch");
64  for (size_type i = 0; i < P-1; ++i)
65  gmm::copy(dref_pts_fc[i+1] - dref_pts_fc[0], gmm::mat_col(base_ref_fc,i));
66  }
67 
68  proj_ref.resize(P);
69  proj.resize(N);
70 
71  base_node vres(P); // residual vector
72  scalar_type res= 1.;
73 
74  // initial guess
75  proj_ref = gmm::mean_value(pgt->convex_ref()->points_of_face(fc));
76 
77  base_vector val(nb_pts_fc);
78  pgt->poly_vector_val(proj_ref, ind_pts_fc, val);
79  gmm::mult(G_fc, val, proj);
80 
81  base_matrix K(N,P-1);
82 
83  base_matrix grad_fc(nb_pts_fc, P);
84  base_matrix grad_fc1(nb_pts_fc, P-1);
85  base_matrix B(N,P-1), BB(N,P), CS(P-1,P-1);
86 
87  scalar_type EPS = 10E-12;
88  unsigned cnt = 50;
89  while (res > EPS && --cnt) {
90  // computation of the pseudo inverse matrix B at point proj_ref
91  pgt->poly_vector_grad(proj_ref, ind_pts_fc, grad_fc);
92  gmm::mult(grad_fc, base_ref_fc, grad_fc1);
93  gmm::mult(G_fc, grad_fc1, K);
94  gmm::mult(gmm::transposed(K), K, CS);
95  gmm::lu_inverse(CS);
96  gmm::mult(K, CS, B);
97  gmm::mult(B, gmm::transposed(base_ref_fc), BB);
98 
99  // Projection onto the face of the convex
100  gmm::mult_add(gmm::transposed(BB), pt - proj, proj_ref);
101  pgt->poly_vector_val(proj_ref, ind_pts_fc, val);
102  gmm::mult(G_fc, val, proj);
103 
104  gmm::mult(gmm::transposed(BB), pt - proj, vres);
105  res = gmm::vect_norm2(vres);
106  }
107  GMM_ASSERT1( res <= EPS,
108  "Iterative pojection on convex face did not converge");
109  pgt->project_into_reference_convex(proj_ref);
110  pgt->poly_vector_val(proj_ref, ind_pts_fc, val);
111  gmm::mult(G_fc, val, proj);
112  }
113 
114 
115  /* calculates the normal at a specific point on the face of a convex
116  * Input:
117  * pgt : the geometric transformation of the convex
118  * G_cv : the nodes of the convex, stored in columns
119  * fc : the face of the convex to project on
120  * ref_pt: the point in the reference element
121  * Output:
122  * normal: the surface normal in the real element corresponding at
123  * the location of ref_pt in the reference element
124  */
125  void normal_on_convex_face
126  (const bgeot::pgeometric_trans pgt, const base_matrix &G_cv,
127  const short_type fc, const base_node &ref_pt, base_node &normal) {
128 
129  size_type N = gmm::mat_nrows(G_cv); // dimension of the target space
130  size_type P = pgt->dim(); // dimension of the reference element space
131 
132  size_type nb_pts_cv = gmm::mat_ncols(G_cv);
133  size_type nb_pts_fc = pgt->structure()->nb_points_of_face(fc);
134 
135  GMM_ASSERT1( nb_pts_cv == pgt->nb_points(), "Dimensions mismatch");
136 
137  bgeot::convex_ind_ct ind_pts_fc = pgt->structure()->ind_points_of_face(fc);
138 
139  base_matrix G_fc(N, nb_pts_fc);
140  for (size_type i=0; i < nb_pts_fc; i++)
141  gmm::copy(gmm::mat_col(G_cv,ind_pts_fc[i]),gmm::mat_col(G_fc,i));
142 
143  // Local base on reference face
144  base_matrix base_ref_fc(P,P-1);
145  {
146  dref_convex_pt_ct dref_pts_fc = pgt->convex_ref()->dir_points_of_face(fc);
147  GMM_ASSERT1( dref_pts_fc.size() == P, "Dimensions mismatch");
148  for (size_type i = 0; i < P-1; ++i)
149  gmm::copy(dref_pts_fc[i+1] - dref_pts_fc[0], gmm::mat_col(base_ref_fc,i));
150  }
151 
152  normal.resize(N);
153 
154  base_matrix K(N,P-1);
155  { // calculate K at the final point
156  base_matrix grad_fc(nb_pts_fc, P);
157  base_matrix grad_fc1(nb_pts_fc, P-1);
158  pgt->poly_vector_grad(ref_pt, ind_pts_fc, grad_fc);
159  gmm::mult(grad_fc, base_ref_fc, grad_fc1);
160  gmm::mult(G_fc, grad_fc1, K);
161  }
162 
163  base_matrix KK(N,P);
164  { // calculate KK
165  base_matrix grad_cv(nb_pts_cv, P);
166  pgt->poly_vector_grad(ref_pt, grad_cv);
167  gmm::mult(G_cv, grad_cv, KK);
168  }
169 
170  base_matrix bases_product(P-1, P);
171  gmm::mult(gmm::transposed(K), KK, bases_product);
172 
173  for (size_type i = 0; i < P; ++i) {
174  std::vector<size_type> ind(0);
175  for (size_type j = 0; j < P; ++j)
176  if (j != i ) ind.push_back(j);
177  scalar_type det = gmm::lu_det(gmm::sub_matrix(bases_product,
178  gmm::sub_interval(0, P-1),
179  gmm::sub_index(ind) ) );
180  gmm::add(gmm::scaled(gmm::mat_col(KK, i), (i % 2) ? -det : +det ), normal);
181  }
182 
183  // normalizing
184  gmm::scale(normal, 1/gmm::vect_norm2(normal));
185 
186  // ensure that normal points outwards
187  base_node cv_center(N), fc_center(N);
188  for (size_type i=0; i < nb_pts_cv; i++)
189  gmm::add(gmm::mat_col(G_cv,i), cv_center);
190  for (size_type i=0; i < nb_pts_fc; i++)
191  gmm::add(gmm::mat_col(G_fc,i), fc_center);
192  gmm::scale(cv_center, scalar_type(1)/scalar_type(nb_pts_cv));
193  gmm::scale(fc_center, scalar_type(1)/scalar_type(nb_pts_fc));
194  if (gmm::vect_sp(normal, fc_center -cv_center) < 0)
195  gmm::scale(normal, scalar_type(-1));
196  }
197 
198  /* calculates the normal at a specific point of a convex in a higher
199  * dimension space
200  * Input:
201  * pgt : the geometric transformation of the convex
202  * G_cv : the nodes of the convex, stored in columns
203  * ref_pt: the point in the reference element
204  * Output:
205  * normal: the surface normal in the real element corresponding at
206  * the location of ref_pt in the reference element
207  * (or one of the possible normals if the space dimension
208  * is more than one higher than the convex dimension)
209  */
210  void normal_on_convex
211  (const bgeot::pgeometric_trans pgt, const base_matrix &G_cv,
212  const base_node &ref_pt, base_node &normal) {
213 
214  size_type N = gmm::mat_nrows(G_cv); // dimension of the target space
215  size_type P = pgt->dim(); // dimension of the reference element space
216 
217  GMM_ASSERT1( N == 2 || N == 3, "Normal on convexes calculation is supported "
218  "only for space dimension equal to 2 or 3.");
219  GMM_ASSERT1( P < N, "Normal on convex is defined only in a space of"
220  "higher dimension.");
221 
222  size_type nb_pts = gmm::mat_ncols(G_cv);
223  base_matrix K(N,P);
224  { // calculate K at the final point
225  base_matrix grad_cv(nb_pts, P);
226  pgt->poly_vector_grad(ref_pt, grad_cv);
227  gmm::mult(G_cv, grad_cv, K);
228  }
229 
230  gmm::resize(normal,N);
231  if (P==1 && N == 2) {
232  normal[0] = -K(1,0);
233  normal[1] = K(0,0);
234  }
235  else if (P==1 && N == 3) {
236  normal[0] = K(2,0)-K(1,0);
237  normal[1] = K(0,0)-K(2,0);
238  normal[2] = K(1,0)-K(0,0);
239  }
240  else if (P==2) {
241  normal[0] = K(1,0)*K(2,1)-K(2,0)*K(1,1);
242  normal[1] = K(2,0)*K(0,1)-K(0,0)*K(2,1);
243  normal[2] = K(0,0)*K(1,1)-K(1,0)*K(0,1);
244  }
245  gmm::scale(normal, 1/gmm::vect_norm2(normal));
246  }
247 
248  void projected_fem::build_kdtree(void) const {
249  tree.clear();
250  dal::bit_vector dofs=mf_source.basic_dof_on_region(rg_source);
251  dofs.setminus(blocked_dofs);
252  dim_type qdim=target_dim();
253  for (dal::bv_visitor dof(dofs); !dof.finished(); ++dof)
254  if (dof % qdim == 0)
255  tree.add_point_with_id(mf_source.point_of_basic_dof(dof), dof);
256  }
257 
258  bool projected_fem::find_a_projected_point(const base_node &pt, base_node &ptr_proj,
259  size_type &cv_proj, short_type &fc_proj) const {
260 
262  //scalar_type dist =
263  tree.nearest_neighbor(ipt, pt);
264 
265  size_type cv_sel = size_type(-1);
266  short_type fc_sel = short_type(-1);
267  scalar_type dist_sel(1e10);
268  base_node proj_ref, proj_ref_sel, proj, proj_sel;
269  const getfem::mesh::ind_cv_ct cvs = mf_source.convex_to_basic_dof(ipt.i);
270  for (size_type i=0; i < cvs.size(); ++i) {
271  size_type cv = cvs[i];
272  const bgeot::pgeometric_trans pgt = mf_source.linked_mesh().trans_of_convex(cv);
273  if (rg_source.is_in(cv)) { // project on the convex
274  bool gt_invertible;
275  gic = bgeot::geotrans_inv_convex(mf_source.linked_mesh().convex(cv), pgt);
276  gic.invert(pt, proj_ref, gt_invertible);
277  if (gt_invertible) {
278  pgt->project_into_reference_convex(proj_ref);
279  proj = pgt->transform(proj_ref, mf_source.linked_mesh().points_of_convex(cv));
280  scalar_type dist = gmm::vect_dist2(pt, proj);
281  if (dist < dist_sel) {
282  dist_sel = dist;
283  cv_sel = cv;
284  fc_sel = short_type(-1);
285  proj_ref_sel = proj_ref;
286  }
287  }
288  }
289  else { // project on convex faces
290  mesh_region::face_bitset faces = rg_source.faces_of_convex(cv);
291  if (faces.count() > 0) { // this should rarely be more than one face
292  mf_source.linked_mesh().points_of_convex(cv, G);
293  short_type nbf = mf_source.linked_mesh().nb_faces_of_convex(cv);
294  for (short_type f = 0; f < nbf; ++f) {
295  if (faces.test(f)) {
296  projection_on_convex_face(pgt, G, f, pt, proj_ref, proj);
297  scalar_type dist = gmm::vect_dist2(pt, proj);
298  if (dist < dist_sel) {
299  dist_sel = dist;
300  cv_sel = cv;
301  fc_sel = f;
302  proj_ref_sel = proj_ref;
303  proj_sel = proj;
304  }
305  }
306  }
307  }
308  }
309  }
310  if (cv_sel != size_type(-1)) {
311  scalar_type elm_size = mf_source.linked_mesh().convex_radius_estimate(cv_sel);
312  if (dist_sel < 0.05*elm_size) { //FIXME
313  cv_proj = cv_sel;
314  fc_proj = fc_sel;
315  ptr_proj = proj_ref_sel;
316  return true;
317  }
318  }
319  return false;
320  }
321 
323  fictx_cv = size_type(-1);
324  dim_ = dim_type(-1);
325 
326  dim_type N = mf_source.linked_mesh().dim();
327  GMM_ASSERT1( N == mim_target.linked_mesh().dim(),
328  "Dimensions mismatch between the source and the target meshes");
329 
330  build_kdtree();
331 
332  elements.clear();
333  ind_dof.resize(mf_source.nb_basic_dof());
334  std::fill(ind_dof.begin(), ind_dof.end(), size_type(-1));
335  size_type max_dof = 0;
336  if (rg_target.id() != mesh_region::all_convexes().id() &&
337  rg_target.is_empty()) {
338  dim_ = mim_target.linked_mesh().dim();
339  return;
340  }
341 
342  for (mr_visitor i(rg_target); !i.finished(); ++i) {
343  size_type cv = i.cv(); // refers to the target mesh
344  short_type f = i.f(); // refers to the target mesh
345 
346  dim_type dim__ = mim_target.linked_mesh().structure_of_convex(cv)->dim();
347  if (dim_ == dim_type(-1)) {
348  dim_ = dim__;
349  if (i.is_face()) dim__ = dim_type(dim__ - 1);
350  GMM_ASSERT1(dim__ < N, "The projection should take place in lower "
351  "dimensions than the mesh dimension. Otherwise "
352  "use the interpolated_fem object instead.");
353  }
354  else
355  GMM_ASSERT1(dim_ == dim__,
356  "Convexes/faces of different dimension in the target mesh");
357 
358  pintegration_method pim = mim_target.int_method_of_element(cv);
359  GMM_ASSERT1(pim->type() == IM_APPROX,
360  "You have to use approximated integration to project a fem");
361  papprox_integration pai = pim->approx_method();
362  bgeot::pgeometric_trans pgt = mim_target.linked_mesh().trans_of_convex(cv);
363  bgeot::pgeotrans_precomp pgp =
364  bgeot::geotrans_precomp(pgt, pai->pintegration_points(), 0);
365  size_type last_cv = size_type(-1); // refers to the source mesh
366  short_type last_f = short_type(-1); // refers to the source mesh
367  size_type nb_pts = i.is_face() ? pai->nb_points_on_face(f)
368  : pai->nb_points_on_convex();
369  size_type start_pt = i.is_face() ? pai->ind_first_point_on_face(f) : 0;
370  elt_projection_data &e = elements[cv];
371  base_node gpt(N);
372  dal::bit_vector new_dofs;
373  for (size_type k = 0; k < nb_pts; ++k) {
374  pgp->transform(mim_target.linked_mesh().points_of_convex(cv),
375  start_pt + k, gpt);
376  gausspt_projection_data &gppd = e.gausspt[start_pt + k];
377  gppd.iflags = find_a_projected_point(gpt, gppd.ptref, gppd.cv, gppd.f) ? 1 : 0;
378  if (gppd.iflags) {
379  // calculate gppd.normal
380  const bgeot::pgeometric_trans pgt_source = mf_source.linked_mesh().trans_of_convex(gppd.cv);
381  mf_source.linked_mesh().points_of_convex(gppd.cv, G);
382  if (gppd.f != short_type(-1))
383  normal_on_convex_face(pgt_source, G, gppd.f, gppd.ptref, gppd.normal);
384  else
385  normal_on_convex(pgt_source, G, gppd.ptref, gppd.normal);
386  // calculate gppd.gap
387  base_node ppt = pgt_source->transform(gppd.ptref, G);
388  gppd.gap = gmm::vect_sp(gpt-ppt, gppd.normal);
389  }
390 
391  if (gppd.iflags && (last_cv != gppd.cv || last_f != gppd.f)) {
392  if (gppd.f == short_type(-1)) { // convex
393  size_type nbdof = mf_source.nb_basic_dof_of_element(gppd.cv);
394  for (size_type loc_dof = 0; loc_dof < nbdof; ++loc_dof) {
395  size_type dof = mf_source.ind_basic_dof_of_element(gppd.cv)[loc_dof];
396  if (!(blocked_dofs[dof]))
397  new_dofs.add(dof);
398  }
399  }
400  else { // convex face
401  size_type nbdof = mf_source.nb_basic_dof_of_face_of_element(gppd.cv, gppd.f);
402  for (size_type loc_dof = 0; loc_dof < nbdof; ++loc_dof) {
403  size_type dof = mf_source.ind_basic_dof_of_face_of_element(gppd.cv, gppd.f)[loc_dof];
404  if (!(blocked_dofs[dof]))
405  new_dofs.add(dof);
406  }
407  }
408  last_cv = gppd.cv;
409  last_f = gppd.f;
410  }
411  }
412 
413  size_type cnt(0);
414  dal::bit_vector old_dofs;
415  for (const size_type dof : e.inddof) {
416  old_dofs.add(dof);
417  ind_dof[dof] = cnt++;
418  }
419  for (dal::bv_visitor dof(new_dofs); !dof.finished(); ++dof)
420  if (!(old_dofs[dof])) {
421  ind_dof[dof] = cnt++;
422  e.inddof.push_back(dof);
423  }
424 
425  e.pim = pim;
426  e.nb_dof = e.inddof.size();
427  max_dof = std::max(max_dof, e.nb_dof);
428  for (size_type k = 0; k < nb_pts; ++k) {
429  gausspt_projection_data &gppd = e.gausspt[start_pt + k];
430  if (gppd.iflags) {
431  if (gppd.f == short_type(-1)) { // convex
432  size_type nbdof = mf_source.nb_basic_dof_of_element(gppd.cv);
433  for (size_type loc_dof = 0; loc_dof < nbdof; ++loc_dof) {
434  size_type dof = mf_source.ind_basic_dof_of_element(gppd.cv)[loc_dof];
435  gppd.local_dof[loc_dof] = new_dofs.is_in(dof) ? ind_dof[dof]
436  : size_type(-1);
437  }
438  }
439  else { // convex face
440  size_type nbdof = mf_source.nb_basic_dof_of_face_of_element(gppd.cv, gppd.f);
441  pfem pf = mf_source.fem_of_element(gppd.cv);
442  bgeot::convex_ind_ct ind_pts_fc = pf->structure(gppd.cv)->ind_points_of_face(gppd.f);
443  unsigned rdim = target_dim() / pf->target_dim();
444  if (rdim == 1)
445  for (size_type loc_dof = 0; loc_dof < nbdof; ++loc_dof) { // local dof with respect to the source convex face
446  size_type dof = mf_source.ind_basic_dof_of_face_of_element(gppd.cv, gppd.f)[loc_dof];
447  size_type loc_dof2 = ind_pts_fc[loc_dof]; // local dof with respect to the source convex
448  gppd.local_dof[loc_dof2] = new_dofs.is_in(dof) ? ind_dof[dof]
449  : size_type(-1);
450  }
451  else
452  for (size_type ii = 0; ii < nbdof/rdim; ++ii)
453  for (size_type jj = 0; jj < rdim; ++jj) {
454  size_type loc_dof = ii*rdim + jj; // local dof with respect to the source convex face
455  size_type dof = mf_source.ind_basic_dof_of_face_of_element(gppd.cv, gppd.f)[loc_dof];
456  size_type loc_dof2 = ind_pts_fc[ii]*rdim + jj; // local dof with respect to the source convex
457  gppd.local_dof[loc_dof2] = new_dofs.is_in(dof) ? ind_dof[dof]
458  : size_type(-1);
459  }
460  }
461  }
462  }
463 
464  for (const size_type dof : e.inddof)
465  ind_dof[dof] = size_type(-1);
466 
467  }
468  /** setup global dofs, with dummy coordinates */
469  base_node P(dim()); gmm::fill(P,1./20);
470  std::vector<base_node> node_tab_(max_dof, P);
471  pspt_override = bgeot::store_point_tab(node_tab_);
472  pspt_valid = false;
473  dof_types_.resize(max_dof);
474  std::fill(dof_types_.begin(), dof_types_.end(),
475  global_dof(dim()));
476 
477  /* ind_dof should be kept filled with -1 ( real_base_value and
478  grad_base_value expect that)
479  */
480  std::fill(ind_dof.begin(), ind_dof.end(), size_type(-1));
481  }
482 
484  {
485  context_check();
486  GMM_ASSERT1(mim_target.linked_mesh().convex_index().is_in(cv),
487  "Wrong convex number: " << cv);
488  std::map<size_type,elt_projection_data>::const_iterator eit;
489  eit = elements.find(cv);
490  return (eit != elements.end()) ? eit->second.nb_dof : 0;
491  }
492 
493  size_type projected_fem::index_of_global_dof(size_type cv, size_type i) const
494  {
495  std::map<size_type,elt_projection_data>::const_iterator eit;
496  eit = elements.find(cv);
497  GMM_ASSERT1(eit != elements.end(), "Wrong convex number: " << cv);
498  return eit->second.inddof[i];
499  }
500 
501  bgeot::pconvex_ref projected_fem::ref_convex(size_type cv) const
502  { return mim_target.int_method_of_element(cv)->approx_method()->ref_convex(); }
503 
505  {
506  GMM_ASSERT1(mim_target.linked_mesh().convex_index().is_in(cv),
507  "Wrong convex number: " << cv);
509  (dim(), nb_dof(cv),
510  mim_target.linked_mesh().structure_of_convex(cv)->nb_faces()));
511  }
512 
513  void projected_fem::base_value(const base_node &, base_tensor &) const
514  { GMM_ASSERT1(false, "No base values, real only element."); }
515  void projected_fem::grad_base_value(const base_node &,
516  base_tensor &) const
517  { GMM_ASSERT1(false, "No grad values, real only element."); }
518  void projected_fem::hess_base_value(const base_node &,
519  base_tensor &) const
520  { GMM_ASSERT1(false, "No hess values, real only element."); }
521 
522  inline void projected_fem::actualize_fictx(pfem pf, size_type cv,
523  const base_node &ptr) const {
524  if (fictx_cv != cv) {
525  mf_source.linked_mesh().points_of_convex(cv, G);
527  (mf_source.linked_mesh().trans_of_convex(cv), pf, base_node(), G, cv);
528  fictx_cv = cv;
529  }
530  fictx.set_xref(ptr);
531  }
532 
534  base_tensor &t, bool) const {
535  std::map<size_type,elt_projection_data>::iterator eit;
536  eit = elements.find(c.convex_num());
537  if (eit == elements.end()) {
538  mi2[1] = target_dim();
539  mi2[0] = short_type(0);
540  t.adjust_sizes(mi2);
541  std::fill(t.begin(), t.end(), scalar_type(0));
542  return;
543  }
544 // GMM_ASSERT1(eit != elements.end(), "Wrong convex number: " << c.convex_num());
545  elt_projection_data &e = eit->second;
546 
547  mi2[1] = target_dim();
548  mi2[0] = short_type(e.nb_dof);
549  t.adjust_sizes(mi2);
550  std::fill(t.begin(), t.end(), scalar_type(0));
551  if (e.nb_dof == 0) return;
552 
553  std::map<size_type,gausspt_projection_data>::iterator git;
554  git = e.gausspt.find(c.ii());
555  if (c.have_pgp() &&
556  (c.pgp()->get_ppoint_tab()
557  == e.pim->approx_method()->pintegration_points()) &&
558  git != e.gausspt.end()) {
559  gausspt_projection_data &gppd = git->second;
560  if (gppd.iflags & 1) {
561  if (gppd.iflags & 2) {
562  t = gppd.base_val;
563  return;
564  }
565  size_type cv = gppd.cv;
566  pfem pf = mf_source.fem_of_element(cv);
567  actualize_fictx(pf, cv, gppd.ptref);
568  pf->real_base_value(fictx, taux);
569  unsigned rdim = target_dim() / pf->target_dim();
570  std::map<size_type,size_type>::const_iterator ii;
571  if (rdim == 1) // mdim == 0
572  for (size_type i = 0; i < pf->nb_dof(cv); ++i) {
573  ii = gppd.local_dof.find(i);
574  if (ii != gppd.local_dof.end() && ii->second != size_type(-1))
575  for (size_type j = 0; j < target_dim(); ++j)
576  t(ii->second,j) = taux(i,j);
577  }
578  else // mdim == 1
579  for (size_type i = 0; i < pf->nb_dof(cv); ++i)
580  for (size_type j = 0; j < target_dim(); ++j) {
581  ii = gppd.local_dof.find(i*rdim+j);
582  if (ii != gppd.local_dof.end() && ii->second != size_type(-1))
583  t(ii->second,j) = taux(i,0);
584  }
585 
586  if (store_values) {
587  gppd.base_val = t;
588  gppd.iflags |= 2;
589  }
590  }
591  }
592  else {
593  size_type cv;
594  short_type f;
595  if (find_a_projected_point(c.xreal(), ptref, cv, f)) {
596  pfem pf = mf_source.fem_of_element(cv);
597  actualize_fictx(pf, cv, ptref);
598  pf->real_base_value(fictx, taux);
599 
600  for (size_type i = 0; i < e.nb_dof; ++i)
601  ind_dof.at(e.inddof[i]) = i;
602 
603  unsigned rdim = target_dim() / pf->target_dim();
604  if (rdim == 1) // mdim == 0
605  for (size_type i = 0; i < pf->nb_dof(cv); ++i) {
606  size_type ii = ind_dof.at(mf_source.ind_basic_dof_of_element(cv)[i]);
607  if (ii != size_type(-1)) {
608  for (size_type j = 0; j < target_dim(); ++j)
609  t(ii,j) = taux(i,j);
610  }
611  }
612  else // mdim == 1
613  for (size_type i = 0; i < pf->nb_dof(cv); ++i)
614  for (size_type j = 0; j < target_dim(); ++j) {
615  size_type ij = ind_dof.at(mf_source.ind_basic_dof_of_element(cv)[i*rdim+j]);
616  if (ij != size_type(-1))
617  t(ij,j) = taux(i,0);
618  }
619 
620  for (size_type i = 0; i < e.nb_dof; ++i)
621  ind_dof[e.inddof[i]] = size_type(-1);
622  }
623  }
624 
625  }
626 
628  base_tensor &t, bool) const {
629  std::map<size_type,elt_projection_data>::iterator eit;
630  eit = elements.find(c.convex_num());
631  if (eit == elements.end()) {
632  mi3[2] = mf_source.linked_mesh().dim();
633  mi3[1] = target_dim();
634  mi3[0] = short_type(0);
635  t.adjust_sizes(mi3);
636  std::fill(t.begin(), t.end(), scalar_type(0));
637  return;
638  }
639 // GMM_ASSERT1(eit != elements.end(), "Wrong convex number: " << c.convex_num());
640  elt_projection_data &e = eit->second;
641 
642  size_type N = mf_source.linked_mesh().dim();
643  mi3[2] = short_type(N);
644  mi3[1] = target_dim();
645  mi3[0] = short_type(e.nb_dof);
646  t.adjust_sizes(mi3);
647  std::fill(t.begin(), t.end(), scalar_type(0));
648  if (e.nb_dof == 0) return;
649 
650  std::map<size_type,gausspt_projection_data>::iterator git;
651  git = e.gausspt.find(c.ii());
652  if (c.have_pgp() &&
653  (c.pgp()->get_ppoint_tab()
654  == e.pim->approx_method()->pintegration_points()) &&
655  git != e.gausspt.end()) {
656  gausspt_projection_data &gppd = git->second;
657  if (gppd.iflags & 1) {
658  if (gppd.iflags & 4) {
659  t = gppd.grad_val;
660  return;
661  }
662  size_type cv = gppd.cv;
663  pfem pf = mf_source.fem_of_element(cv);
664  actualize_fictx(pf, cv, gppd.ptref);
665  pf->real_grad_base_value(fictx, taux);
666 
667  unsigned rdim = target_dim() / pf->target_dim();
668  std::map<size_type,size_type>::const_iterator ii;
669  if (rdim == 1) // mdim == 0
670  for (size_type i = 0; i < pf->nb_dof(cv); ++i) {
671  ii = gppd.local_dof.find(i);
672  if (ii != gppd.local_dof.end() && ii->second != size_type(-1))
673  for (size_type j = 0; j < target_dim(); ++j)
674  for (size_type k = 0; k < N; ++k)
675  t(ii->second, j, k) = taux(i, j, k);
676  }
677  else // mdim == 1
678  for (size_type i = 0; i < pf->nb_dof(cv); ++i)
679  for (size_type j = 0; j < target_dim(); ++j) {
680  ii = gppd.local_dof.find(i*rdim+j);
681  if (ii != gppd.local_dof.end() && ii->second != size_type(-1))
682  for (size_type k = 0; k < N; ++k)
683  t(ii->second, j, k) = taux(i, 0, k);
684  }
685  if (store_values) {
686  gppd.grad_val = t;
687  gppd.iflags |= 4;
688  }
689  }
690  }
691  else {
692  size_type cv;
693  short_type f;
694  if (find_a_projected_point(c.xreal(), ptref, cv, f)) {
695  pfem pf = mf_source.fem_of_element(cv);
696  actualize_fictx(pf, cv, ptref);
697  pf->real_grad_base_value(fictx, taux);
698  for (size_type i = 0; i < e.nb_dof; ++i)
699  ind_dof.at(e.inddof[i]) = i;
700 
701  unsigned rdim = target_dim() / pf->target_dim();
702  if (rdim == 1) // mdim == 0
703  for (size_type i = 0; i < pf->nb_dof(cv); ++i) {
704  size_type ii = ind_dof.at(mf_source.ind_basic_dof_of_element(cv)[i]);
705  if (ii != size_type(-1))
706  for (size_type j = 0; j < target_dim(); ++j)
707  for (size_type k = 0; k < N; ++k)
708  t(ii,j,k) = taux(i,j,k);
709  }
710  else // mdim == 1
711  for (size_type i = 0; i < pf->nb_dof(cv); ++i)
712  for (size_type j = 0; j < target_dim(); ++j) {
713  size_type ij = ind_dof.at(mf_source.ind_basic_dof_of_element(cv)[i*rdim+j]);
714  if (ij != size_type(-1))
715  for (size_type k = 0; k < N; ++k)
716  t(ij,j,k) = taux(i,0,k);
717  }
718 
719  for (size_type i = 0; i < e.nb_dof; ++i)
720  ind_dof[e.inddof[i]] = size_type(-1);
721  }
722  }
723  }
724 
726  (const fem_interpolation_context&, base_tensor &, bool) const
727  { GMM_ASSERT1(false, "Sorry, to be done."); }
728 
729  void projected_fem::projection_data(const fem_interpolation_context& c,
730  base_node &normal, scalar_type &gap) const {
731  std::map<size_type,elt_projection_data>::iterator eit;
732  eit = elements.find(c.convex_num());
733 
734  if (eit != elements.end()) {
735  elt_projection_data &e = eit->second;
736  if (e.nb_dof == 0) { // return undefined normal vector and huge gap
737  normal = base_node(c.N());
738  gap = 1e12;
739  return;
740  }
741  std::map<size_type,gausspt_projection_data>::iterator git;
742  git = e.gausspt.find(c.ii());
743  if (c.have_pgp() &&
744  (c.pgp()->get_ppoint_tab()
745  == e.pim->approx_method()->pintegration_points()) &&
746  git != e.gausspt.end()) {
747  gausspt_projection_data &gppd = git->second;
748  if (gppd.iflags & 1) {
749  normal = gppd.normal;
750  gap = gppd.gap;
751  }
752  else { // return undefined normal vector and huge gap
753  normal = base_node(c.N());
754  gap = 1e12;
755  }
756  return;
757  }
758  }
759 
760  // new projection
761  projection_data(c.xreal(), normal, gap);
762  }
763 
764  void projected_fem::projection_data(const base_node& pt,
765  base_node &normal, scalar_type &gap) const {
766  size_type cv;
767  short_type f;
768  if (find_a_projected_point(pt, ptref, cv, f)) {
769  const bgeot::pgeometric_trans pgt = mf_source.linked_mesh().trans_of_convex(cv);
770  mf_source.linked_mesh().points_of_convex(cv, G);
771  if (f != short_type(-1))
772  normal_on_convex_face(pgt, G, f, ptref, normal);
773  else
774  normal_on_convex(pgt, G, ptref, normal);
775  base_node ppt = pgt->transform(ptref, G);
776  gap = gmm::vect_sp(pt-ppt, normal);
777  }
778  else { // return undefined normal vector and huge gap
779  normal = base_node(pt.size());
780  gap = 1e12;
781  }
782 
783  }
784 
785  dal::bit_vector projected_fem::projected_convexes() const {
786  dal::bit_vector bv;
787  std::map<size_type,elt_projection_data>::const_iterator eit;
788  for (eit = elements.begin(); eit != elements.end(); ++eit) {
789  std::map<size_type,gausspt_projection_data>::const_iterator git;
790  for (git = eit->second.gausspt.begin(); git != eit->second.gausspt.end(); ++git) {
791  if (git->second.iflags)
792  bv.add(git->second.cv);
793  }
794  }
795  return bv;
796  }
797 
799  context_check();
800  mesh_region projected_target;
801  for (mr_visitor v(rg_target); !v.finished(); ++v) {
802  pintegration_method pim = mim_target.int_method_of_element(v.cv());
803  papprox_integration pai = pim->approx_method();
804  size_type start_pt = v.is_face() ? pai->ind_first_point_on_face(v.f()) : 0;
805  size_type nb_pts = v.is_face() ? pai->nb_points_on_face(v.f())
806  : pai->nb_points_on_convex();
807  bool isProjectedOn = false;
808  for (size_type ip = 0; ip != nb_pts; ++ip) {
809  auto &proj_data = elements.at(v.cv()).gausspt[start_pt + ip];
810  if (proj_data.iflags) {
811  isProjectedOn = true;
812  break;
813  }
814  }
815  if (isProjectedOn) projected_target.add(v.cv(), v.f());
816  }
817  return projected_target;
818  }
819 
820  void projected_fem::gauss_pts_stats(unsigned &ming, unsigned &maxg,
821  scalar_type &meang) const {
822  std::vector<unsigned> v(mf_source.linked_mesh().nb_allocated_convex());
823  std::map<size_type,elt_projection_data>::const_iterator eit;
824  for (eit = elements.begin(); eit != elements.end(); ++eit) {
825  std::map<size_type,gausspt_projection_data>::const_iterator git;
826  for (git = eit->second.gausspt.begin(); git != eit->second.gausspt.end(); ++git) {
827  if (git->second.iflags)
828  v[git->second.cv]++;
829  }
830  }
831 
832  ming = 100000; maxg = 0; meang = 0;
833  unsigned cntg = 0;
834  for (dal::bv_visitor cv(mf_source.linked_mesh().convex_index());
835  !cv.finished(); ++cv) {
836  ming = std::min(ming, v[cv]);
837  maxg = std::max(maxg, v[cv]);
838  meang += v[cv];
839  if (v[cv] > 0) ++cntg;
840  }
841  meang /= scalar_type(cntg);
842  }
843 
844  size_type projected_fem::memsize() const {
845  size_type sz = 0;
846  sz += blocked_dofs.memsize();
847  sz += sizeof(*this);
848  sz += elements.size() * sizeof(elt_projection_data); // Wrong for std::map
849  std::map<size_type,elt_projection_data>::const_iterator eit;
850  for (eit = elements.begin(); eit != elements.end(); ++eit) {
851  sz += eit->second.gausspt.size() * sizeof(gausspt_projection_data); // Wrong for std::map
852  sz += eit->second.inddof.capacity() * sizeof(size_type);
853  std::map<size_type,gausspt_projection_data>::const_iterator git;
854  for (git = eit->second.gausspt.begin(); git != eit->second.gausspt.end(); ++git) {
855  sz += git->second.local_dof.size() * sizeof(size_type); // Wrong for std::map
856  }
857  }
858  return sz;
859  }
860 
861  projected_fem::projected_fem(const mesh_fem &mf_source_,
862  const mesh_im &mim_target_,
863  size_type rg_source_,
864  size_type rg_target_,
865  dal::bit_vector blocked_dofs_, bool store_val)
866  : mf_source(mf_source_), mim_target(mim_target_),
867  rg_source(mf_source.linked_mesh().region(rg_source_)),
868  rg_target(mim_target.linked_mesh().region(rg_target_)),
869  store_values(store_val), blocked_dofs(blocked_dofs_), mi2(2), mi3(3) {
870  this->add_dependency(mf_source);
871  this->add_dependency(mim_target);
872  is_pol = is_lag = is_standard_fem = false; es_degree = 5;
873  is_equiv = real_element_defined = true;
874  ntarget_dim = mf_source.get_qdim();
875 
877  }
878 
879  DAL_SIMPLE_KEY(special_projfem_key, pfem);
880 
881  pfem new_projected_fem(const mesh_fem &mf_source_, const mesh_im &mim_target_,
882  size_type rg_source_, size_type rg_target_,
883  dal::bit_vector blocked_dofs_, bool store_val) {
884  pfem pf = std::make_shared<projected_fem>
885  (mf_source_, mim_target_, rg_source_, rg_target_,blocked_dofs_,store_val);
886  dal::pstatic_stored_object_key
887  pk = std::make_shared<special_projfem_key>(pf);
888  dal::add_stored_object(pk, pf);
889  return pf;
890  }
891 
892 
893 } /* end of namespace getfem. */
894 
dref_convex_pt_ct dir_points_of_face(short_type i) const
Direct points for a given face.
Definition: bgeot_convex.h:85
const base_node & xreal() const
coordinates of the current point, in the real convex.
void set_xref(const base_node &P)
change the current point (coordinates given in the reference convex)
does the inversion of the geometric transformation for a given convex
bool invert(const base_node &n, base_node &n_ref, scalar_type IN_EPS=1e-12, bool project_into_element=false)
given the node on the real element, returns the node on the reference element (even if it is outside ...
void add_point_with_id(const base_node &n, size_type i)
insert a new point, with an associated number.
Definition: bgeot_kdtree.h:120
void clear()
reset the tree, remove all points
Definition: bgeot_kdtree.h:113
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
short_type nb_faces_of_convex(size_type ic) const
Return the number of faces of convex ic.
pconvex_structure structure_of_convex(size_type ic) const
Return the pconvex_structure of the convex ic.
size_type nb_allocated_convex() const
The number of convex indexes from 0 to the index of the last convex.
bool context_check() const
return true if update_from_context was called
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:750
Describe a finite element method linked to a mesh.
virtual ind_dof_ct ind_basic_dof_of_element(size_type cv) const
Give an array of the dof numbers a of convex.
virtual dim_type get_qdim() const
Return the Q dimension.
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
virtual dal::bit_vector basic_dof_on_region(const mesh_region &b) const
Get a list of basic dof lying on a given mesh_region.
virtual ind_dof_face_ct ind_basic_dof_of_face_of_element(size_type cv, short_type f) const
Give an array of the dof numbers lying of a convex face (all degrees of freedom whose associated base...
virtual base_node point_of_basic_dof(size_type cv, size_type i) const
Return the geometrical location of a degree of freedom.
virtual size_type nb_basic_dof_of_face_of_element(size_type cv, short_type f) const
Return the number of dof lying on the given convex face.
virtual pfem fem_of_element(size_type cv) const
Return the basic fem associated with an element (if no fem is associated, the function will crash!...
virtual size_type nb_basic_dof_of_element(size_type cv) const
Return the number of degrees of freedom attached to a given convex.
virtual const mesh::ind_cv_ct & convex_to_basic_dof(size_type d) const
Return the list of convexes attached to the specified dof.
Describe an integration method linked to a mesh.
virtual pintegration_method int_method_of_element(size_type cv) const
return the integration method associated with an element (in no integration is associated,...
const mesh & linked_mesh() const
Give a reference to the linked mesh of type mesh.
"iterator" class for regions.
structure used to hold a set of convexes and/or convex faces.
static mesh_region all_convexes()
provide a default value for the mesh_region parameters of assembly procedures etc.
virtual scalar_type convex_radius_estimate(size_type ic) const
Return an estimate of the convex largest dimension.
Definition: getfem_mesh.cc:461
ref_convex convex(size_type ic) const
return a bgeot::convex object for the convex number ic.
Definition: getfem_mesh.h:189
mesh_region projected_target_region() const
faces and convexes from the target region that contain at least one Gauss point that is projected by ...
void hess_base_value(const base_node &, base_tensor &) const
Give the value of all hessians (on ref.
virtual size_type nb_dof(size_type cv) const
Number of degrees of freedom.
void real_base_value(const fem_interpolation_context &c, base_tensor &t, bool=true) const
Give the value of all components of the base functions at the current point of the fem_interpolation_...
dal::bit_vector projected_convexes() const
return the list of convexes of the projected mesh_fem which contain at least one gauss point (should ...
void gauss_pts_stats(unsigned &ming, unsigned &maxg, scalar_type &meang) const
return the min/max/mean number of gauss points in the convexes of the projected mesh_fem
void grad_base_value(const base_node &, base_tensor &) const
Give the value of all gradients (on ref.
virtual bgeot::pconvex_ref ref_convex(size_type cv) const
Return the convex of the reference element.
void real_hess_base_value(const fem_interpolation_context &, base_tensor &, bool=true) const
Give the hessian of all components of the base functions at the current point of the fem_interpolatio...
virtual const bgeot::convex< base_node > & node_convex(size_type cv) const
Gives the convex representing the nodes on the reference element.
virtual void update_from_context(void) const
this function has to be defined and should update the object when the context is modified.
void base_value(const base_node &, base_tensor &) const
Give the value of all components of the base functions at the point x of the reference element.
void real_grad_base_value(const fem_interpolation_context &c, base_tensor &t, bool=true) const
Give the gradient of all components of the base functions at the current point of the fem_interpolati...
indexed array reference (given a container X, and a set of indexes I, this class provides a pseudo-co...
Definition: gmm_ref.h:304
FEM which projects a mesh_fem on a different mesh.
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1791
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:558
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
Definition: gmm_blas.h:598
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:210
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1664
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*‍/
Definition: gmm_blas.h:264
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1277
linalg_traits< DenseMatrixLU >::value_type lu_det(const DenseMatrixLU &LU, const Pvector &pvector)
Compute the matrix determinant (via a LU factorization)
Definition: gmm_dense_lu.h:241
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
Definition: gmm_dense_lu.h:212
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:543
dim_type target_dim() const
dimension of the target space.
Definition: getfem_fem.h:314
size_type convex_num() const
get the current convex number
Definition: getfem_fem.cc:53
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
dim_type dim() const
dimension of the reference element.
Definition: getfem_fem.h:311
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:73
pconvex_ref generic_dummy_convex_ref(dim_type nc, size_type n, short_type nf)
generic convex with n global nodes
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
GEneric Tool for Finite Element Methods.
pfem new_projected_fem(const mesh_fem &mf_source, const mesh_im &mim_target, size_type rg_source_=size_type(-1), size_type rg_target_=size_type(-1), dal::bit_vector blocked_dofs=dal::bit_vector(), bool store_val=true)
create a new projected FEM.
store a point and the associated index for the kdtree.
Definition: bgeot_kdtree.h:59